为什么我需要硬编码凭据才能使用 javascript SDK 连接到 AWS?

Why do I need to hardcode credentials to connect to AWS using the javascript SDK?

我问过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

我有一些连接到 AWS Athena 的工作代码。如果我手动对凭据进行硬编码,我只能让它工作,这似乎与上面的文档相矛盾。这是我的代码:

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];
};

如您所见,我正在使用一个名为 "LOCAL_MODE" 的环境变量。如果将其设置为 true,它会从我的共享凭据文件中获取凭据。然而,如果您不处于本地模式,它会将所有凭证设置为未定义并改为依赖 IAM 角色。 文档不是说我不必这样做吗?

但是,如果我将代码更改为此,对 athena 的任何调用都会挂起,直到超时:

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

如果我将超时设置为非常大的数字,它最终会让我知道我的凭据无效。

根据文档,第二个示例不应该像第一个示例一样查找凭据吗?为什么第二个例子挂了?我不想写上面的代码。如何让我的代码像示例一样工作?

  1. 我是否以某种方式在第二个示例中创建了 AWS.Athena() 错误的方式?
  2. 如何解决此问题以找出挂起的原因?
  3. 根据文档,下面的例子不应该和上面的例子做同样的事情吗?

如果您使用的是 IAM 角色,则无需显式提供任何凭据,无论是 null 还是其他:

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

事实上,这也适用于通过本地环境变量或 credentials/config 文件提供的凭据。有一个 chain of credentials providers SDK 会一个一个地尝试。

所以经过调查,这似乎(即第二个代码段的失败)是因为您的 .aws/credentials 文件中没有 [default] 配置文件。这是一个特殊的配置文件。我假设客户在找不到它时使用空字符串(或空值或其他东西)。老实说,我觉得这很有趣(应该抛出异常)。

无论如何,要解决此问题,您必须重命名配置文件 [default] 或在代码中设置不同的配置文件。这是相关文档:

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

我建议使用 AWS_PROFILE 环境变量。将使您的代码更具可移植性。