ユーザーに一時的に権限を付与する Assume Role を使ってみる

Assume Role という機能があり使ってみたのでメモ。

参考

Assume Role とは

Assume には「引き受ける」という意味がある。
権限がないユーザーが一時的に権限を「引き受ける」事によって普段許可されていない事ができるようになる。

例えば S3 にアクセスするロールが適用されていないIAMユーザーでも、一時的にロールを適用することによって S3 にアクセスできるようになる。

なにが良いのか

  • 多様なロールを適用したIAMユーザーを作成しなくて良いのでユーザー数が節約できる。
  • 付与されるロールのには期限があるのでセキュリティ的によい。
  • アクセスキー等が漏洩したとしてもロールを引き受けないと、そのIAMユーザーではできる事が限られる。

...とのこと。

準備

用意する設定は下記の通り。
1つのポリシーが直接アタッチされたユーザー。
2つのポリシーがアタッチされたロール。

  • ロールを引き受けるユーザー
    • ロールを引き受ける事を可能にするポリシー
  • 引き受けられるロール。
    • S3を扱うポリシー
    • 引き受けるユーザーを信頼するポリシー

ユーザーがS3操作権限のあるロールを一時的に借りるが、お互いに信頼するポリシーも必要みたいな感じ。

手順

  1. ロールを引き受けるユーザーを作成する。
  2. 引き受けられるロールを作成する。
  3. ロールを引き受ける事を可能にするポリシーを作成する。
  4. ユーザーにポリシーをアタッチする。

ロールを引き受けるユーザーを作成する

まずは何の許可も持たないユーザーを作成します。

  1. IAMページを開く。
  2. サイドバーの「ユーザー」をクリックする。
  3. 「ユーザーを追加」をクリックする。
  4. 「ユーザー名」で「AssumeS3User」と入力して「次へ」をクリックする。
  5. とりあえず「ポリシーを直接アタッチする」を選択だけして何もアッタッチせずに「次へ」をクリックする。
  6. 「ユーザーの作成」をクリックする。
  7. 新しいユーザーのページに移動するのでARNを控えておく。
  8. ARNに含まれる12桁のIDを控えておく。
arn:aws:iam::123456789012:user/AssumeS3User

引き受けられるロールを作成する

信頼するアカウントIDを設定する。

  1. IAMページを開く。
  2. サイドバーの「ロール」をクリックする。
  3. 「ロールを作成」をクリックする。
  4. 「AWSアカウント」を選択する。
  5. 「別のAWSアカウント」を選択し先ほど控えた12桁のIDを入力する。
  6. 「次へ」をクリックする。

S3のポリシーを設定する。

  1. 「許可ポリシー」で「AmazonS3FullAccess」と検索し、表示されたポリシーにチェックをつけ「次へ」をクリックする。
  2. 「ロール名」に「AllowedAssumeS3Role」と入力し「ロールを作成」をクリックする。

ユーザーを全員ではなく特定のユーザーのみ信頼する。

  1. 上記で作成したロールのページの「信頼関係」タブを開く。
  2. 「信頼されたエンティティ」が以下のようになっているので「信頼ポリシーを編集」をクリックする。
    {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
    }
  3. 作成したユーザーのARNに書き換え「ポリシーを更新」をクリックする。
    {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/AssumeS3User" // ユーザーのARN
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
    }
  4. 作成したロールの ARN をコピーして控えておく。

ロールを引き受ける事を可能にするポリシーを作成する

  1. サイドバーの「ポリシー」をクリックする。
  2. 「ポリシーを作成」をクリックする。
  3. Resource に先ほど作成したロールのARNを指定し下記のようにJSONを変更し「次のステップ: タグ」をクリックする。
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::123456789012:role/AllowedAssumeS3Role" // ロールのARN
    }
}
  1. 今回はタグ付けしないのでそのまま「次のステップ: 確認」をクリックする。
  2. 「名前」に「AssumeS3RolePolicy」と入力し「ポリシーの作成」をクリックする。

ユーザーにポリシーをアタッチする

  1. 作成したユーザー AssumeS3User のページを開き「許可を追加」をクリックする。
  2. 「ポリシーを直接アタッチする」をクリックし「AssumeS3RolePolicy」を検索し表示されたポリシーにチェックをつけ「次へ」をクリックする。
  3. 「許可を追加」をクリックする。

以上で設定は終わりです。

確認する

アクセスキーを発行する

まずは作成したユーザーのアクセスキーを発行します。

  1. 作成したユーザーのページ
  2. セキュリティ認証情報
  3. アクセスキーを作成
  4. コマンドラインインターフェイス (CLI)
  5. 次へ → アクセスキーを作成
  6. アクセスキーとシークレットアクセスキーを控える
  7. 完了

python で確認する

権限を持たない状態でS3からファイルのダウンロードを試してみます。

import boto3
from boto3.session import Session

# Assume User
AWS_ACCESS_KEY_ID = 'xxxxxxxxxx'
AWS_SECRET_ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
REGION_NAME = 'ap-northeast-1'

# To Switch Role
IAM_ROLE_ARN = 'arn:aws:iam::123456789012:role/AllowedAssumeS3Role'
IAM_ROLE_SESSION_NAME = 'hogehoge'

# Bucket Name
BUCKET_NAME = "hogehoge-bucket"

# download S3 File
s3 = boto3.resource(
    's3',
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name=REGION_NAME,
)
bucket = s3.Bucket(BUCKET_NAME)
bucket.download_file('hoge.zip', 'hoge.zip')

結果は権限がないとの事。

botocore.exceptions.ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden

今度は、ロールを一時的に借りてダウンロードを試してみます。

import boto3
from boto3.session import Session

# Assume User
AWS_ACCESS_KEY_ID = 'xxxxxxxxxx'
AWS_SECRET_ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
REGION_NAME = 'ap-northeast-1'

# To Switch Role
IAM_ROLE_ARN = 'arn:aws:iam::123456789012:role/AllowedAssumeS3Role'
IAM_ROLE_SESSION_NAME = 'hogehoge'

# Bucket Name
BUCKET_NAME = "hogehoge-bucket"

# Call Security Token Service
client = boto3.client(
    'sts',
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name=REGION_NAME,
)

# Get Role Info
response = client.assume_role(
    RoleArn=IAM_ROLE_ARN,
    RoleSessionName=IAM_ROLE_SESSION_NAME
)

# Get Session
session = Session(
    aws_access_key_id=response['Credentials']['AccessKeyId'],
    aws_secret_access_key=response['Credentials']['SecretAccessKey'],
    aws_session_token=response['Credentials']['SessionToken'],
    region_name=REGION_NAME
)

# Use Session Instead Of Boto3
s3 = session.resource("s3")
bucket = s3.Bucket(BUCKET_NAME)
bucket.download_file('hoge.zip', 'hoge.zip')

実行したら無事 hoge.zip がダウンロードできました。

追記

ロールの作成で「信頼されたエンティティタイプ」で「ウェブアイデンティティ」を選択すると、GCPのサービスアカウントにもロールの付与を許可できるみたいです。