サービスロールとSTSを利用してクロスアカウント連携をしたい場合の設定方法です。
この設定ができると、サービスロールによるクロスアカウントのアクセス制御ができると、
IPが固定されないLambdaでも制御できるようになりますし、連携先のアカウントにもキーを発行などする必要がなくなるので
便利です。(ただ、テストのためにちょっと工夫する必要がありますが・・・。)
■こんな感じ
サンプル実装
0. policyの作成
- 「サービスの選択」> "STS"を選択
- 「アクション」の"All STS actions (sts:*)"を選択
- 「リソース」すべてのリソース
- 「Review policy」を押し、名前を入力して「Create Policy」から作成
1. サービスロールAの作成
- サービス> IAM > ロール
- ロールの作成
-「信頼されたエンティティの種類を選択」で「AWSサービス」の「Lambda」を選択 - ポリシーに上記 「0. policyの作成」で作成したポリシーを指定
- ロール名を入力し作成
2. サービスロールBの作成
- サービス> IAM > ロール
- ロールの作成
- 「信頼されたエンティティの種類を選択」で「AWSサービス」の「Lambda」を選択
- ポリシーに「AmazonS3FullAccess」を選択
- ロール名を入力し作成
- 作成した
サービスロールB
を選択し、「信頼関係」タブをひらく。 - 「信頼関係の編集」をひらき、以下の内容で上書きして「信頼ポリシーの更新」をおして更新
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::`{アカウントAのID}`:role/`{サービスロールAの名前}`"
},
"Action": "sts:AssumeRole"
}
]
}
3. データの準備(バケットの作成とテストファイルの作成)
-
AWSアカウントB
側に適当なバケットを作成する。 - sample.txtとしてアップロードする。
4. Lambdaファンクションの作成
- サービス > Lambda > 「関数の作成」
- 「一から作成」から適当に関数を作成。
- "ランタイム" は Python3.6
- "ロール"は、
サービスロールA
を指定 - 「関数コード」セクションの「コードエントリータイプ」を"コードをインラインで編集"に設定
- lambda_functionに書きのコードをコピーして貼る
# -*- Coding: utf-8 -*-
from __future__ import print_function
import boto3
import botocore
ROLE_ARN='arn:aws:iam::{アカウントBのID}:role/{サービスロールBの名前}'
def get_credentials():
# // STS Client
sts_client = boto3.client('sts', 'ap-northeast-1')
assumeRoleObject = sts_client.assume_role(
RoleArn=ROLE_ARN,
RoleSessionName="s3-access"
)
return assumeRoleObject['Credentials']
def s3_resource():
credentials = get_credentials()
s3_resource = boto3.resource(
's3',
aws_access_key_id = credentials['AccessKeyId'],
aws_secret_access_key = credentials['SecretAccessKey'],
aws_session_token = credentials['SessionToken']
)
return s3_resource
def lambda_handler(event, context):
bucket = '{作成したバケット名}'
key = 'sample.txt'
try:
obj = s3_resource().Object(bucket, key)
response = obj.get()
print("CONTENT TYPE: " + response['ContentType'])
print("Body : " + response['Body'].read(1024*256).decode('utf-8'))
# with open('sample.txt','a') as output:
# chunk = response['Body'].read(1024*256)
# while chunk:
# output.write(chunk.decode('utf-8'))
# chunk = response['Body'].read(1024*256)
return response['ContentType']
except Exception as e:
print(e)
print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
raise e
■こんな感じで。
■サービスロールがSTSにアクセス権限があることがこれで確認できます
動作確認
・「3.Lambdaファンクションの作成」で作成した Lambdaでテストを実行すれば確認できるはず・・・。
この機能のポイント
- リソースを提供する側(
アカウントB
側)が、アカウントA
のアクションを制御できる。 - 設定する場合は、リソースを提供される側(
アカウントA
)が、連携するサービスロールのARN
を
提供する側に教える。 - 今回のようにLambdaが別アカウントのS3を利用するだけであれば、Lambdaのサービスロールに
Amazon S3のアクションを付与する必要はない。
こんなときは?
- クロスアカウントでS3からS3へファイルを移したいとき。
- 直接、S3間のコピーはできないので一度、一時ファイルを作成してから、2回にわけて移動させる。
⇒この場合は、サービスロールA
側にもAmazonS3へのアクセス権限が必要になる。 - 開発環境と本番環境どうわける?
-
ROLE_ARN
をきりかえられるようにすれば自動的に環境先のサービスロールが切り替わります。
⇒サービスロールB
のポリシーでうまいことアクセスを絞ると良いかと。
以上です。
アカウント二つないと試せないですが、どういう設定をすればいいのかがわかってもらえたらいいな・・。
明日は、@maemoriさんです。