この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 IoT事業部の若槻です。
前回のエントリでは、CircleCIとAWSをOIDC連携させて、永続的な認証情報を使用しないセキュアなAssumeRoleを試してみました。
今回は、CircleCIとAWSのOIDC連携でさらにセキュリティを高める対応として、特定のCircle CI Project(GitHub Repository)やUserにのみAssumeRoleを許可する設定を試してみました。
やってみた
同じCircleCI Organization(GitHub Account)に属するProject(Repository)であるrepository_a
とrepository_b
で試してみます。
準備
まず準備として、ProjectおよびUserの制限なくOIDCによるAssumeRoleが可能なOIDC設定を構築します。(前回のエントリとほぼ同じ構築内容です)
Circle CIのOrganization SettingsにOIDCに使用するContextsを作成します。Organization IDを控えます。
AWSには上記Contextsに対応したID Providerを作成します。
またAssumeRole用のIAM Roleを作成済します。
RoleのTrust Policyは次のように設定します。特定のOrganizationのID ProviderとのみFederation可能としていますが、ProjectおよびUserの制限はしていません。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "<id-providor-arn>"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
Contexts内に、AssumeRoleに必要なEnvironment Variablesとして、AWS_ROLE_ARN
とAWS_DEFAULT_REGION
を作成します。
それぞれのRepositoryに次のCircleCI Config(.circleci/config.yml
)を作成します。
.circleci/config.yml
version: 2.1
executors:
node:
docker:
- image: circleci/node # deprecated
orbs:
aws-cli: circleci/aws-cli@2.1.0
jobs:
assume:
executor: node
steps:
- checkout
- aws-cli/install
- run:
name: Assume role
command: |
aws_sts_credentials=$(aws sts assume-role-with-web-identity \
--role-arn ${AWS_ROLE_ARN} \
--web-identity-token ${CIRCLE_OIDC_TOKEN} \
--role-session-name "circleci-oidc" \
--duration-seconds 900 \
--query "Credentials" \
--output "json")
echo export AWS_ACCESS_KEY_ID="$(echo $aws_sts_credentials | jq -r '.AccessKeyId')" >> $BASH_ENV
echo export AWS_SECRET_ACCESS_KEY="$(echo $aws_sts_credentials | jq -r '.SecretAccessKey')" >> $BASH_ENV
echo export AWS_SESSION_TOKEN="$(echo $aws_sts_credentials | jq -r '.SessionToken')" >> $BASH_ENV
source $BASH_ENV
- run:
name: Some deploy
command: aws sts get-caller-identity
workflows:
version: 2
release:
jobs:
- assume:
context: aws-deploy
IAM Roleで何も制限を掛けなければ、同じOrganization(GitHub Account)内のProject間でContextを共有できるため、ContextからOIDC用のIAM Roleを取得してAssumeRoleが可能となります。
それぞれのRepositoryでWorkflowを実行すると、AssumeRoleは正常に行えています。
Project単位で許可する場合
それでは、まずProject単位でのOIDCによるAssumeRoleを許可してみます。
CircleCIのダッシュボードで、AssumeRoleを許可したいProject(ここではrepository_a
)のProject IDを控えます。
IAM RoleのTrust Policyを次のように編集します。先程控えたOrganization IDとProject IDを指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "<id-providor-arn>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"oidc.circleci.com/org/<organization-id>:sub": [
"org/<organization-id>/project/<project-id>/user/*"
]
}
}
}
]
}
repository_a
のWorkflowを実行すると、AssumeRoleは正常に行えました。
一方、repository_b
のWorkflowを実行すると、AssumeRoleはAccessDenied
エラーとなり失敗しました。Project単位での許可設定がちゃんとできているようです。
An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation: Not authorized to perform sts:AssumeRoleWithWebIdentity
User単位で許可する場合
続いて、User単位でのOIDCによるAssumeRoleを許可してみます。
CircleCIのダッシュボードで、AssumeRoleを許可したいUser(ここではcm-rwakatsuki
)のUser IDを控えます。
IAM RoleのTrust Policyを次のように編集します。subの末尾の*
をUser IDに置き換えます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "<id-providor-arn>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"oidc.circleci.com/org/<organization-id>:sub": [
"org/<organization-id>/project/<project-id>/user/<user-id>"
]
}
}
}
]
}
許可されたユーザーでWorkflowを実行すると、AssumeRoleは正常に行えました。
一方、許可されていないユーザーでWorkflowを実行すると、AssumeRoleはAccessDenied
エラーとなり失敗しました。User単位での許可設定がちゃんとできているようです。
An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation: Not authorized to perform sts:AssumeRoleWithWebIdentity
おわりに
CircleCIとAWSのOIDC連携で特定のProjectやUserにのみAssumeRoleを許可させてみました。
ProjectおよびUserの両方が難しければどちらか一方だけでも良いと思います。さらなるセキュリティ向上のために今回の許可設定は是非とも行っておきたいところです。
参考
- Using OpenID Connect Tokens in Jobs - CircleCI
- CircleCI が OIDC をサポート! 永続的な AWS Access Key を廃止できる!
- CircleCI-AWSをOIDC認証で連携する際のTips
以上