雰囲気エンジニアの備忘録

Atmosphere Engineer's Memorandum

PostsGithub CodespacesにAssumeRoleを設定する

Github CodespacesにAssumeRoleを設定する

概要

AWS の講座などを見ていると,たいがい最初にIAMユーザーを作成する,というチャプターがあります。
IAMユーザーの権限が大きい場合,シークレットキーの漏洩で被害が大きくなる可能性があります。

ユーザーの権限を最小限にし,AssumeRoleにより一時的に開発用のロールを取得する方法を考えました。

Github Codespacesを使うことを想定して開発しますが,他の環境でも転用可能です。

assumeRoleについて

https://dev.classmethod.jp/articles/iam-role-passrole-assumerole/https://dev.classmethod.jp/articles/iam-role-passrole-assumerole/

コード(ロール,ユーザーの設定)

Cloudshellなどで,以下のコマンドを実行します。
"sts:AssumeRole"のみを実行できるIAMユーザーを作成し,"PowerUserAccess"ポリシーを保有するロールを使用できる権限を与えます。

setup_assume_role.sh
#!/bin/bash

set -e

# ----------- 変数設定 -------------
IAM_USER_NAME="codespaces-user"
ROLE_NAME="codespaces-assumable-role"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# ----------- IAMユーザー作成 -------------
echo "👤 Creating IAM user: $IAM_USER_NAME (if not exists)"
aws iam create-user --user-name "$IAM_USER_NAME" 2>/dev/null || echo "ℹ️ User already exists."

# アクセスキー作成
echo "🔐 Creating access key for $IAM_USER_NAME"
ACCESS_KEYS=$(aws iam create-access-key --user-name "$IAM_USER_NAME")
ACCESS_KEY_ID=$(echo "$ACCESS_KEYS" | jq -r '.AccessKey.AccessKeyId')
SECRET_ACCESS_KEY=$(echo "$ACCESS_KEYS" | jq -r '.AccessKey.SecretAccessKey')

# ----------- AssumeRole パーミッション付与 -------------
echo "📜 Attaching sts:AssumeRole permission to $IAM_USER_NAME"
POLICY_DOC=$(cat <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME"
  }]
}
EOF
)
echo "$POLICY_DOC" > temp-user-policy.json
aws iam put-user-policy \
  --user-name "$IAM_USER_NAME" \
  --policy-name "AllowAssumeRole" \
  --policy-document file://temp-user-policy.json
rm temp-user-policy.json

# ----------- IAMロール作成 -------------
echo "🎭 Creating IAM role: $ROLE_NAME (if not exists)"
TRUST_POLICY=$(cat <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::$ACCOUNT_ID:user/$IAM_USER_NAME"
    },
    "Action": "sts:AssumeRole"
  }]
}
EOF
)
echo "$TRUST_POLICY" > trust-policy.json
aws iam create-role \
  --role-name "$ROLE_NAME" \
  --max-session-duration 4 \
  --assume-role-policy-document file://trust-policy.json 2>/dev/null || echo "ℹ️ Role already exists."
rm trust-policy.json

# ----------- PowerUserAccess ポリシーをロールにアタッチ -------------
echo "⚡ Attaching PowerUserAccess policy to role: $ROLE_NAME"
aws iam attach-role-policy \
  --role-name "$ROLE_NAME" \
  --policy-arn arn:aws:iam::aws:policy/PowerUserAccess

# ----------- GitHub 用出力 -------------
echo ""
echo "📝 Add the following IAM user credentials to your GitHub Codespaces secrets:"
echo "-------------------------------------------------------------"
echo "AWS_ACCESS_KEY_ID=$ACCESS_KEY_ID"
echo "AWS_SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY"
echo "-------------------------------------------------------------"

実行すると,codespaces-userというIAMユーザー,codespaces-assumable-roleというIAMロールが作成されます。
ロールのほうには最大セッション時間を設定できる引数(--max-session-duration)があるので用途に応じて変更します。(デフォルト:1時間)

コード(ログイン用)

上記のスクリプトで最後に出力される,codespaces-userのAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYを控えておき,Githubレポジトリのシークレットに設定しておきます。

(このシークレットは"sts:AssumeRole"しか実行権限がないので幾分安全なはずですが,念のため漏洩には気を付ける必要があります)

export AWS_PERSISTENT_ACCESS_KEY_ID=xxxxxxxxxxxxxx
export AWS_PERSISTENT_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=ap-northeast-1

以下のシェルスクリプトを実行するとAssume Roleが実行され,新たにAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKENという環境変数が設定されます。
これらは一定時間で無効化される一時的なアクセスキーです。

login.sh
#!/bin/bash

ROLE_NAME="codespaces-assumable-role"
ACCOUNT_ID="アカウントIDを指定"

# 永続キーを Secrets から設定(最初のみ)
export AWS_ACCESS_KEY_ID=${AWS_PERSISTENT_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${AWS_PERSISTENT_SECRET_ACCESS_KEY}

# AssumeRole 実行
CREDS=$(aws sts assume-role \
  --role-arn arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME \
  --role-session-name codespace-session \
  --duration-seconds 14400) # 4h   

# 取得した一時トークンで上書き
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r '.Credentials.SessionToken')

echo "✅ Temporary AWS credentials set"
echo "⏰ Credentials valid until: $(echo "$CREDS" | jq -r '.Credentials.Expiration')"

実行後はPowerUserAccessの権限を得ているので,例えば以下のようなコマンドが実行可能になります。

aws s3 ls    

一定時間が過ぎトークンの有効期限が切れた後も,もう一度login.shを実行すれば再度認証できます。

まとめ

認証管理が有効期限つきのトークンになったので,鍵漏洩のリスクが少し減少した。