AssumeRoleできるかをローカルで検証する
AssumeRoleできるかをローカルで検証する:
Bアカウントが作成したS3バケットにAアカウントで書き込みたい。
Bアカウントの人にお願いしてバケットポリシーを書いてもらい、AアカウントからS3バケットへ書き込めるようにしてもらった。
無事に書き込めたが、BアカウントからS3オブジェクトに対して操作ができないと言われた。
ご存知だと思うが、この方法を使ってBアカウントの持つS3バケットにAアカウントを使ってオブジェクトを書き込めるが、
オブジェクトに対する操作ができない。これはオブジェクトの所有者がAアカウントになっている為である。
具体的にはオブジェクトに対する閲覧、権限変更ができない。しかしバケット自体に権限はあるのでBアカウントからオブジェクトを削除することは可能。
どうすればAアカウントからアップロードしたS3オブジェクトに対し、Bアカウントにも権限を付与できるか。
AssumeRoleを使ってBアカウントとして書き込めば、そのオブジェクトはBアカウントが所有者となるので、自由に権限を操作できる。
Bアカウントにお願いし、Aアカウントで用意したRole(以下、A-role)にのみAssumeでき、S3バケットに対して操作できるRole(以下、B-role)を用意してもらった。
これでAssumeRoleすれば書き込めるぞ!
本当にA-roleでAssumeRoleできるのか検証しないといけない。
しかも操作するのはAWS Batchであった為、いちいちコンテナにスクリプト入れて試行錯誤する必要があって、とても手間がかかる。面倒。
AssumeできるのはA-roleにのみ許可されているので、Aアカウントに所属するIAMユーザーを使ってクレデンシャルを発行してもそのIAMユーザーにはB-RoleをAssumeできる権限はない。
あくまでA-Roleでないといけない。しかしA-Roleにクレデンシャルは発行できない。どうする・・・
そうだ!A-RoleをさらにAssumeできるIAMユーザーを発行して、A-roleにAssumeし、
さらにそこからB-roleをAssumeすればいいんだ!
コードだと以下のような感じ。
結局何がしたかったのかというと、RoleにのみAssumeが許可されている場合、いちいちEC2等にアタッチして検証するのは面倒なので、IAMユーザーを使って疑似的にEC2が行っている権限情報をSTSから貰う仕組みをやっている感じです。
EC2ならいいけど、これがコンテナ経由だとコンテナデプロイやって試行錯誤していると時間がもったいないので、お手軽にできるかと思います。
事の発端
Bアカウントが作成したS3バケットにAアカウントで書き込みたい。Bアカウントの人にお願いしてバケットポリシーを書いてもらい、AアカウントからS3バケットへ書き込めるようにしてもらった。
無事に書き込めたが、BアカウントからS3オブジェクトに対して操作ができないと言われた。
なぜか?
ご存知だと思うが、この方法を使ってBアカウントの持つS3バケットにAアカウントを使ってオブジェクトを書き込めるが、オブジェクトに対する操作ができない。これはオブジェクトの所有者がAアカウントになっている為である。
具体的にはオブジェクトに対する閲覧、権限変更ができない。しかしバケット自体に権限はあるのでBアカウントからオブジェクトを削除することは可能。
どうすればAアカウントからアップロードしたS3オブジェクトに対し、Bアカウントにも権限を付与できるか。
解決策
AssumeRoleを使ってBアカウントとして書き込めば、そのオブジェクトはBアカウントが所有者となるので、自由に権限を操作できる。Bアカウントにお願いし、Aアカウントで用意したRole(以下、A-role)にのみAssumeでき、S3バケットに対して操作できるRole(以下、B-role)を用意してもらった。
これでAssumeRoleすれば書き込めるぞ!
ここで壁に当たる。
本当にA-roleでAssumeRoleできるのか検証しないといけない。しかも操作するのはAWS Batchであった為、いちいちコンテナにスクリプト入れて試行錯誤する必要があって、とても手間がかかる。面倒。
AssumeできるのはA-roleにのみ許可されているので、Aアカウントに所属するIAMユーザーを使ってクレデンシャルを発行してもそのIAMユーザーにはB-RoleをAssumeできる権限はない。
あくまでA-Roleでないといけない。しかしA-Roleにクレデンシャルは発行できない。どうする・・・
ここで思いつく。
そうだ!A-RoleをさらにAssumeできるIAMユーザーを発行して、A-roleにAssumeし、さらにそこからB-roleをAssumeすればいいんだ!
コードだと以下のような感じ。
import boto3
from boto3.session import Session
def main():
# ユーザーとして入る。このユーザーはA-roleをAssumeできる権限があり、A-roleから信頼済みアカウントとして定義されている。
client = boto3.client(
'sts',
aws_access_key_id="A:User:xxx",
aws_secret_access_key="yyy")
account_id = client.get_caller_identity()
print("1. {}".format(account_id))
# ユーザーとしてA-roleの権限をAssumeする。
response = client.assume_role(
RoleArn="arn:aws:iam::A:role/A-role",
RoleSessionName="A-role"
)
# A-roleでクライアントを作る。
A_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)
A_client = A_session.client('sts')
account_id = A_client.get_caller_identity()
print("2. {}".format(account_id))
# A-roleのクライアントを使ってAssumeRoleを行う。このRoleであれば許可されている為、Assumeできる。
# このRoleにS3のアクセス権限がある。このRoleをAssumeできるのはA-roleのみ。
response = A_client.assume_role(
RoleArn="arn:aws:iam::B:role/B-role",
RoleSessionName="Assume",
)
B_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)
B_client = B_session.client('sts')
account_id = B_client.get_caller_identity()
print("3. {}".format(account_id))
# S3バケットにアップロードしてみる。B-roleにはS3バケットへの操作権限があるので書き込める。
# またAssumeしているのでそのオブジェクトの所有者もBアカウントとなる。
s3 = B_session.resource('s3')
s3.meta.client.upload_file('A.png', "B-bucket", 'A.png')
if __name__ == "__main__":
main()
まとめ
結局何がしたかったのかというと、RoleにのみAssumeが許可されている場合、いちいちEC2等にアタッチして検証するのは面倒なので、IAMユーザーを使って疑似的にEC2が行っている権限情報をSTSから貰う仕組みをやっている感じです。EC2ならいいけど、これがコンテナ経由だとコンテナデプロイやって試行錯誤していると時間がもったいないので、お手軽にできるかと思います。
コメント
コメントを投稿