STS@AWSリソース¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. STSとは:Security Token Service¶
認証済みのIAMユーザーに対して、特定のAWSアカウントのAWSリソースに認可スコープを持つ一時的な認証情報 (アクセスキーID、シークレットアクセスキー、セッショントークン) を持つIAMユーザーを発行する。
02. スイッチロールの仕組み¶
スイッチロールとは¶
AssumeRole (権限委譲) によって、ユーザーのIAMロールを動的に切り替える。
1. IAMロールに信頼ポリシーを紐付け¶
必要なポリシーが設定されたIAMロールを作成する。
その時信頼ポリシーでは、IAMユーザーのARN
を信頼されたエンティティとして設定しておく。
これにより、そのIAMユーザーに対して、IAMロールを紐付けできるようになる。
この時に使用するユーザーは、IAMユーザーではなく、AWSリソースやフェデレーテッドユーザーでもよい。
{
"Version": "2012-10-17",
"Statement":
[
{
"Effect": "Allow",
"Principal":
{"AWS": "arn:aws:iam::<AWSアカウントID>:user/<ユーザー名>"},
"Action": "sts:AssumeRole",
"Condition": {
# 完全一致
"StringEquals": {"sts:ExternalId": "<適当な文字列>"},
},
},
],
}
2. IAMロールを引き受けた認証情報をリクエスト¶
信頼されたエンティティから、STSのエンドポイント (https://sts.amazonaws.com
) に対して、ロールの紐付けをリクエストする。
OIDCによるフェデレーションユーザーの場合は、--external-id
オプションの代わりに、--web-identity-token
オプションを使用する。
このオプションに、発行されたJWTを設定する必要がある。
#!/bin/bash
set -xeuo pipefail
# 事前に環境変数に実行環境名を代入する。
case "${ENV}" in
"tes")
aws_account_id="<テスト環境アカウントID>"
aws_access_key_id="<テスト環境アクセスキーID>"
aws_secret_access_key="<テスト環境シークレットアクセスキー>"
aws_iam_role_external_id="<信頼ポリシーに設定した外部ID>"
;;
"stg")
aws_account_id="<ステージング環境アカウントID>"
aws_access_key_id="<ステージング環境アクセスキーID>"
aws_secret_access_key="<ステージング環境シークレットアクセスキー>"
aws_iam_role_external_id="<信頼ポリシーに設定した外部ID>"
;;
"prd")
aws_account_id="<本番環境アカウントID>"
aws_access_key_id="<本番環境アクセスキーID>"
aws_secret_access_key="<本番環境シークレットアクセスキー>"
aws_iam_role_external_id="<信頼ポリシーに設定した外部ID>"
;;
*)
echo "The parameter "${ENV}" is invalid."
exit 1
;;
esac
# 信頼されたエンティティの認証情報を設定する。
aws configure set aws_access_key_id "$aws_account_id"
aws configure set aws_secret_access_key "$aws_secret_access_key"
aws configure set aws_default_region "ap-northeast-1"
# https://sts.amazonaws.com に、ロールの紐付けをリクエストする。
aws_sts_credentials="$(aws sts assume-role \
--role-arn "arn:aws:iam::${aws_access_key_id}:role/"${ENV}"-<紐付けしたいIAMロール名>" \
--role-session-name "<任意のセッション名>" \
--external-id "$aws_iam_role_external_id" \
--duration-seconds "<セッションの失効秒数>" \
--query "Credentials" \
--output "json")"
3. 返信されたレスポンスから認証情報を取得¶
STSのエンドポイントから一時的な認証情報が発行される。
また同時に、この認証情報は、ローカルマシンの~/.aws/cli/cache
ディレクトリ配下にもjson
ファイルで保管される。
認証情報の失効時間に合わせて、STSはこのjson
ファイルを定期的に更新する。
{
"Credentials":
{
"AccessKeyId": "<アクセスキーID>",
"SecretAccessKey": "<シークレットアクセスキー>",
"SessionToken": "<セッショントークン文字列>",
"Expiration": "<セッションの期限>",
},
"AssumeRoleUser":
{
"AssumedRoleId": "<セッションID>:<セッション名>",
"Arn": "arn:aws:sts:<新しいアカウントID>:assumed-role/<IAMロール名>/<セッション名>",
},
"ResponseMetadata":
{
"RequestId": "*****",
"HTTPStatusCode": 200,
"HTTPHeaders":
{
"x-amzn-requestid": "*****",
"content-type": "text/xml",
"content-length": "1472",
"date": "Fri, 01 Jul 2022 13:00:00 GMT",
},
"RetryAttempts": 0,
},
}
4. 認証情報を取得¶
レスポンスされたデータから認証情報を抽出する。
この時、アクセスキーID、シークレットアクセスキー、セッショントークン、が必要になる。
代わりに、~/.aws/cli/cache
ディレクトリ配下のjson
ファイルから取得しても良い。
認証情報を環境変数として出力し、使用できるようにする。
#!/bin/bash
cat <<EOF > assumed_user.sh
export AWS_ACCESS_KEY_ID="$(echo "$aws_sts_credentials" | jq -r ".AccessKeyId")"
export AWS_SECRET_ACCESS_KEY="$(echo "$aws_sts_credentials" | jq -r ".SecretAccessKey")"
export AWS_SESSION_TOKEN="$(echo "$aws_sts_credentials" | jq -r ".SessionToken")"
export AWS_ACCOUNT_ID="$aws_account_id"
export AWS_DEFAULT_REGION="ap-northeast-1"
EOF
環境変数に登録する代わりに、AWSの認証情報ファイルを作成しても良い。
#!/bin/bash
aws configure --profile "${ENV}"-repository <<EOF
$(echo "$aws_sts_credentials" | jq -r ".AccessKeyId")
$(echo "$aws_sts_credentials" | jq -r ".SecretAccessKey")
ap-northeast-1
json
EOF
echo aws_session_token = $(echo "$aws_sts_credentials" | jq -r ".SessionToken") >> ~/.aws/credentials
5. 認証認可の動作確認¶
ロールを引き受けた新しいアカウントを使用して、AWSリソースに認証認可できるか否かを確認する。
認証情報の取得方法として認証情報ファイルの作成をtfstate
ファイル択した場合、profile
オプションが必要である。
#!/bin/bash
# 認証情報ファイルを参照するオプションが必要がある。
aws s3 ls --profile <プロファイル名> <tfstateファイルが管理されるバケット名>
03. STSで発行されるIAMユーザー¶
Trusted Entityの事前作成¶
事前に、元となるIAMユーザー (Trusted Entity) を作成しておく。
AssumeRoleによるスイッチロールの仕組みでは、まずTrusted Entityをコールする。
Trusted Entityを使って、必要なIAMロールをSTSから発行し、一時的なIAMユーザーを作成する。
IAMユーザーの自動更新¶
STSで発行されたIAMユーザーには、そのAWSアカウント内のみで使用できるロールが紐付けられている。
この情報には失効秒数が存在し、期限が過ぎると新しいIAMユーザーになる。
秒数の最大値は、該当するIAMロールの概要の最大セッション時間から変更できる。
発行するIAMユーザーの切り替え¶
IAMユーザーを一括で管理しておき、特定のAWSアカウントでは特定の認可スコープを委譲する。
04. IAMユーザーの発行元¶
フェデレーテッドユーザー¶
任意のIDプロバイダーで認証済みのユーザー (フェデレーテッドユーザー) にIAMロールを付与することにより、AWSリソースにリクエストを送信できる。
OIDC、Web IDフェデレーション¶
▼ OIDC、Web IDフェデレーションとは¶
OIDCまたはWeb IDフェデレーションによる認証/認可を使用する。
▼ CognitoをIDプロバイダーとする場合¶
CognitoをIDプロバイダーとして使用するように、信頼されたエンティティを設定する。
{
"Version": "2012-10-17",
"Statement":
{
"Effect": "Allow",
"Principal": {"Federated": "cognito-identity.amazonaws.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
# 完全一致
"StringEquals": {"cognito-identity.amazonaws.com:aud": "*****"},
"ForAnyValue:StringLike":
{"cognito-identity.amazonaws.com:amr": "unauthenticated"},
},
},
}
▼ AWS EKSをIDプロバイダーとする場合¶
AWS EKSをIDプロバイダーとして使用するように、Federated
キーでAWS EKS Clusterの識別子を設定する。
これにより、AWS EKS Cluster内で認証済みのServiceAccountにIAMロールを紐付けることができるようになる。
また、Condition
キーで特定のServiceAccountを指定できるようにする。
{
"Version": "2012-10-17",
"Statement":
[
{
"Sid": "",
"Effect": "Allow",
"Principal":
{
"Federated": "arn:aws:iam::<AWSアカウントID>:oidc-provider/<AWS EKS ClusterのOpenID ConnectプロバイダーURL>",
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
# 完全一致
"StringEquals":
{
"<AWS EKS ClusterのOpenID ConnectプロバイダーURL>:sub":
["system:serviceaccount:<Namespace名>:<ServiceAccount名>"],
},
},
},
],
}
KubernetesのServiceAccountを作成し、IAMロールのARNを設定する。
ServiceAccountは、Terraformではなくマニフェストで定義した方が良い。
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
AWS EKS.amazonaws.com/role-arn: <IAMロールのARN>
name: <信頼されたエンティティで指定したユーザー名内のServiceAccount名>
namespace: <信頼されたエンティティで指定したユーザー名内のNamespace名>
IRSAにより、ServiceAccountを介してPodとAWS IAMロールが紐づく。
▼ その他のIDプロバイダー¶
- Auth0
- Keycloak
- Google Cloud Auth
SAMLベースフェデレーション¶
SAMLによる認証/認可を使用する。
05. IAMロールの委譲先ユーザー¶
IAMロールの委譲先ユーザー¶
IAMユーザー、AWSリソース、フェデレーテッドユーザー、にIAMロールを委譲できる。
IAMロールの委譲先ユーザーの種類¶
▼ IAMユーザー¶
IAMロールと同じ/異なるAWSアカウントのIAMユーザーに委譲できる。
IAMユーザーの場合、外部IDが必要になる。
▼ AWSリソース¶
IAMロールと同じ/異なるAWSアカウントのAWSリソースに委譲できる。
IAMリソースの場合、外部IDが必要になる。
▼ フェデレーテッドユーザー¶
OIDC、SAML、によって発行されたユーザーに委譲できる。
OIDCのフェデレーテッドユーザーの場合、発行されたJWTが必要になる。
フェデレーテッドユーザー¶
▼ AWS OIDC¶
IAMロールの信頼されたエンティティに、AWS OIDCで発行されたユーザーを設定する。
フェデレーテッドユーザーは任意のIPプロバイダーで発行する。
{
"Version": "2012-10-17",
"Statement":
{
"Effect": "Allow",
"Principal": {"Federated": "cognito-identity.amazonaws.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
# 完全一致
"StringEquals": {"cognito-identity.amazonaws.com:aud": "*****"},
"ForAnyValue:StringLike":
{"cognito-identity.amazonaws.com:amr": "unauthenticated"},
},
},
}
▼ 外部OIDC¶
IAMロールの信頼されたエンティティに、外部OIDCサービスで発行されたユーザーを設定する。
{
"Version": "2012-10-17",
"Statement":
{
"Effect": "Allow",
"Principal": {"Federated": "accounts.google.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
# 完全一致
"StringEquals": {"accounts.google.com:aud": "*****"},
"ForAnyValue:StringLike":
{"accounts.google.com:amr": "unauthenticated"},
},
},
}
▼ AWS SAML¶
IAMロールの信頼されたエンティティに、AWS SAMLで発行されたユーザーを設定する。
{
"Version": "2012-10-17",
"Statement":
[
{
"Effect": "Allow",
"Principal":
{
"Federated": "arn:aws:iam::<AWSアカウントID>:saml-provider/<プロバイダー名>",
},
"Action": "sts:AssumeRole",
"Condition": {
# 完全一致
"StringEquals": {"SAML:aud": "https://signin.aws.amazon.com/saml"},
},
},
],
}