Why do I need to hardcode credentials to connect t

2019-08-26 21:35发布

问题:

I've asked this other question here that leads me to believe, by default, the JavaScript AWS SDK looks for credentials in a number of places in your environment without you having to do anything. The order of places it checks is listed here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html

I've got some working code that connects to AWS Athena. I can only get it to work if I hardcode the credentials manually, which seems to contradict the documentation above. Here is my code:

export const getAthena = (): AWS.Athena => {
    if (process.env["LOCAL_MODE"] === "true") {
        const awsCredentials = {
            region: "us-east-1",
            accessKeyId: awsCredentialsParser("aws_access_key_id"),
            secretAccessKey: awsCredentialsParser("aws_secret_access_key"),
            sessionKey: awsCredentialsParser("aws_session_token")
        };
        AWS.config.update(awsCredentials);
        let credential = new AWS.Credentials({
            accessKeyId: awsCredentials.accessKeyId,
            secretAccessKey: awsCredentials.secretAccessKey,
            sessionToken: awsCredentials.sessionKey
        });
        return new AWS.Athena({credentials: credential, signatureCache: false});
    } else {
        const awsCredentials1 = {
            region: "us-east-1",
            accessKeyId: undefined,
            secretAccessKey: undefined,
            sessionKey: undefined
        };
        AWS.config.update(awsCredentials1);
        return new AWS.Athena({credentials: undefined, signatureCache: false});
    }
};

export const awsCredentialsParser = (key: string): string => {
    const homeDirectory = os.homedir();
    const awsCredentials = fs.readFileSync(homeDirectory + "/.aws/credentials", {encoding: "UTF8"});
    const awsCredentialLines = awsCredentials.split("\n");
    const lineThatStartsWithKey = awsCredentialLines.filter((line) => line.startsWith(key))[0];
    return lineThatStartsWithKey.split(" = ")[1];
};

As you can see, I am using an environment variable called "LOCAL_MODE". If this is set to true, it grabs credentials from my shared credential file. Whereas, if you're not in local mode, it sets all credentials to undefined and relies on the IAM role instead. Isn't the documentation saying I don't have to do this?

But, if I change my code to this, any call to athena hangs until it times out:

export const getAthena = (): AWS.Athena => {
    return new AWS.Athena();
};

If I set the timeout to a really large number, it eventually will let me know that I have invalid credentials.

According to the documentation, shouldn't the 2nd example be find credentials the same way the 1st does? Why does the 2nd example hang? I don't want to have to write the code above. How do I get my code to work like the examples?

  1. Am I somehow creating AWS.Athena() the wrong way in the 2nd example?
  2. How do I troubleshoot this to figure out why it's hanging?
  3. According to the documentation, shouldn't the bottom example be doing the same thing as the top?

回答1:

So after an investigation it seems that this (i.e. the failure on your second snippet) is because you don't have the [default] profile in your .aws/credentials file. Which is a special profile. I assume that the client uses empty strings (or nulls or something) when he can't find it. Which I find amusing to be honest (should throw an exception).

Anyway, to fix that either rename the profile you have to [default] or setup a different profile in your code. Here's the relevant docs:

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-node-credentials-shared.html

I recommend using the AWS_PROFILE environment variable. Will make your code more portable.



回答2:

If you're using an IAM role, you don't need to explicitly supply any credentials, null or otherwise:

const AWS = require('aws-sdk');
const athena = new AWS.Athena();
const params = { ... };
const rc = await athena.startQueryExecution(params).promise();

In fact, this works with credentials supplied via local environment variables or in a credentials/config file too. There's a chain of credentials providers that the SDK will try, one by one.