こんな感じでLambdaに処理を実装する。
const AWS = require('aws-sdk')
const arn = 'arn:aws:iam::9999999:role/EXAMPLE'
const sts = new AWS.STS()
sts.assumeRole({
RoleArn: arn,
RoleSessionName: 'test'
}).promise().then(data => {
AWS.config.update({
credentials: new AWS.Credentials(
data.Credentials.AccessKeyId,
data.Credentials.SecretAccessKey,
data.Credentials.SessionToken
),
region: 'us-west-2'
})
const docClient = new AWS.DynamoDB.DocumentClient()
return docClient.get({
TableName: 'Test',
Key: {
ID: 'hello'
}
}).promise()
})
.then(data => console.log(data))
.catch(e => console.log(e))
1回目は問題なく動くが、2回目以降にこうなる。
{
"message": "Access denied",
"code": "AccessDenied",
"time": "2019-02-18T08:18:27.089Z",
"requestId": "c44f9f87-3355-11e9-bfa8-451bc09ebb35",
"statusCode": 403,
"retryable": false,
"retryDelay": 20.810919578930864
}
原因
AWS.config.update
で切り替えた後の情報でAWS SDKの処理が走るため、1回目と2回目以降では実行しようとしているIAMロールが異なる。
sts.getCallerIdentity()
でAccountなどの情報を見ると、変わっているのがわかる。
対応
sts.getCallerIdentity()
でどのロールを使おうとしているかわかるので、assumeRoleする必要がないときは何もしないようにすれば良い。
const AWS = require('aws-sdk')
const getCallerIdentity = () => {
return new Promise((resolve, reject) => {
const sts = new AWS.STS()
sts.getCallerIdentity((error, data) => {
if (error) return reject(error)
return resolve(data)
})
})
}
getCallerIdentity()
.then({Account} => {
if (Account === 'YOUR_ACCOUNT_ID') return Account
const sts = new AWS.STS()
return sts.assumeRole({
RoleArn: 'arn:aws:iam::9999999:role/EXAMPLE',
RoleSessionName: 'test'
}).promise()
}).then(data => {
const credentials = new AWS.Credentials(
data.Credentials.AccessKeyId,
data.Credentials.SecretAccessKey,
data.Credentials.SessionToken
)
const docClient = new AWS.DynamoDB.DocumentClient({ credentials })
return docClient.get({
TableName: 'Test',
Key: {
ID: 'hello'
}
}).promise()
})
.then(data => console.log(data))
.catch(e => console.log(e))