この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 IoT事業部の若槻です。
GitHub Actionsで、不必要なシークレットまで取得するWorkflowを組んでしまっていませんか?私は今まで組んでしまっていました。
そこで今回は、GitHub Actionsで三項演算子(condition ? exprIfTrue : exprIfFalse
)ライクな記述を使用して、ブランチ名に応じて必要なシークレットのみ取得するWorkflowを作ってみました。
不必要なシークレットまで取得してしまうパターン
AWSの開発/ステージング/本番環境の認証情報を使用してシステムのデプロイを行うWorkflowを想定します。開発はdevelop
、ステージングはstaging
、本番はmain
のブランチにマージが行われた時にそれぞれの環境にデプロイが行われる想定です。
.github/workflows/cicd.yaml(不必要なシークレットを取得してしまうパターン)
on:
push:
paths-ignore:
- '**/*.md'
jobs:
integration:
runs-on: ubuntu-latest
steps:
- run: echo "中略"
deploy:
runs-on: ubuntu-latest
needs: integration
if: |
github.ref_name == 'develop' ||
github.ref_name == 'staging' ||
github.ref_name == 'main'
env:
DEV_AWS_OIDC_ROLE_ARN: ${{ secrets.DEV_AWS_OIDC_ROLE_ARN }}
STG_AWS_OIDC_ROLE_ARN: ${{ secrets.STG_AWS_OIDC_ROLE_ARN }}
PRD_AWS_OIDC_ROLE_ARN: ${{ secrets.PRD_AWS_OIDC_ROLE_ARN }}
AWS_REGION: us-east-1
permissions:
id-token: write
contents: read
steps:
- name: debug
run: |
echo Branch: ${{ github.ref_name }}
echo DEV_AWS_OIDC_ROLE_ARN: ${DEV_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:}
echo STG_AWS_OIDC_ROLE_ARN: ${STG_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:}
echo PRD_AWS_OIDC_ROLE_ARN: ${PRD_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:}
- name: Assume Role DEV
if: ${{ github.ref_name == 'develop' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.DEV_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
- name: Assume Role STG
if: ${{ github.ref_name == 'staging' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.STG_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
- name: Assume Role PRD
if: ${{ github.ref_name == 'main' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.PRD_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
# checkout & some build & deploy
env
では開発/ステージング/本番環境それぞれの認証情報をシークレットからすべて取得して環境変数に格納するようになっています。
.github/workflows/cicd.yaml(不必要なシークレットを取得してしまうパターン)
env:
DEV_AWS_OIDC_ROLE_ARN: ${{ secrets.DEV_AWS_OIDC_ROLE_ARN }}
STG_AWS_OIDC_ROLE_ARN: ${{ secrets.STG_AWS_OIDC_ROLE_ARN }}
PRD_AWS_OIDC_ROLE_ARN: ${{ secrets.PRD_AWS_OIDC_ROLE_ARN }}
認証情報を使用した認証(AssumeRole)処理では、ブランチに応じてどの環境変数を使用して認証を行うかの条件分岐を書いています。
.github/workflows/cicd.yaml(不必要なシークレットを取得してしまうパターン)
- name: Assume Role DEV
if: ${{ github.ref_name == 'develop' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.DEV_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
- name: Assume Role STG
if: ${{ github.ref_name == 'staging' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.STG_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
- name: Assume Role PRD
if: ${{ github.ref_name == 'main' }}
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.PRD_AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
そしてこのWorkflowを使用して、例えばfeature/xxxxxxx
ブランチからdevelop
ブランチへマージすると、開発環境に対するAssumeRoleが行われますが、シークレットの取得は全環境に対して行われてしまいます。.../dev-github-oidc-role
が開発、.../stg-github-oidc-role
がステージング、.../prd-github-oidc-role
が本番環境用の認証情報です。
このシークレットをすべて取得する処理は認証情報を不必要に暴露させるため、セキュリティリスクに繋がります。開発環境へのデプロイを行うのに、ステージングおよび本番環境の認証情報をシークレットから取得する必要はないはずです。
必要なシークレットのみ取得してみる
そこで、Workflowを次のように修正します。
.github/workflows/cicd.yaml
on:
push:
paths-ignore:
- '**/*.md'
jobs:
integration:
runs-on: ubuntu-latest
steps:
- run: echo "中略"
deploy:
runs-on: ubuntu-latest
needs: integration
if: |
github.ref_name == 'develop' ||
github.ref_name == 'staging' ||
github.ref_name == 'main'
env:
AWS_OIDC_ROLE_ARN: |
${{
github.ref_name == 'main' &&
secrets.PRD_AWS_OIDC_ROLE_ARN ||
github.ref_name == 'staging' &&
secrets.STG_AWS_OIDC_ROLE_ARN ||
secrets.DEV_AWS_OIDC_ROLE_ARN
}}
AWS_REGION: us-east-1
permissions:
id-token: write
contents: read
steps:
- name: debug
run: |
echo Branch: ${{ github.ref_name }}
echo AWS_OIDC_ROLE_ARN: ${AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:}
- name: Assume Role
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
# checkout & some build & deploy
GitHub ActionsのExpressionsでは、次のような三項演算子ライクな記述が可能です。それを使用して単一の環境変数に対して現在のブランチ名に応じたシークレットの指定が可能です。
.github/workflows/cicd.yaml
env:
AWS_OIDC_ROLE_ARN: |
${{
github.ref_name == 'main' &&
secrets.PRD_AWS_OIDC_ROLE_ARN ||
github.ref_name == 'staging' &&
secrets.STG_AWS_OIDC_ROLE_ARN ||
secrets.DEV_AWS_OIDC_ROLE_ARN
}}
認証情報を使用した認証(AssumeRole)処理で、指定する環境変数はブランチによって変わらないため、一つの処理を済めば事足ります。
.github/workflows/cicd.yaml
- name: Assume Role
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
aws-region: ${{env.AWS_REGION}}
feature/xxxxxxx
からdevelop
へマージすると、開発環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
develop
からstaging
へマージすると、ステージング環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
staging
からmain
へマージすると、本番環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
おわりに
GitHub Actionsで三項演算子ライクな記述を使用して、ブランチ名に応じて必要なシークレットのみ取得するWorkflowを作ってみました。
GitHub ActionsのExpressionsは使いこなすと様々な表現が出来ることが分かり、いじっていて楽しかったです。こういう小さな積み重ねを大事にしたいですね。
参考
- Possible to use conditional in the "env" section of a job? - Code to Cloud / GitHub Actions - GitHub Community
- How to write multi-line condition in if - Code to Cloud / GitHub Actions - GitHub Community
- Push時はCIのみ、Merge時はCIおよびCDを実行するGitHub Actionsを作る(単一のWorkflowで) | DevelopersIO
以上