AWS CDK で作成した Secrets Manager シークレットを GitHub Actions で aws-actions/aws-secretsmanager-get-secrets を使用して環境変数に設定する
こんにちは、製造ビジネステクノロジー部の若槻です。
システムのテストにはいくつか種類がありますが、実際のシステムに接続する Integration テスト(E2E テスト)を GitHub Actions 上で実行したい場合に 、API への接続情報や AWS リソースの ARN などの情報をワークフロー内で環境変数として参照したいことがあると思います。しかし参照するべき値が増えていくと、そのたびにワークフローファイルを修正する手間が発生したり、設定忘れが起きやすくなったりしてしまいます。
そのような場合におすすめなのが aws-actions/aws-secretsmanager-get-secrets という AWS 公式アクションです。このアクションを使用すると、GitHub Actions ワークフロー内で参照したい環境変数の管理を AWS Secrets Manager シークレットに集約し、運用を簡素化することが可能になります。
今回は、AWS CDK で作成した Secrets Manager シークレットを GitHub Actions で aws-actions/aws-secretsmanager-get-secrets を使用して取得し、環境変数に設定する方法を紹介します。
やってみた
AWS CDK 実装
まず、必要な AWS リソースを AWS CDK で実装します。以下のコードでは、2つの Secrets Manager シークレットと GitHub Actions OIDC ロールを作成しています。
import * as cdk from "aws-cdk-lib";
import * as iam from "aws-cdk-lib/aws-iam";
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
import { Construct } from "constructs";
export class MainStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);
const awsAccountId = cdk.Stack.of(this).account;
const githubOrganizationName = process.env.GITHUB_ORGANIZATION_NAME || "";
const githubRepositoryName = process.env.GITHUB_REPOSITORY_NAME || "";
/**
* Secrets Manager シークレット 1 の作成
*/
const secret1 = new secretsmanager.Secret(this, "Secret1", {
secretObjectValue: {
api_user: cdk.SecretValue.unsafePlainText("user_hoge_"),
api_key: cdk.SecretValue.unsafePlainText("key_fuga_"),
config: cdk.SecretValue.unsafePlainText(
JSON.stringify({ active: "user2_piyo_", standby: "user3_nyan_" })
),
},
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
new cdk.CfnOutput(this, "Secret1ArnOutput", {
value: secret1.secretArn,
description:
"Specify this output value with the aws-actions/aws-secretsmanager-get-secret action to get the value of the secret1.",
});
/**
* Secrets Manager シークレット 2 の作成
*/
const secret2 = new secretsmanager.Secret(this, "Secret2", {
secretObjectValue: {
myusername: cdk.SecretValue.unsafePlainText("alejandro_rosalez_"),
mypassword: cdk.SecretValue.unsafePlainText("EXAMPLE_PASSWORD_"),
},
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
new cdk.CfnOutput(this, "Secret2ArnOutput", {
value: secret2.secretArn,
description:
"Specify this output value with the aws-actions/aws-secretsmanager-get-secret action to get the value of the secret2.",
});
/**
* GitHub Actions OIDC ロールの作成
*/
const gitHubActionsOidcRole = new iam.Role(this, "GitHubActionsOidcRole", {
assumedBy: new iam.FederatedPrincipal(
`arn:aws:iam::${awsAccountId}:oidc-provider/token.actions.githubusercontent.com`,
{
StringEquals: {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
},
StringLike: {
"token.actions.githubusercontent.com:sub": `repo:${githubOrganizationName}/${githubRepositoryName}:*`,
},
},
"sts:AssumeRoleWithWebIdentity"
),
});
new cdk.CfnOutput(this, "GitHubActionsOidcRoleArnOutput", {
value: gitHubActionsOidcRole.roleArn,
description:
"Specify this output value with the aws-actions/configure-aws-credentials action to assume the role.",
});
/**
* GitHub Actions OIDC ロールに Secrets Manager シークレットの読み取り権限を付与
*/
secret1.grantRead(gitHubActionsOidcRole);
secret2.grantRead(gitHubActionsOidcRole);
}
}
シークレット作成時のポイントとして、secretObjectValue
プロパティを使用して、シークレットの値をオブジェクトとして定義しています。これにより、シークレットの値を JSON 形式の階層で管理でき、また後述の GitHub Actions ワークフローでも個別の環境変数として展開することが可能になります。
上記実装を AWS CDK でデプロイします。
GitHub Environments の設定
前述の CDK 実装をデプロイすると出力されるリソースの ARN を GitHub Environments の変数として以下の通り登録します。
変数名 | 値 |
---|---|
ROLE_TO_ASSUME_ARN | GitHubActionsOidcRole の ARN |
SECRET1_ARN | Secret1 の ARN |
SECRET2_ARN | Secret2 の ARN |
GitHub Actions ワークフロー
aws-actions/aws-secretsmanager-get-secrets
アクションを使用して Secrets Manager シークレットの値を取得し、環境変数に設定する GitHub Actions ワークフローを作成します。
name: SECRET_RETRIEVE_TEST
on: workflow_dispatch
jobs:
get-secrets:
environment: DEVELOPMENT
runs-on: ubuntu-latest
permissions:
# @see https://github.com/aws-actions/configure-aws-credentials?tab=readme-ov-file#oidc
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
# AWS 認証情報を設定
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.ROLE_TO_ASSUME_ARN }} # CDK で作成した GitHubActionsOidcRole の ARN
aws-region: ap-northeast-1 # AWS リージョン
# Secret1 と Secret2 の値を取得して環境変数に設定
- name: Get secrets from AWS Secrets Manager
uses: aws-actions/aws-secretsmanager-get-secrets@v2
with:
secret-ids: |
SECRET1,${{ vars.SECRET1_ARN }}
SECRET2,${{ vars.SECRET2_ARN }}
parse-json-secrets: true # JSONを解析して個別の環境変数に設定
# 環境変数を使用するサンプルタスク(マスクされないように末尾1文字を削って出力)
- name: Use environment variables in a task
run: |
echo "${SECRET1_API_USER%?}"
echo "${SECRET1_API_KEY%?}"
echo "${SECRET1_CONFIG_ACTIVE%?}"
echo "${SECRET1_CONFIG_STANDBY%?}"
echo "${SECRET2_MYUSERNAME%?}"
echo "${SECRET2_MYPASSWORD%?}"
AWS 認証さえ行われていれば、シークレットの ARN を指定するだけで、aws-actions/aws-secretsmanager-get-secrets
アクションが Secrets Manager からシークレットの値を取得し、環境変数に設定してくれます。また環境変数名の形式は SECRET1_API_USER
のように、シークレット名とキー名をアンダースコアで連結した形式になります。
動作確認
ワークフローを実行すると、以下のように Secrets Manager シークレットの値が環境変数として設定されていることが確認できました。
Run echo "${SECRET1_API_USER%?}"
echo "${SECRET1_API_USER%?}"
echo "${SECRET1_API_KEY%?}"
echo "${SECRET1_CONFIG_ACTIVE%?}"
echo "${SECRET1_CONFIG_STANDBY%?}"
echo "${SECRET2_MYUSERNAME%?}"
echo "${SECRET2_MYPASSWORD%?}"
shell: /usr/bin/bash -e {0}
env:
AWS_DEFAULT_REGION: ap-northeast-1
AWS_REGION: ap-northeast-1
AWS_ACCESS_KEY_ID: ***
AWS_SECRET_ACCESS_KEY: ***
AWS_SESSION_TOKEN: ***
SECRET1_API_KEY: ***
SECRET1_API_USER: ***
SECRET1_CONFIG_ACTIVE: ***
SECRET1_CONFIG_STANDBY: ***
SECRET2_MYPASSWORD: ***
SECRET2_MYUSERNAME: ***
SECRETS_LIST_CLEAN_UP: ["SECRET1_API_KEY","SECRET1_API_USER","SECRET1_CONFIG_ACTIVE","SECRET1_CONFIG_STANDBY","SECRET2_MYPASSWORD","SECRET2_MYUSERNAME"]
user_hoge
key_fuga
user2_piyo
user3_nyan
alejandro_rosalez
EXAMPLE_PASSWORD
ハマった箇所
アクションのドキュメントによると、デバッグログの有効化で環境変数の値が出力されるようになるとのこと。先ほどは環境変数の値がマスクされないように末尾1文字を削る工夫をしていましたが、これを使えば値をそのまま出力できるのではないかと当初考えました。
To view the environment variables created from your secrets, turn on debug logging. For more information, see Enabling debug logging in the GitHub Docs.
デバッグログの有効化ドキュメントを参考に GitHub Environments にてデバッグログを有効化してみました。
変数名 | 値 |
---|---|
ACTIONS_RUNNER_DEBUG | true |
ACTIONS_STEP_DEBUG | true |
しかし、デバッグログにも、もちろん実際の出力にも環境変数の値が出てこずマスクされたままです...。
::add-mask::***
##[debug]Injecting secret SECRET1 as environment variable 'SECRET1_API_KEY'.
::add-mask::***
##[debug]Injecting secret SECRET1 as environment variable 'SECRET1_API_USER'.
::add-mask::***
##[debug]Injecting secret SECRET1 as environment variable 'SECRET1_CONFIG_ACTIVE'.
::add-mask::***
##[debug]Injecting secret SECRET1 as environment variable 'SECRET1_CONFIG_STANDBY'.
::add-mask::***
##[debug]Injecting secret SECRET2 as environment variable 'SECRET2_MYUSERNAME'.
::add-mask::***
##[debug]Injecting secret SECRET2 as environment variable 'SECRET2_MYPASSWORD'.
やり方が悪いのか仕様なのか今回は上手くいきませんでした。同様のデバッグを考えている方は注意するようにしましょう。
おわりに
AWS CDK で作成した Secrets Manager シークレットを GitHub Actions で aws-actions/aws-secretsmanager-get-secrets を使用して取得し、環境変数に設定する方法を紹介しました。
どなたかの参考になれば幸いです。
以上