こんにちは。CS課の坂本です。
タイトルは違いますが、前回の続きです。前回の処理は、2つのアカウントにまたがって実行されていました。
1. 開発アカウントのLambdaから処理を実行
2. 本番アカウントのCloudWatchのデータを取得
3. 取得したデータを開発アカウントのDynamoDBに入れる
という流れでした。
このように別のアカウントにアクセスする場合、ユーザーの「アクセスキー、シークレットアクセスキー」をもう一方のアカウントに知らせて、そのキーを使ってアクセスすることもできますが、ユーザーとキーの管理をしっかりおこなわないといけません。しかし、「AWS STS」を使うとユーザーとキーの管理がいらなくなり、よりセキュアな運用ができます。
「AssumedRoleUser」の部分が動的に作成されるユーザーの情報で、「Credentials」の部分には、「AccessKeyId」と「SecretAccessKey」、「SessionToken」の3つがあり、これが一時的な認証情報であることがわかると思います。 上記の場合は、Lambdaファンクションを作成するときに「LambdaRole」を選んでいるので、ちゃんと想定した結果が返ってきていますが、たとえば「TestRole」を選ぶと以下のようなエラーが返ってきます。このことから、想定していないリソースからはきちんとアクセスできないようになっていて、本番アカウントがセキュアに守られている、ということがおわかりいただけるのではないかと思います。
1. AWS STSとは?
「AWS STS」とは、「AWS Security Token Service」の略で一時的な認証情報を発行してくれるサービスです。 一時的な認証情報は、「アクセスキー」と「シークレットアクセスキー」、「セッショントークン」の3つから成り立っています。 この3つの一時的な認証情報を使うことで、許可された別のアカウントのリソースにアクセスすることができます。STSを使った別のアカウントのリソースへのアクセス(イメージ図)
ざっくりとした別のアカウントへのアクセスまでの流れは上の図のような感じです。 まず、開発アカウントで動的に作成されたユーザーが本番アカウントのリソースにアクセスするための認証情報をSTSに発行してもらいます。その一時的な認証情報を使って本番アカウントのリソースにアクセスします。STSを使うと、このような流れで別のアカウントへアクセスすることになります。 STSを使うと、図のようにユーザー自体が動的に生成されるので、自分でこの処理用にユーザーをつくる必要がありません。認証情報も許可されたリソースしか使えない一時的なものが定期的に自動で更新されるので、自分で定期的にキーの更新をおこなうよりも安心です。このように、STSを利用すれば、ユーザーとキーの管理をする手間がなくなって、よりセキュアに運用することができます。 では、実際にアカウントごとにどのような設定をしているのか見てみましょう。2. 開発アカウント(アカウントA)の設定
ロールの設定内容を確認(LambdaRole)
アクセスする側のアカウントもアクセスされる側のアカウントも「ロール」を作成して設定する必要があります。「ロール」の詳しい説明はこちらにあるので省きますが、簡単に説明すると「ユーザーやグループに紐付かないで、AWSのサービスやリソースに対して操作権限を付与することができる」というモノです。AWS IAMというサービスに属しています。 以下の画像は、IAMのマネジメントコンソールで確認したアクセスする側の開発アカウントのロール、「LambdaRole」の設定です。まずは「アクセス許可」タブを確認します。 管理ポリシーの方は、「AmazonDynamoDBFullAccess」と「AWSLambdaBasicExecutionRole」を設定しています。インラインポリシーの方は「ProdStsPolicy」という名前で以下の設定をしています。こちらのインラインポリシーが今回取り上げているSTSに関する設定です。{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::XXXXXXXXXXXX:role/DevReadOnlyRole" } }「XXXXXXXXXXXX」のところは本番アカウントのIDだと思ってください。STSのAssumeRoleというアクションを本番アカウントの「DevReadOnlyRole」ロールというリソースに対して実行することを許可している、という意味の内容です。 次に「信頼関係」タブを確認します。こちらもSTSに関する設定です。「信頼されたエンティティ」が「lambda.amazonaws.com」となっています。 設定の中身は以下のようになっており、LambdaがSTSの「AssumeRole」をできるサービスとして信頼されている、という意味の内容です。なのでこのロールの場合、Lambda以外のサービス、たとえばEC2からは「AssumeRole」ができない、ということになります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
3. 本番アカウント(アカウントB)の設定
ロールの設定内容を確認(DevReadOnlyRole)
次は、本番アカウントのロールの確認です。以下の画像がIAMのマネジメントコンソールで確認したアクセスされる側のアカウントのロール、「DevReadOnlyRole」の設定です。こちらもまずは「アクセス許可」タブを確認します。 管理ポリシーに、「AmazonEC2ReadOnlyAccess」と「CloudWatchReadOnlyAccess」を設定しています。こちらは、インラインポリシーの方は設定していません。 次に「信頼関係」タブを確認します。こちらがSTSに関する設定です。「信頼されたエンティティ」が「arn:aws:iam::YYYYYYYYYYYY:role/LambdaRole」となっています。「YYYYYYYYYYYY」の部分は開発アカウントのIDだと思ってください。 設定の中身は以下のようになっており、開発アカウントのリソース、「LambdaRole」ロールが「AssumeRole」をできるリソースとして信頼されている、という意味の内容です。なのでこの場合、開発アカウントの「LambdaRole」以外の別のロール、たとえば「TestRole」からは「AssumeRole」ができません。開発アカウントで「LambdaRole」が割り当てられているリソース以外は「AssumeRole」することを許可していない、ということになります。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YYYYYYYYYYYY:role/LambdaRole" }, "Action": "sts:AssumeRole" } ] }たとえば、もし開発アカウントであれば全て「AssumeRole」することを許可するのであれば、以下のような設定になります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YYYYYYYYYYYY:root" }, "Action": "sts:AssumeRole" } ] }今回は、「LambdaRole」のみ許可するようにします。自分が持っている開発環境からのアクセスであっても、想定していないリソースからはアクセスできないようにして、よりセキュアに運用できるようにしたいと思います。
4. LambdaからSTSのサンプルコードを実行
STSのサンプルコードを準備したので、Lambdaから実行してみます。 実行すると、以下のような形で結果が返ってきます。{u'AssumedRoleUser': {u'Arn': 'arn:aws:sts::XXXXXXXXXXXX:assumed-role/DevReadOnlyRole/kokeshi', u'AssumedRoleId': 'AAAAAAAAAAAAAAAAAAAAA:kokeshi'}, u'Credentials': {u'AccessKeyId': 'BBBBBBBBBBBBBBBBBBBB', u'Expiration': datetime.datetime(2016, 5, 16, 0, 0, 0, tzinfo=tzlocal()), u'SecretAccessKey': 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC', u'SessionToken': 'FQoDYXdzEIj//////////wEaDDz1NcYJo/Ai7x5MDiKAAkupwvZ8Dy1y84tblLQpn3LivwP91YT3BSlNgAyTf1c3VcqRUh7RHLyrkGX+Q7AKMAxnkRWEk3gDSXa9EucVocy49z0p7O+SIBYw75jbmrFK+jQvN58HpDbFg93MgSyXMU++kIEuG9mss0pWApxzzGg4hXi9nY5th/fPVn1rXZYZHJ/tQK8CA1iQj68V3HJ8HXlnbq2FGoth/guwl38gGumG6F7+XgCvBH7AvIpacNE32INMVPLQGicwDvBcttXhAY8eIVzi+U2S0zFtTLSjumKkg5wIi5IxhZH5zFXAJueo4ZdfF/X9sdUGgmo7D7SoYOPCOZAfmO9WMpy0bgWNkS0otOPluQU='}, 'ResponseMetadata': {'HTTPStatusCode': 200, 'RequestId': 'DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD'}}
「AssumedRoleUser」の部分が動的に作成されるユーザーの情報で、「Credentials」の部分には、「AccessKeyId」と「SecretAccessKey」、「SessionToken」の3つがあり、これが一時的な認証情報であることがわかると思います。 上記の場合は、Lambdaファンクションを作成するときに「LambdaRole」を選んでいるので、ちゃんと想定した結果が返ってきていますが、たとえば「TestRole」を選ぶと以下のようなエラーが返ってきます。このことから、想定していないリソースからはきちんとアクセスできないようになっていて、本番アカウントがセキュアに守られている、ということがおわかりいただけるのではないかと思います。
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::YYYYYYYYYYYY:assumed-role/TestRole/awslambda_000_20160516000000000 is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::XXXXXXXXXXXX:role/DevReadOnlyRole NG