概要
AWS を複数アカウントで運用する場合、Switch ロールでアカウントユーザを切り替えることがベストプラクティスになっています。
これはマスターアカウントでユーザを一元管理し、マスターアカウントに紐づく子アカウントではユーザを作成せずロールの切り替えによって権限管理ができるからです。
この方法を利用することでユーザの管理はマスターで一元管理できるので便利ですが、一方で、不用意なユーザを子アカウントに作成しないといった制限もかかります。ユーザを作成できなければ不用意なシークレットキー、アクセスキーの管理からも開放されます。
一方、プログラムから AWS リソースにアクセスする場合、一般的にシークレットキー、アクセスキーを発行することがあると思います。しかし、Switch ロールを利用する場合は子アカウントへのユーザ作成を極力避けなければなりません。
今回はこのような場合でもリソースにアクセスできるような **「Switch ロールに対応した複数アカウントのインスタンス一覧の取得」**の例を解説します。
仕組み
Lambda を利用して、引数で渡されたアカウントIDと切り替え先のロール名によって、複数アカウントの切り替えを行います。
また、切り替え先のロールには、インスタンス一覧が取得できる権限を付与しておきます。
lambda コード
今回の Lambda コードです。Python で書いています。
import boto3
import json
from boto3.session import Session
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# 引数で渡された AWS アカウント/ロールのクレデンシャルを取得
def sts_assume_role(account_id, role_name, region):
role_arn = "arn:aws:iam::" + account_id + ":role/" + role_name
session_name = "test"
client = boto3.client('sts')
# AssumeRole で一時クレデンシャルを取得
response = client.assume_role(
RoleArn=role_arn,
RoleSessionName=session_name
)
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
)
return session
def lambda_handler(event,context):
print("Received event: " + json.dumps(event, indent=2))
account_id = event.get('body')['account']
role_name = event.get('body')['role']
region = event.get('body')['region']
# account_id = event['account']
# role_name = event['role']
# region = event['region']
# イベントで指定されたAWSアカウント/ロールのクレデンシャルを取得
session = sts_assume_role(account_id, role_name, region)
ec2 = session.client('ec2')
# 取得したクレデンシャルを使ってインスタンスリソースを取得
instances = ec2.describe_instances(MaxResults=123)["Reservations"]
# logger.info(instances)
instanceList = []
# インスタンス一覧を取得
for i in instances:
for j in i["Instances"]:
values= {
'InstanceId': j.get("InstanceId"),
'Status': j.get("State")["Name"],
'InstanceType': j.get("InstanceType"),
'PrivateIpAddress': j.get("PrivateIpAddress"),
'SubnetId': j.get("SubnetId"),
'AvailabilityZone': j.get("Placement")["AvailabilityZone"],
'PublicIpAddress': j.get("PublicIpAddress"),
'ImageId': j.get("ImageId"),
'KeyName': j.get("KeyName"),
'Tags': j.get("Tags"),
}
instanceList.append(values)
return {
'isBase64Encoded': False,
'statusCode': 200,
'headers': {},
'body': instanceList
}
マスターアカウント(1111111111)のロールです。
このロールは Lambda にアタッチします。
複数の AWS の子アカウントに対して lambda から Switch ロールが実行できるように権限を付与します。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::99999999999:role/AWSGetResourceByLambdaReadOnlyRole",
"Effect": "Allow"
},
{
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::88888888888:role/AWSGetResourceByLambdaReadOnlyRole",
"Effect": "Allow"
},
]
}
子アカウントのロールです。
信頼関係をマスターアカウントのIDからのアクセスを許可するように付与します。
子アカウントのロールは、単にEC2のリソースを取得できる権限を付与しているだけです。
arn:aws:iam::1111111111:role/AWSGetResourceByLambdaReadOnlyRole
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*",
"ec2:SearchTransitGatewayRoutes",
"ec2:Get*"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
解説
注目すべき点は下記のコードです。
def sts_assume_role(account_id, role_name, region):
role_arn = "arn:aws:iam::" + account_id + ":role/" + role_name
session_name = "foobar"
client = boto3.client('sts')
# AssumeRoleで一時クレデンシャルを取得
response = client.assume_role(
RoleArn=role_arn,
RoleSessionName=session_name
)
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
)
return session
引数にとったアカウントIDとロール名によって一時的な Switch ロール用のクレデンシャルを発行できます。この一時クレデンシャルを利用して、Switch ロール先の子アカウントのリソース情報を取得することができます。
あとは、シークレットキー、アクセスキーとを用いたときの AWS SDK の利用方法と同じです。必要なリソース情報を取得し、煮るなり焼くなりしましょう。
私は、これを API GateWay にデプロイし外部から API を叩けるようにし、スプレッドシートでインスタンス一覧を管理するようにしています。
まとめ
やっぱり表計算で AWS リソースを管理したくなるのが、エンジニアのさがなのですかね。
一度スプレッドシートで管理しておけば、AWS にログインしなくても誰でもリソース情報が確認できるようになるので便利です。
特にインスタンスが何台動いているのか、無駄なインスタンスが動いていないかをすぐに把握できます。
また、インフラへの問い合わせも減って、苦労も削減できてみんなはっぴーです。
みんなでインフラの問い合わせを減らしましょうー!!