LoginSignup
8
11

More than 5 years have passed since last update.

STSのassumeRoleをLambdaで使うと、2回目以降でAccess Dinedになる件

Last updated at Posted at 2019-02-18

こんな感じで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))

8
11
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11