dshimizu/blog/alpha

とりとめのないITブログ

MFA 有効化時に AWS CLI で AssumeRole を実行する設定

はじめに

AWS CLI を使う時に、MFA が設定されている IAM ユーザーのクレデンシャル情報を利用して、他のAWSアカウントにある IAM Role を AssumeRole して使う(Switch Roleを実行する)設定について調べてやったことのメモ書きです。

MFA 用のプロファイルを定義して、コマンド実行に MFA のコードを入力するパターンと、MFA の認証処理をした一時認証情報を取得し、それを使って CLI を実行するパターンがあるようでした。 それぞれのやり方について試したことを書いてます。

各 IAM Role/Policy の設定

踏み台側の IAM Policy の設定

踏み台となる AWS アカウントでは以下のようなポリシーを作成し、該当 IAM ユーザーにアタッチされているものとします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::123456789123:role/AdminRole",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

Terraform だと以下のような感じになると思います。

// IAM ポリシー
resource "aws_iam_policy" "switch_role_policy" {
  name   = "${aws_iam_group.switch_role_policy.name}"
  policy = "${data.aws_iam_policy_document.switch_role_policy.json}"
}

// IAM ポリシードキュメント
data "aws_iam_policy_document" "switch_role_policy" {
  statement {
    // 123456789123 の AWS アカウントの AdminRole という IAM ロールを利用可能にする
    effect  = "Allow"
    actions = ["sts:AssumeRole"]
    resources = [
      "arn:aws:iam::123456789123:role/AdminRole",
    ]
    // MFA 認証されている場合に AssumeRole を許可する
    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = ["true"]
    }
  }
}

アクセス先AWSアカウントの IAM Role の設定

AdminRole という IAM ポリシーに、以下のような信頼ポリシードキュメントを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::987654321987:root"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}

Terraform だと以下のような感じになると思います。

// IAM ロール
resource "aws_iam_role" "admin" {
  name               = "AdminRole"
  assume_role_policy = "${data.aws_iam_policy_document.assume_role_policy.json}"
}

// IAM ポリシードキュメント 
data "aws_iam_policy_document" "assume_role_policy" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::987654321987:root"]
    }

    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = ["true"]
    }
  }
}

1つ目のやり方: aws profile に mfa_serial を定義する

~/.aws/credentials を以下のように設定します。

[default]
aws_access_key_id = ********************
aws_secret_access_key = ***************************************

~/.aws/config を以下のように設定します。

[default]
region = ap-northeast-1
output = json

[profile dev]
region = ap-northeast-1
output = json
role_arn = arn:aws:iam::123456789123:role/AdminRole  # アクセス先の AWS アカウントに作成しているロール
mfa_serial = arn:aws:iam::987654321987:mfa/dshimizu  # 踏み台 AWS アカウントに作成している IAM ユーザーの MFA の ARN
source_profile = default  # default プロファイルの認証情報を利用する設定

この状態で、dev のプロファイルをつかって 123456789123 のアカウントのリソースにアクセスするために AWS CLI を実行すると、MFA のコードを要求するプロンプトが表示されます。 これを入力すると、S3 の一覧の結果が得られます。

 % aws --profile dev s3 ls
Enter MFA code for arn:aws:iam::987654321987:mfa/dshimizu:

このとき、AWS CLI のキャッシュ情報を見ると、以下のようなものが記録されていました。

% cat ~/.aws/cli/cache/************.json | jq
{
  "Credentials": {
    "AccessKeyId": "********************",
    "SecretAccessKey": "****************************************",
    "SessionToken": "************************************************************************************************************************",
    "Expiration": "2023-02-03T11:26:11+00:00"
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "****************:botocore-session-123456789123",
    "Arn": "arn:aws:sts::123456789123:assumed-role/AdminRole/botocore-session-123456789123"
  },
  "ResponseMetadata": {
    "RequestId": "********-****-****-****-************",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "x-amzn-requestid": "********-****-****-****-************",
      "content-type": "text/xml",
      "content-length": "1520",
      "date": "Fri, 03 Feb 2023 10:26:10 GMT"
    },
    "RetryAttempts": 0
  }
}

ドキュメントを見ると、下記のようにあり、指定されたロールの一時認証情報が取得されるとのことなので、キャッシュに記録されているのはその情報のようです。

When you specify that an AWS CLI command is to use the profile marketingadmin, the AWS CLI automatically looks up the credentials for the linked user1 profile and uses them to request temporary credentials for the specified IAM role. The CLI uses the sts:AssumeRole operation in the background to accomplish this. Those temporary credentials are then used to run the requested AWS CLI command. The specified role must have attached IAM permission policies that allow the requested AWS CLI command to run.

2つ目のやり方: aws profile に一時認証情報を定義する

一時認証情報を利用するやり方をやってみます。

~/.aws/credentials を以下のように設定します。

[default]
aws_access_key_id = ********************
aws_secret_access_key = ****************************************

~/.aws/config を以下のように設定します。

[default]
region = ap-northeast-1
output = json

以下のコマンドで、IAM ユーザーの一時認証情報を取得します。get-session-tokenAPI を実行するためのアクセス権限設定は不要なようなので、何もしなくても実行できると思います。

% aws --profile default sts get-session-token --serial-number arn:aws:iam::987654321987:mfa/dshimizu --token-code <MFA の 6桁の番号を指定>

以下のような一時認証情報用のアクセスキー、シークレットキー、セッショントークンが返されます。 これで MFA 認証が通った状態の一時認証情報を取得できました。

{
  "Credentials": {
    "AccessKeyId": "********************",
    "SecretAccessKey": "****************************************",
    "SessionToken": "************************************************************************************************************************",
    "Expiration": "2023-02-02T22:13:39+00:00"
  }
}

取得した一時認証情報を ~/.aws/credentials へ追記します。

[default]
aws_access_key_id = ********************
aws_secret_access_key = ****************************************

[mfa]
aws_access_key_id = ********************
aws_secret_access_key = ****************************************
aws_session_token = ************************************************************************************************************************

~/.aws/config では、以下のように Assume する Role に対して一時認証情報を利用するように source_profile を定義します。

[default]
region = ap-northeast-1
output = json

[profile mfa]
region = ap-northeast-1
output = json
source_profile = mfa
role_arn = arn:aws:iam::123456789123:role/AdminRole

これで AWS CLI が実行できるようになりました。 MFAの認証は通っているので、6桁のコードを入力することなく実行できます。

 % aws --profile dev s3 ls
:
:

まとめ

MFA が設定されている IAM ユーザーのクレデンシャル情報を利用して、他のAWSアカウントにある IAM Role を AssumeRole して使う(Switch Roleを実行する)設定について書きました。

ドキュメントを見る限りですと、 get-session-tokenAPI が、 MFA 認証する場合のために用意されているためのもののようですので、これを利用するのが良さそうです。

参考