Serverless Frameworkは ~/.aws/config に書いたAssume Roleの設定を読んでくれないようなので、先日、EC2にアタッチされたIAM Roleからassume roleして、一時クレデンシャルを取得して、Serverless Frameworkを実行するスクリプトを書きました。 credential_source=EC2InstanceMetadata の場合だけの場当たり的な処理を追加したスクリプトでした。今回は source_profile にも対応しました。
スクリプト
シェルスクリプトですが、Pythonコードも埋め込まれています。
#!/bin/bash
# serverlessコマンドのラッパーとして機能する簡易的なスクリプト。
#
# --aws-profile が指定されていた場合に
# ~/.aws/config を読み込み、
# credential_sourceまたはsource_profile と role_arn が指定されていた場合は、
# 一時クレデンシャルを取得してserverlessを実行する。
# --aws-profile は先頭に必要で、途中では認識しない。
profile=
if [ $# -ge 2 ]; then
if [ "$1" = --aws-profile ]; then
profile="$2"
shift
shift
fi
fi
if [ -z "$profile" ]; then
# そのままserverlessを実行
echo serverless "$@"
exec serverless "$@"
fi
################################
# boto3で一時クレデンシャル取得
################################
tmpfile=$(mktemp)
python <<EOF > $tmpfile
import configparser
import os
import sys
import boto3
home_path = "$HOME"
aws_config_filepath = home_path + "/.aws/config"
profile = "$profile"
if not os.path.exists(aws_config_filepath):
sys.exit(0)
aws_config = configparser.ConfigParser()
aws_config.read(aws_config_filepath)
section_name = "profile " + profile
def get_config(name):
try:
return aws_config.get(section_name, name)
except configparser.NoOptionError:
return None
except configparser.NoSectionError:
return None
credential_source = get_config("credential_source")
source_profile = get_config("source_profile")
role_arn = get_config("role_arn")
if credential_source == "Ec2InstanceMetadata":
session = boto3.session.Session()
sts_client = session.client("sts")
res = sts_client.assume_role(
RoleArn = role_arn,
RoleSessionName = "serverless",
DurationSeconds = 900,
)
elif source_profile != None:
session = boto3.session.Session(profile_name = profile)
sts_client = session.client("sts")
res = sts_client.assume_role(
RoleArn = role_arn,
RoleSessionName = "serverless",
DurationSeconds = 900,
)
else:
session = boto3.session.Session(profile_name = profile)
sts_client = session.client("sts")
res = sts_client.get_session_token(
DurationSeconds = 900,
)
access_key_id = res["Credentials"]["AccessKeyId"]
secret_access_key = res["Credentials"]["SecretAccessKey"]
session_token = res["Credentials"]["SessionToken"]
print(f"export AWS_ACCESS_KEY_ID={access_key_id}")
print(f"export AWS_SECRET_ACCESS_KEY=\"{secret_access_key}\"")
print(f"export AWS_SESSION_TOKEN=\"{session_token}\"")
EOF
. $tmpfile
rm $tmpfile
################################
# 取得したアクセスキーでserverless実行
################################
echo serverless "$@"
exec serverless "$@"
################################
適当な名前で実行権限を付けて、PATHの通るところに置けば、普通のserverlessコマンドと同じように動かせます。
すごく変なことをしている気がするのですが、どうするのが正しいんだろう。
リンク
このスクリプトに至る経緯