一時クレデンシャルを取得するserverlessコマンドのラッパースクリプト その2

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コマンドと同じように動かせます。

すごく変なことをしている気がするのですが、どうするのが正しいんだろう。

リンク

このスクリプトに至る経緯