🔐

GitHub Actions で使うシークレットをセキュアに参照可能にして管理したい

2024/12/15に公開

はじめに

https://qiita.com/advent-calendar/2024/github-actions

GitHub Actions でパスワードなどを扱うときシークレットを使うかと思います。

https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=webui

このシークレットに保存している値をあとから見返すときはどうすればいいのだろうともやもやを抱えていました。
見返せるように Notion や Google スプレットシートを使って管理していましたがそれはそれでどうなのだろうと。。。
(もし参照する方法を知っている方がいらっしゃいましたら教えていただけると嬉しいです。)

そんなもやもやを抱えているなか「GitHub CI/CD実践ガイド」[2]を読んでいたところ GitHub CLI でシークレットの設定ができることを知りました。(これまでは Web UI でぽちぽち設定していました。)

https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=cli

GitHub CLI で登録できるなら仕組みを作ればなんかいい感じのことができそう!という感じでネタを思いついたので共有です。

TL;DR

ツール

本記事での仕組みを利用するためには以下のツールを利用します。
※ Mac 環境での動作です。

GitHub CLI

https://github.com/cli/cli

シークレットを CLI にて登録するために利用します。

SOPS

https://github.com/getsops/sops

暗号化・復号のために利用します。

age

https://github.com/FiloSottile/age

暗号化・復号のための鍵を生成するのに利用します。

aqua

https://aquaproj.github.io/

SOPS および age を管理するために利用します。
※ なくても大丈夫です。

鍵生成

age を使って暗号化・復号の鍵を生成します。

age-keygen

コマンドを実行すると以下の結果が得られます。

# created: 2024-12-15T13:39:59+09:00
# public key: age15ejyvpj84w5f42t0v6wnlz86qtnyyrxqx0k9ghtlqr5tfs23tcnsjupyay
AGE-SECRET-KEY-1WPUDMFQNYQ572CMUVMQSEH6U83VXE99FGAXJF7E8HPK64ZCRLRVQHJS0RH

public key: である age15ejyvpj84w5f42t0v6wnlz86qtnyyrxqx0k9ghtlqr5tfs23tcnsjupyay は暗号化するために使う鍵です。
これは公開しても問題ない情報です。
AGE-SECRET-KEY-1WPUDMFQNYQ572CMUVMQSEH6U83VXE99FGAXJF7E8HPK64ZCRLRVQHJS0RH は復号に使う鍵です。
これは公開してしまうとダメな情報です。
安全な場所で管理してください。
※ 今回はサンプルなので載せています。& サンプルコードとしてコミットもしています。

参照のためのファイル

シークレット値を後から見返すために init.sh スクリプトを用意します。
secret ディレクトリにて管理する想定です。

#!/bin/bash -ue

name=$1

if [[ -z "${name}" ]]; then echo "please specify secret name"; exit 1; fi

touch secret/${name}.in.txt

touch secret/${name}.out.txt

シークレットの名前を指定して空のテキストファイルを生成するだけです。

init.sh <name>

.in.txt.out.txt はコミットしない想定です。
このファイルをシークレット値の参照に使います。
.in.txt.out.txt を用意しているのはプレーンテキストを一方向で管理したかったからです。
.in.txt に暗号化したい値を入力します。

ex)

sample

暗号化

age にて生成した鍵と SOPS を使って暗号化するために encrypt.sh スクリプトを用意します。

#!/bin/bash -ue

key=age15ejyvpj84w5f42t0v6wnlz86qtnyyrxqx0k9ghtlqr5tfs23tcnsjupyay

name=$1

if [[ ! -e secret/${name}.in.txt ]]; then echo "secret/${name}.in.txt not exists"; exit 1; fi

sops encrypt \
	 --age ${key} \
	 secret/${name}.in.txt > secret/${name}.json.tmp

cat secret/${name}.json.tmp | jq . > secret/${name}.enc.json

rm secret/${name}.json.tmp

以下のコマンドにて先ほど設定したシークレット名を指定して実行します。

encrypt.sh <name>

すると暗号化された json 形式のファイルが出力されます。

{
  "data": "ENC[AES256_GCM,data:ftJ9oOA6,iv:hb1dXrT7wIhGggoqV8DMcNxm3GVd9USkr9fXysxh6Jk=,tag:Xcqk3Q9w2uPFXd3aO4LEaw==,type:str]",
  "sops": {
    "kms": null,
    "gcp_kms": null,
    "azure_kv": null,
    "hc_vault": null,
    "age": [
      {
        "recipient": "age1tvx0ufxk5vkucmlyzha3xvkw4u29nl8x5u7m43qqv75num7tda2qzzxtt4",
        "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXcDdTN1FrTnN5TWY5aHJD\nRHdjLzNpcE90N01TZ05lSGRzbEVkOGVWTURVCnVaRGExYy9DcXM4VEFRbTl4cE95\ndkJRZzZhaWtDcGJ4VUlvWVBZVkEySVkKLS0tIHlBL3NyMlp0VkZ1L0JCTGlPVFEx\nN1Brd3RMb1hWVHZleFgxZTNpbXlTRnMKuJ8OyS0cHQBfZW7oxt4Rqlg5CZGfSDeB\nwAd0FN78xsh59930yPjK38QmoeZKCsX1PY+7GqthslttKwhLTt/8dA==\n-----END AGE ENCRYPTED FILE-----\n"
      }
    ],
    "lastmodified": "2024-12-14T16:50:05Z",
    "mac": "ENC[AES256_GCM,data:mlwor2jWjwilUWAI6MjIiAWaVX4IaoUS2pwiCIyVh3jTooW2GsuAS/+cjsjGg7dgl0yW7udqKndVVuyj/FdSmf6P4MMFUl2d07JRic276Jr6PDTUJ304ENXVT/9+vi1sml0EtJmX1uWYnVP6YtHWLekhmTwpNzZzgmctr5Hxm6I=,iv:ZRKXBeJFdCrI/t4Bn15J2NX3KSkpXCHqrLaXel8i8m0=,tag:ugtjAE42UdUJj65cqX2ahA==,type:str]",
    "pgp": null,
    "unencrypted_suffix": "_unencrypted",
    "version": "3.9.2"
  }
}

※ json ファイルはコミットして問題ないです。

復号

age にて生成した鍵と SOPS を使って復号するために decrypt.sh スクリプトを用意します。

#!/bin/bash -ue

name=$1

source ./.env

export SOPS_AGE_KEY="${SOPS_AGE_KEY}"

if [[ ! -e secret/${name}.enc.json ]]; then echo "secret/${name}.enc.json not exists"; exit 1; fi

sops decrypt secret/${name}.enc.json > secret/${name}.tmp.json

touch secret/${name}.in.txt

cat secret/${name}.tmp.json | jq .data | tr -d '"' > secret/${name}.out.txt

rm secret/${name}.tmp.json

復号で使う鍵は .env で管理します。
このファイルはコミットしないでください。

SOPS_AGE_KEY="AGE-SECRET-KEY-1WPUDMFQNYQ572CMUVMQSEH6U83VXE99FGAXJF7E8HPK64ZCRLRVQHJS0RH"

以下のコマンドにて先ほど設定したシークレット名を指定して実行します。

decrypt.sh <name>

すると復号されて .out.txt に値が記載されます。

ex)

sample

シークレットセット

GitHub CLI と SOPS を組み合わせて GitHub にシークレット値を登録する set.sh スクリプトを用意します。

#!/bin/bash -ue

name=$1

source ./.env

export SOPS_AGE_KEY="${SOPS_AGE_KEY}"

if [[ ! -e secret/${name}.enc.json ]]; then echo "secret/${name}.enc.json not exists"; exit 1; fi

sops decrypt secret/${name}.enc.json > secret/${name}.tmp.json

touch secret/${name}.in.txt

cat secret/${name}.tmp.json | jq .data | tr -d '"' > secret/${name}.out.txt

rm secret/${name}.tmp.json

NAME=$(echo ${name} | awk '{print toupper($0)}')

gh secret set ${NAME} --body "$(cat secret/${name}.out.txt)"

以下のコマンドにて先ほど設定したシークレット名を指定して実行します。

set.sh <name>

これにてリポジトリにシークレットが登録されます。

動作確認

本当にシークレットが登録されているか実際に GitHub Actions で参照して確認します。
以下のようなワークフローを定義し値を確認します。
※ シークレットを可視化するための実装です。シークレットがログに出力されるので推奨されません。

name: secret
run-name: ${{ github.ref_name }} by @${{ github.actor }} at ${{ github.workflow }}
on:
  workflow_dispatch:
defaults:
  run:
    shell: bash
jobs:
  echo:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    env:
      PASSWORD: ${{ secrets.PASSWORD }}
    steps:
      - name: echo
        run: echo "${PASSWORD:0:1} ${PASSWORD#?}"

ワークフローを起動すると以下のような出力が得られます。

Run echo "${PASSWORD:0:1} ${PASSWORD#?}"
  echo "${PASSWORD:0:1} ${PASSWORD#?}"
  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
  env:
    PASSWORD: ***

s ample

指定した通りシークレットの1文字目と2文字目の間にスペースが含まれ値が参照できました。

おわりに

こんな感じでリポジトリ内でシークレットを参照する方法を考案してみました。

いやいや、SOPS_AGE_KEY はどうやってセキュアに管理するの???
はい、サボりました。
理想としては AWS Key Management ServiceCloud Key Management を使って鍵は管理したいです。
SOPS_AGE_KEY の代わりに利用すればもうちょっとセキュアに管理できるはずです。
が、環境構築がめんどくさかったので悪しからず...

今回実装したコードは以下に置いておきます。バージョン情報などは以下のリポジトリをご確認ください。

https://github.com/otakakot/sample-github-actions-secrets

脚注
  1. 空いていたので後追いで執筆しました。 ↩︎

  2. GitHub CI/CD実践ガイド――持続可能なソフトウェア開発を支えるGitHub Actionsの設計と運用 ↩︎

Discussion