認証情報の食い違いを調べる
例えば、ローカルで AWS CLI を使って S3 の情報にアクセスできているのに、AWS SDK 使った Node.js プログラムで S3 にアクセスしたときに Access Denied (403) になるときは、異なる認証情報 (credentials) を使ってアクセスしている可能性 があります。
AWS CLI が、どのようなユーザーでアクセスしているかは、下記のようにして確認できます。
$ aws sts get-caller-identity
Account: '123456789012'
Arn: arn:aws:sts::123456789012:assumed-role/MyDeveloperRole/botocore-session-9876543210
UserId: A6B3EVWX58AR9AVTXAP5T:botocore-session-9876543210
次に、Node.js のプログラムなどで、AWS SDK を使って上記と同様の情報を取得します。
Node.js 用の SDK ver.2 では、AWS.STS.getCallerIdentity()
、SDK ver.3 では STSClient.send()
を使います。
import { STS } from 'aws-sdk';
async function printCallerIdentity() {
try {
const sts = new STS();
const result = await sts.getCallerIdentity().promise()
console.log(result)
} catch (e) {
console.error(e);
}
}
printCallerIdentity();
import {
STSClient,
GetCallerIdentityCommand,
GetCallerIdentityCommandInput,
GetCallerIdentityCommandOutput,
} from "@aws-sdk/client-sts";
async function printCallerIdentity() {
const client = new STSClient({ region: "ap-northeast-1" });
const input: GetCallerIdentityCommandInput = {};
const command = new GetCallerIdentityCommand(input);
try {
const output: GetCallerIdentityCommandOutput = await client.send(command);
console.log(output);
} catch (e) {
console.error(e);
}
}
printCallerIdentity();
$ ts-node printCallerIdentity.ts
{
ResponseMetadata: { RequestId: '2ce10620-9158-4e5e-8bca-8258bfd02927' },
UserId: 'MWUCVBID75KAC5PB68LSP',
Account: '777888999000',
Arn: 'arn:aws:iam::777888999000:user/your-user-name'
}
上記の結果と aws sts get-caller-identity
の結果を比べると、別のユーザー (credential) でアクセスしていることが分かります。
つまり、AWS SDK 対して、正しく認証情報 (credentails) を設定してやれば問題は解決するはずです。
AWS CLI に設定されている認証情報は、aws configure list
コマンドなどで確認できます。
(おまけ)今回の原因
ちなみに、今回の Access Denied (403) の原因は、AWS CLI では Assume Role したユーザーでアクセスできていたけれど、AWS SDK の方は直接アクセスしていたので弾かれていたというオチでした。
AWS SDK で Assume Role したいときは、AWS.SMS
オブジェクトの assumeRole
メソッドを使います。
例えば、下記のような感じで Assume Role して取得した認証情報をセットしてから、S3 などの API を呼び出せば、うまくアクセスできるようになります。
import * as AWS from 'aws-sdk';
async function assumeRole() {
const roleToAssume = {
RoleArn: 'arn:aws:iam::123456789012:role/MyDeveloperRole',
RoleSessionName: 'session1',
DurationSeconds: 900,
};
try {
const sts = new AWS.STS();
const data = await sts.assumeRole(roleToAssume).promise();
AWS.config.update({
credentials: {
accessKeyId: data.Credentials?.AccessKeyId!,
secretAccessKey: data.Credentials?.SecretAccessKey!,
sessionToken: data.Credentials?.SessionToken!
}
});
} catch (err) {
console.error(err);
}
}
複雑すぎでしょ・・・(´へ`;
(おまけ)Access Key Id の情報を調べる
次のようにすれば、AWS SDK が使用しようとしているアクセスキーの ID を調べることができます。 この情報もトラブル発生時のヒントになるかもしれません。
import * as AWS from 'aws-sdk';
function printAccessKey() {
AWS.config.getCredentials(err => {
if (err) console.error(err.message);
else console.log('Access Key: ' + AWS.config.credentials?.accessKeyId);
});
}
printAccessKey();
関連記事
- AWS CloudFormation の設定例: SNS トピックを Lambda 関数からサブスクライブする
- AWS SNS トピックから通知されるイベントデータの例
- Lambda 実装例: S3 へのアップロードを SNS で通知して Lambda から読み込む
- AWS CloudFormation で SNS トピックのリソースを生成する
- AWS CloudFormation の設定例: S3 通知を SNS トピックに Publish する
- AWS CloudFormation の設定例: Lambda 関数から S3 にアクセスできるようにする
- AWS CloudFormation で S3 バケットのリソースを作成する