はじめに
STSのAssumeRoleを利用して他のロールの一時クレデンシャルを取得し
CostExplorerの情報取得を行う機会があったが、少々複雑だったため書いておきます。
行ったこと
- 環境AのAWSのサービス(今回はCostExplorer)にアクセスし情報を取得した。
- AssumeRoleの機能を使い、環境Bの一時クレデンシャルを取得し、
ロールBに許可されたAWSのサービス(今回はCostExplorer)にアクセスし情報を取得した。(下図) - slackへ送信した。
用意するもの
以下のものを用意し、lambda関数を実行すれば環境Aと環境BのCostExplorerを参照し、取得した価格情報が指定したSlackのURL先へと送信されます。(アカウントIDなど任意の物に書き直す必要があり、対応したSlackのURLも用意する必要があります)
環境A(ローカル)
ロールA(STSのAssumeRoleでロールBを指定したポリシー+環境Aの情報取得に必要なポリシーがアタッチされたもの)
lambda関数環境B(リモート)
ロールB(信頼関係の設定でロールAを指定+環境Bの情報取得に必要なポリシーがアタッチされたもの)
環境A(ローカル)
lambda関数
import boto3 from datetime import datetime,timedelta import re import urllib.request import json from boto3.session import Session # 異なるAWSアカウント/ロールのクレデンシャル取得を実行する def sts_assume_role(account_id,role_name): role_arn = "arn:aws:iam::" + account_id + ":role/" + role_name session_name = "foobar" region = "ap-northeast-1" 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 get_cost(client): today_year = datetime.now().year today_month = datetime.now().strftime('%m') today_day = datetime.now().strftime('%d') #today_str yesterday_day = datetime.now() - timedelta(days=1) #yesterday_datetime yesterday_month=yesterday_day.strftime('%m') yesterday_year=yesterday_day.year yesterday_day = yesterday_day.strftime('%d') #yesterday_str end = str(today_year) + "-" + str(today_month) + "-" + str(today_day) #today_str_year-month-day start = str(yesterday_year) + "-" + str(yesterday_month) + "-" + str(yesterday_day) #yesterday_str_year-month-day error_point response = client.get_cost_and_usage( TimePeriod={ 'Start': start, 'End' : end, }, Granularity='DAILY', Metrics= [ 'UnblendedCost' ] ) answer = re.findall('[0-9]+.[0-9]+',str(response)) return answer,start def lambda_handler(event,context): region1 = "ap-northeast-1" region2 = "us-east-1" client = boto3.client( 'ce', region_name = region2 ) account_id = "環境BアカウントID" role_name = "ロールB" answer,start=get_cost(client) # print(answer[2]) #イベントで指定されたAWSアカウント/ロールのクレデンシャルを取得 session = sts_assume_role(account_id,role_name) client2 = session.client('ce') answer2,start=get_cost(client2) # print(answer2[2]) obj={"text":"環境A : "+start+"=>"+answer[2]+"$"+"\n環境B : "+start+"=>"+answer2[2]+"$"} json_data = json.dumps(obj).encode("utf-8") request = urllib.request.Request("slackのURL", data=json_data, method="POST", headers={"Content-Type" : "application/json"}) with urllib.request.urlopen(request) as response: response_body = response.read().decode("utf-8")
ロールA– ポリシー1(環境Aの情報取得に必要なポリシー)
|-ポリシー2(STSのAssumeRoleでロールBを指定したポリシー)
- ポリシー1(環境Aの情報取得に必要なポリシー)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "sns:*", "aws-portal:*Usage", "aws-portal:*PaymentMethods", "aws-portal:*Billing", "ce:*" ], "Resource": "*" }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:*:*:*" } ] }
- ポリシー2(STSのAssumeRoleでロールBを指定したポリシー)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::環境BアカウントID:role/ロールB" } ] }
環境B(リモート)
ロールB– ポリシー(環境Bの情報取得に必要なポリシー)
|-信頼関係(AsuumeRole,ロールAを指定)
- ポリシー(環境Bの情報取得に必要なポリシー)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "aws-portal:*Billing", "aws-portal:*Usage", "aws-portal:*PaymentMethods" ], "Resource": "*" }, { "Effect": "Allow", "Action": "ce:*", "Resource": "*" }, { "Effect": "Allow", "Action": "sns:*", "Resource": "*" } ] }
- 信頼関係(AsuumeRole,ロールAを指定)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::環境AアカウントID:role/ロールA" }, "Action": "sts:AssumeRole", "Condition": {} } ] }
送信結果
環境A : 2018-11-18=>〇〇〇〇〇〇〇$ 環境B : 2018-11-18=>〇〇〇〇〇〇〇$