本記事は LIFULL Advent Calendar 2023 の17日目の記事です。 qiita.com
事業基盤のチームのマネジメントを担当している磯野です。
自他共に認めるGitHubおじさんとして社内では活動しています。
私たちのチームは開発生産性をより高めるため、開発エコシステムの改善に取り組んでおり、特にGitHubを中心とした生産性向上に注力しています。
今回はその取り組みの一環として、GitHub Actions においてマシンユーザーやAppsを減らしつつ、セキュリティと利便性を向上させるための施策について紹介します。
GitHub Actionsでの課題
GitHub Actionsを用いた処理の実行に際し、いくつかの課題に直面しました。
課題としては以下のような点があります:
- 標準で使用可能なGITHUB_TOKENではworkflowのトリガーが不可能で、また
.github/workflowsディレクトリの更新もできない - マシンユーザーやGitHub Appsの管理にコストがかかる
- マシンユーザーやGitHub Appsを利用するには、リポジトリごとにシークレットを設定し、すべての利用箇所に対して必要な権限を付与する必要があり、セキュリティ上のリスクが存在する
これらの課題への解決策として、GitHub Actionsでの認証情報の設定を単純化する処理を開発しました。
これにより、ワークフローに必要な権限のみを付与することでセキュリティの向上が期待できます。
課題解決後の利用シナリオ
GitHub Actionsでの認証情報の設定を単純化することで、次のようなことが可能になりました:
- GitHub ActionsからのpushまたはPR作成時において、Actionsをトリガーすることが可能
.github/workflows/ディレクトリ内のファイル更新が可能- 標準のGITHUB_TOKENではできない処理も簡易に実行可能
また、リポジトリ側でシークレット情報を管理する必要がない ため、シークレットを各リポジトリへ配布する必要がなく、運用上のメリットもあります。
弊社ではマイクロサービス化が進むにつれてRepositoryが増加し、それぞれに対しマシンユーザーを個別に追加することで運用コストが肥大化しており、大きな運用コスト削減につながっています。
課題を解決するための仕組み
GitHub Actionsでの認証情報を単純化するため、以下のような仕組みを開発しました。実線はActions内の処理の流れを、点線は各処理からのAPI呼び出しを表しています。
graph TB
subgraph GitHub Actions
direction TB
START((開始))
ACTION1("aws-actions/configure-aws-credentials<br>次のLambda呼び出し用")
ACTION2("configure-github-credentials<br>(今回作成したもの)")
ACTION3("実処理")
END((終了))
end
subgraph GitHub API
direction TB
API1("POST /app/installations/{installation_id}/access_tokens")
API2("その他のAPI")
end
subgraph AWS
direction TB
STS["AWS STS<br>後続のLambdaを呼び出すトークンを取得"]
LAMBDA["AWS Lambda<br>(IDトークンの検証と<br>GitHubトークンの取得)"]
end
START --> ACTION1
ACTION1 --> ACTION2
ACTION2 --> ACTION3
ACTION3 --> END
ACTION1 -."①後続のLambdaを呼び出す権限のある<br>AWSクレデンシャルの取得".-> STS
ACTION2 -."②後続のActionで利用するための<br>GitHubのTokenの取得".-> LAMBDA
LAMBDA -."③指定権限のトークン取得".-> API1
ACTION3 -..-> API2
Composite Actionとしての実装は以下のようになっています。
name: Create specified scoped token workflow
descroption: |
Create specified scoped token workflow
inputs:
role:
required: true
type: string
outputs:
token:
description: "GitHub App token"
value: ${{ steps.create-app-token.outputs.token }}
runs:
using: "composite"
steps:
- name: set env
shell: bash
run: |
echo "LAMBDA_NAME="<<<lambda function name>>" >> $GITHUB_ENV
echo "IAM_ROME_ARN="<<<iam role arn>>>" >> $GITHUB_ENV
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: "${{ env.IAM_ROME_ARN }}"
aws-region: "<<<region>>>"
- id: create-app-token
name: create app token
shell: bash
run: |
export AWS_DEFAULT_REGION="<<<region>>>"
ID_TOKEN="$(curl --silent -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=configure-github-credentials" | jq -r '.value')"
aws lambda invoke --cli-binary-format raw-in-base64-out --function-name "${{ env.LAMBDA_NAME }}" --payload "{
\"id_token\": \"${ID_TOKEN}\",
\"role\": \"${{ inputs.role }}\"
}" outputfile.txt || :
TOKEN=$(cat outputfile.txt | jq -re ".token // empty" || echo "")
if [ -z "${TOKEN}" ]; then
echo "Token is missing in the JSON file"
cat outputfile.txt | jq -re ".errorMessage // empty"
exit 1
fi
echo "::add-mask::$TOKEN"
echo "GITHUB_TOKEN=$TOKEN" >> $GITHUB_ENV
echo "token=$TOKEN" >> $GITHUB_OUTPUT
各処理の詳細
① 後続のLambdaを呼び出すためのAWSクレデンシャルの取得
aws-actions/configure-aws-credentials を用いて、後続のLambdaを呼び出すためのIAMロールのクレデンシャルを取得します。 事前にGitHubをIDプロバイダとして登録し、GitHub経由でAssumeRoleを実行できるよう設定しておく必要があります。
②GitHubのTokenの取得
IDトークンを用いた呼び出し元の検証を行い、Lambda上で適切な権限を付与します。
IDトークンの正式な検証を行うことで、トークン内に含まれるリポジトリ名やブランチ名、実行者などの情報が利用でき、指定の権限を付与すべき対象かどうかを判断します。
IDトークンから得られる情報についてはこちらを参照してください。
graph TB
subgraph configure-github-credentials
direction LR
CGC1("IDトークンの取得")
CGC2("Lambdaの呼び出し")
CGC3("トークンの環境変数への設定")
CGC4("トークンをシークレットとして設定")
end
subgraph Lambda
direction LR
LAMBDA1("IDトークンの検証")
LAMBDA2("指定の権限が利用可能か検証")
LAMBDA3("GitHubトークンの取得")
LAMBDA4("GitHubトークンの返却")
end
CGC1 --> CGC2
CGC2 --"IDトークン, 必要な権限"--> LAMBDA1
LAMBDA4 --"GitHubトークン、有効期限"--> CGC3
CGC3 --> CGC4
LAMBDA1 --> LAMBDA2
LAMBDA2 --> LAMBDA3
LAMBDA3 --> LAMBDA4
③ 指定権限のトークン取得
②で述べたLambdaから呼び出されるAPIです。 GitHub AppsのInstallation access tokenを生成します。このAPIを呼び出す際はApps側にその権限が必要です。
今後の展望と課題
この仕組みは現在一部のプライベートリポジトリで利用を開始していますが、将来的にはさらに拡張し、最終的にはオープンソースとして公開したいと考えています。
まとめ
GitHubのOIDCとAWS Lambdaを活用し、GitHub AppsのInstallation access tokenを安全に取得できるようになりました。これにより、GitHub Actionsでの認証情報のセットアップを単純化し、よりセキュアな実行が可能です。
LIFULLでは開発生産性向上のための開発エコシステムの改善に積極的に行っています。今回の仕組みはその一環であり、AIを活用して全社的な生産性向上を目指すkeelaiや、Kubernetesを用いたアプリケーション実行基盤であるKEELなど、多くの取り組みを進めています。
LIFULLでは一緒に働いてくれる仲間を募集しています。これらの取り組みに興味を持った方がいらっしゃいましたら以下からぜひお問い合わせください。