æ¬æ¥ã®ãé¡
- CD/CDãªã©ã§GitHub Actionããcdk deployã³ãã³ããå®æ½ããéã«ãOIDCã使ç¨ãã¦(IAM Userã®ã¢ã¯ã»ã¹ãã¼ï¼ã·ã¼ã¯ã¬ããã¢ã¯ã»ã¹ãã¼ã§ã¯ãªã)IAM Roleã§AWSã¨èªè¨¼ãè¡ãæ¹æ³
- ä¸è¨ãAWS CDKã§å®è£ ããæ¹æ³
ä¸è¨ãå®æ½ããéã«å¿ è¦ãªæé
- IAM OIDC IDãããã¤ãã¼ãä½æãã
- èªè¨¼ç¨ã®IAM Roleãä½æãã
- ä¸è¨IAM Roleã«å¿ è¦ãªããªã·ã¼ãã¢ã¿ãããã
- GitHub Actionsã«ã¦configure-aws-credentialsã使ç¨ãã¦AWSã¨èªè¨¼ãã
AWS CDKã®ã³ã¼ã
ä»åã¯ããããªãAWS CDKã®ã³ã¼ããæ²è¼ãã¾ãã(å¤åãã®æ¹ãããããããã®ã§)
import * as cdk from 'aws-cdk-lib'; import { aws_iam } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class OIDCSampleStack extends cdk.Stack { constructor(scope: Construct, id: string) { super(scope, id); // cdk deployAWSãå®æ½ããAWSã¢ã«ã¦ã³ãã¨ãªã¼ã¸ã§ã³ const accountId = this.account; const region = this.region; const user = '<対象ã®GitHubã¦ã¼ã¶ã¼å>'; const repo = '<対象ã®ãªãã¸ããªå>'; const branch = '<対象ã®ãã©ã³ãå>'; // 1. IAM OIDC IDãããã¤ãã¼ãä½æãã const oidcProvider = new aws_iam.OpenIdConnectProvider( this, 'GitHubOIDCProvider', { url: 'https://token.actions.githubusercontent.com', clientIds: ['sts.amazonaws.com'], } ); // 2. èªè¨¼ç¨ã®IAM Roleãä½æãã const oidcDeployRole = new aws_iam.Role(this, 'GitHubOidcRole', { roleName: 'github-oidc-role', assumedBy: new aws_iam.FederatedPrincipal( oidcProvider.openIdConnectProviderArn, { StringLike: { 'token.actions.githubusercontent.com:sub': `repo:${user}/${repo}:ref:refs/heads/${branch}`, }, }, 'sts:AssumeRoleWithWebIdentity' //ãããå¿ããã¨Statementã®Actionã'sts:AssumeRole'ã¨ãªãOIDCã§ã®AssumeRoleã§ä½¿ããªããªãã ), }); // 3. ä¸è¨IAM Roleã«å¿ è¦ãªããªã·ã¼ãã¢ã¿ãããã const deployPolicy = new aws_iam.Policy(this, 'deployPolicy', { policyName: 'deployPolicy', statements: [ new aws_iam.PolicyStatement({ effect: aws_iam.Effect.ALLOW, actions: ['sts:AssumeRole'], resources: [ `arn:aws:iam::${accountId}:role/cdk-hnb659fds-deploy-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-file-publishing-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-image-publishing-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-lookup-role-${accountId}-${region}`, ], }), ], }); oidcDeployRole.attachInlinePolicy(deployPolicy); } }
1. IAM OIDC IDãããã¤ãã¼ãä½æãã
IAM OIDC IDãããã¤ãã¼ãä½æãããã®URLã« https://token.actions.githubusercontent.com
(ãã®ãã¹ãåã¯åºå®)ãã¯ã©ã¤ã¢ã³ãIDã«AWS Security Token Service (AWS STS)ãæå®ãã¾ãã
2. èªè¨¼ç¨ã®IAM Roleãä½æãã
IAM OIDC IDãããã¤ãã¼ã«å¯¾ããGitHub Actionsããã®ãã§ãã¬ã¼ã·ã§ã³èªè¨¼ã®å ´åã«Assume Roleãã許å¯ããIAM Roleãä½æãã¾ãã
ããã¦ãã®URLã« https://token.actions.githubusercontent.com
ãã¯ã©ã¤ã¢ã³ãIDã«AWS Security Token Service (AWS STS)ãæå®ãã¾ãã
ã¾ããã®éã«GitHubã®ã¦ã¼ã¶ã¼åããªãã¸ããªåããã©ã³ãåãæå®ãã対象ã®ãã©ã³ãã§ã®ã¿èªè¨¼ãè¡ãããã«ãã¾ãã
ãªããã®æassumeRoleAction
å¼æ°ã«ãsts:AssumeRoleWithWebIdentityããæå®ããªãã¨OIDCã§ã®AssumeRoleãåºæ¥ãªãã®ã§æ³¨æã§ãã(ãsts:AssumeRoleãã§ã¯ãã¡)
3. ä¸è¨IAM Roleã«å¿ è¦ãªããªã·ã¼ãã¢ã¿ãããã
ä¸è¨IAM ããªã·ã¼ãä½æããä¸è¨IAM Roleã«ã¢ã¿ãããã¾ãã
ä»åã¯cdk deploy
ãå®æ½ããç¨ã®ããªã·ã¼ãã¤ã³ã©ã¤ã³ããªã·ã¼ã¨ãã¦ã¢ã¿ãããã¦ãã¾ãã
ã¡ãªã¿ã«ä¸è¨ããªã·ã¼ã®å
容ï¼sts:AssumeRoleå
ã®ãªã½ã¼ã¹ã®å
容ã«ã¤ãã¦ã¯ãä¸è¨ããåç
§ãã ããã(äºåã« cdk bootstrap
ãå®æ½æ¸ã§ãããã¨ãåæã§ã)
GitHub Enterprise(GHE) ã®å ´å
ãã¡ããä»åã®æ¹æ³ã¯GHEã§ã使ç¨ã§ãã¾ãããGHEã®å ´åãGitHubã¨ä»¥ä¸ã®ç¹ãç°ãªãã¾ãã
- ã¦ã¼ã¶ã¼åãæå®ãã¦ããç®æã¯ãGHEã§ã¯organizationåãæå®ãã
- ãã¹ãåã¯
token.actions.githubusercontent.com
ã§ã¯ãªãã ã<GHEã®ãã¡ã¤ã³å>/_services/tokenãã«ãªã
ä¾ãã°organizationããmy_orgããGHEã®ãã¡ã¤ã³åããgithub.hogehoge.comãã®å ´åãCDKã®ã½ã¼ã¹ã¯ãããªãã¾ãã(å·®åã ãè¨è¼)
const oidcProvider = new aws_iam.OpenIdConnectProvider( this, 'GitHubOIDCProvider', { url: 'https://github.hogehoge.com/_services/token', clientIds: ['sts.amazonaws.com'], } ); // 2. èªè¨¼ç¨ã®IAM Roleãä½æãã const oidcDeployRole = new aws_iam.Role(this, 'GitHubOidcRole', { roleName: 'github-oidc-role', assumedBy: new aws_iam.FederatedPrincipal( oidcProvider.openIdConnectProviderArn, { StringLike: { 'github.hogehoge.com/_services/token:sub': `repo:my_org/${repo}:ref:refs/heads/${branch}`, }, }, 'sts:AssumeRoleWithWebIdentity' ), }); } }
OIDC IDãããã¤ãã¼ã®ãµã ããªã³ãã«ã¤ãã¦
ä»ã¾ã§IAM OIDC IDãããã¤ãã¼ã使ç¨ããå ´åãOIDC IDãããã¤ãã¼ã®æ¤è¨¼ç¨ã«ãµã ããªã³ã(thumbprint)ãè¨å®ããå¿ è¦ãããã¾ããããä»å¹´ã®7/6ãããµã ããªã³ããæ¤è¨¼ã«å¿ è¦ãªããªãã¾ããã
ãªãAWS CDKã§ã¯ãµã ããªã³ãã¯ä»»æé ç®ã§ãCloudFormationã§ã¯å¿ é é ç®ã§ãããé©å½ãªå¤ãå ¥ãã¦ããã°è¯ãã¿ããã§ãã
GitHub Actions
# ããªã¬è¨å®ã¯é©å®å¤æ´ # æä½éããæ¸ãã¦ãªãã§ã(cacheå¦çãªã©ã¯çç¥) on: push: branches: - 'develop' - 'main' jobs: deploy: runs-on: ubuntu-latest env: # ä»åã¯ç´æ¥è¨è¼ãã¦ããããå¿ è¦ã«å¿ãã¦secretsã«ç»é²ãã AWS_ACCOUNT_ID: "<AWSã¢ã«ã¦ã³ãçªå·>" AWS_REGION: "ap-northeast-1" # ããã§permissionãè¨å®ããã®ãå¤§äº permissions: id-token: write contents: read steps: - name: Checkout uses: actions/checkout@v3 - name: Install CDK Dependency run: npm ci # 4. GitHubã«ã¦configure-aws-credentialsã使ç¨ãã¦AWSã¨èªè¨¼ãã - name: Assume Role uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: "arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/github-oidc-role" aws-region: ${{ env.AWS_REGION }} # npm scriptã«ç»é²ãã¦ãããcdk deployã³ãã³ããå®æ½ãã - name: Deploy run: npm run deploy
ãã¤ã³ãã¯ä¸è¨2ç¹ã§ã
permissionsã«id-token: writeãcontents: readãè¨å®ãã
ãããè¨å®ããªãã¨OIDCã使ç¨ãã¦cdk deploy
ãå®æ½ã§ããªã
aws-actions/configure-aws-credentials@v2ã使ç¨ãã¦ãã2. èªè¨¼ç¨ã®IAM Roleãä½æãããã§ä½æããIAM Roleã§èªè¨¼ãè¡ã
role-to-assume
ã«è©²å½IAM Roleã®Arnãæå®ãã
ã¡ãªã¿ã«ãã¼ã«åã ã¨ãcredentialæ å ±ããªããã¿ãããªã¨ã©ã¼ã«ãªã£ãã(secretsã«ã¢ã¯ã»ã¹ãã¼ï¼ã·ã¼ã¯ã¬ããã¢ã¯ã»ã¹ãã¼ãç»é²ããã°OKãã)
ãã ããããããããªãããOIDCã使ç¨ãã¦ããã®ã«ããããã£ããæå³ããªã...
ã¾ã¨ã
以ä¸ãAWS CDKã§GitHubã§OIDCã使ç¨ãã¦AWSã¨èªè¨¼ããæ¹æ³ã§ããã
ã¢ã¯ã»ã¹ãã¼ï¼ã·ã¼ã¯ã¬ããã¢ã¯ã»ã¹ãã¼ã¯ã»ãã¥ãªãã£çãªè¦³ç¹ããããçºè¡ããªãã§æ¸ããªãããã«è¶ãããã¨ã¯ãªãã®ã§ãä»åã®ãããªææ³ãç©æ¥µçã«åãå ¥ãã¦ãããã»ãã¥ã¢ã«ãªãã°ã¨æãã¾ãã
ãªããGitHubå´ã§ãç¹å®ã®IPã¢ãã¬ã¹ããããæ¥ç¶ã許å¯ãã¦ããªãããããªè¨å®ããã¦ããå ´åããã®æ¹æ³ã使ããªãã®ã§ããã®å ´åã¯æ®å¿µãªãããã®æ¹æ³ã¯ä½¿ãã¾ããã(GHEã§ãããã¡)
ã§ã¯ãä»åã¯ãã®è¾ºã§ã