Lambdaを利用した他アカウントの操作
やったことの流れは以下の通り。
IAMロール/ポリシーの設定
Lambdaにアタッチするロールと、他のアカウント(操作対象のインスタンスを保持しているアカウント)側のIAMロールの2つを編集する必要があります。
LambdaのIAMロール/ポリシー
今回のケースで必要な権限(ポリシー)は以下の2つです。
AWSLambdaExecute (built-in):
Lambda実行のための基本的な権限です。具体的には、cloudwatch logs へのフルアクセス、S3へのPut/Get。他のアカウントのIAMロールへのSTS権限:
他のアカウントのIAMロールへの一時的な認証情報を取得(STS)してインスタンスのコントロールを行うために、Lambda側には「他のアカウントのIAMロールへのSTSを行う権限」を与える必要が有ります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "sts:AssumeRole" ], "Resource": [ "arn:aws:iam::999999999999:role/OtherAccountRole" ] } ] }
他のアカウント側のIAMロール/ポリシー
他のアカウント(操作対象のインスタンスを保持しているアカウント)では以下のポリシーを持ったIAMロールを作成します。
- EC2インスタンスの取得、再起動を行う権限
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "ec2:RebootInstances" ], "Resource": [ "*" ] } ] }
また、このIAMロールの信頼済みエンティティに、上記のLambdaロールを追加する必要が有ります。IAM画面から信頼関係の編集
を行い、以下のように編集します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/RebootLambdaRole" }, "Action": "sts:AssumeRole" } ] }
Lambda のコード、テストイベント
Python3.6で書きます。
ソースコード
''' AWS Lambda script for reboot instances. This scripts need STS for IAM Role on Another Account. ''' import boto3 def lambda_handler(event, context): sts_client = boto3.client('sts') sts_res = sts_client.assume_role( RoleArn=event['sts_target'], RoleSessionName='RebootOtherAccount' ) cred = sts_res['Credentials'] ec2_client = boto3.client( 'ec2', aws_access_key_id=cred['AccessKeyId'], aws_secret_access_key=cred['SecretAccessKey'], aws_session_token=cred['SessionToken'], ) full_info = ec2_client.describe_instances( Filters=[ { 'Name': 'tag:need_reboot', 'Values': ['true'] } ] ) instance_ids = [] for r in full_info['Reservations']: for i in r['Instances']: instance_ids.append(i['InstanceId']) return ec2_client.reboot_instances( DryRun=event.get('dry_run', True), InstanceIds=instance_ids, )
テストイベント
{ "dry_run": true, "sts_target": "arn:aws:iam::999999999999:role/OtherAccountRole" }
解説と補足
- テストイベントから取得した他アカウントのIAMロールへのSTSを行い、取得した認証情報を利用してEC2クライアントを作成します。STSを利用して他アカウントのリソースにアクセスする場合は、clientの初期化時に以下のようにする必要があります。
cred = sts_res['Credentials'] ec2_client = boto3.client( 'ec2', aws_access_key_id=cred['AccessKeyId'], aws_secret_access_key=cred['SecretAccessKey'], aws_session_token=cred['SessionToken'], )
full_info = ec2_client.describe_instances( Filters=[ { 'Name': 'tag:need_reboot', 'Values': ['true'] } ] )
- 細かいですが、
DryRun
フラグはちゃんと付けておきたいですね。
return ec2_client.reboot_instances( DryRun=event.get('dry_run', True), InstanceIds=instance_ids, )
終わりに
以上です。IAMロールの設定のところで結構ハマりましたが、IAMロール/ポリシー、信頼関係などについて学ぶことが出来ました。 業務ではこんな感じのLambdaを書くことが増えたので、ブログの方にもメモを残していきたいと思います。