他の人には読めない形式でGitHubのSecretsの値を読み出す

GitHubのSecretsに保存されている値をチームメンバーが誰もわからなくて、安全に読み出すために試行錯誤したときのメモ。
比較的容易かつ汎用的にしたつもりだが、もっと簡単でよいやり方があるかもしれない。

目的・想定場面

GitHubのSecretsの値を、誰も覚えていないので現在の値を読み出したい。
GitHub Actionsを使用すればSecretsを読み出すことは可能であるが、行儀よくやるには意外と難易度が高い。
その理由は以下。

  • GitHub ActionsではSecretsの値を出力しようとすると、マスクされる 1
  • Secretsの値はセンシティブな情報なので、できるだけ知られたくない
    • Read権限のみを持つ人には知られないようにしたいが、GitHub Actionsのワークフローファイルや実行ログはRead権限のみで読むことができてしまう

今回は、行儀よく(=堂々と言えるような、問題のない方法で)GitHubに格納されているSecretsを取得する。
なお、リポジトリへの書き込み権を持っている(=GitHub Actionsでワークフローを実行可能である)ことを前提としている。

方針

秘密鍵・公開鍵を使って読み出す。
より具体的には、以下を順番に実行する。

  1. ローカルで公開鍵および秘密鍵を準備(生成)
  2. GitHub Actionsのワークフローとして、公開鍵を使ってSecretsの値を暗号化・出力させる
  3. ローカルで秘密鍵を用いて、Secretsの値を復号

これを図示すると以下の通り。(図の記法は雰囲気)

overview

バイナリデータや改行文字を扱うのが煩わしいときは、都度BASE64エンコードを使用する。
ちなみに、GitHub Actionsにおいてopensslbase64は特にインストールせずに利用することが可能である。

実際にやってみた

1. 事前準備:公開鍵および秘密鍵を準備する

ローカルで以下を実行して生成する。(もし手元に利用可能なものがあるなら、それを使ってもOK)

openssl genrsa 2048 > private-key.pem
openssl rsa -in private-key.pem -pubout -out public-key.pem

2. 公開鍵でSecretsを暗号化・出力するワークフローを定義する

GitHub Actionsのワークフローにて、以下のシェルコマンド群を実行。ワークフロー全体はこちら

# 公開鍵をpublic_keyとして保存する(BASE64でエンコードされた公開鍵のテキストをデコードする)
echo 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzRmNrV1BqbEVaM1diQk80bGtEagpaaktqVDErejVJS1MxYkRteTc2ZnRYSWl4c1Y2NFFlWTdzUEttSmNjMXFMZFJDSitocEhlOXFLdEQ2NlZLK1htCkc5V25CdnJqT3R1OElpcjJkU1RKRlRiY2hoeFB3SThVMUgrdmRKOGZaUHUxb3d1V2Vibk5FUU4rdFkyTXcrMHoKV3dqa1NpVnJFZmZpSnZQVWYzU3U5SjlkZDgwUFp3cWFaaGREMWl3ak5pN0xxV1VqdjN2RlI0cVVseWdLVThqSgo1Mko2bzVyRldFd1ZpTmFMc0k4VVE3WVB4WkZ1NE5XQ3dJbnlpVmxWK0ZoSlExSW9ubFlJYkRQeWs0V01XMHJhCi9wQ0VmcDFrOHZaMVVkWkxxQi9YQm1iT0U0WktHdGdWUnByUzlYcGZ5L2dEY3NMYjBWbU9ka3JBbnpUU1RpeXkKdlFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==' | base64 -d > public_key

# 公開鍵が正しく渡せたことの確認するため、public_keyをログへ出力
cat public_key

# secretsをsecret_valueファイルに書き出す
echo "${{ secrets.FORGOTTEN_SECRET }}" >secret_value

# 公開鍵public_keyを使用してsecret_valueを暗号化し、encrypted_secret_valueとして保存する
openssl rsautl -encrypt -pubin -inkey public_key -in secret_value -out encrypted_secret_value

# GitHub Actionsのログに、BASE64でエンコードしたテキストを出力する
cat encrypted_secret_value | base64

3. 秘密鍵でSecretsの値を復号する

ワークフローの実行ログは以下。ハイライト部がencrypted_secret_valueをBASE64でエンコードして出力したもの。

log

出力されたテキストは改行文字が入っているため、以下のように取り除く必要がある。

XbfzhYaCzVaqGyIIYAw3aEVOrBeGI/REYvMHXgq+/l7Ydh0c36s2mF2HkwikBlMTDIlhnxwqM8mkAdoKanoAgZy5qc1XnGCdqSwMOcJYCPzXE3w6356ekO9PiAuKi3XD+NyH2npXILFM0w1GvIbcH91Ew/iS4KHb/DFbfDsTa2Y3t1Ibn6NTCqbUSSfrdDBEimbLQ8P1Qwwk1gouQr07BFoprZRX7mBHG8Ia3M08kEbQ+ehX6vxgoYjIqp3aIwP0SWEbaPOUekzv7kbhbrhyx/kjiP7UqQL1fzpDX40oBk+jSIU0c+i9qPXxFj+MZrTaJAtUyBbB8c/rZkl7dksPmw==

その後、ローカルで以下を実行するとSecretsの値を得ることができた。

# BASE64でデコードする
echo "XbfzhYaCzVaqGyIIYAw3aEVOrBeGI/REYvMHXgq+/l7Ydh0c36s2mF2HkwikBlMTDIlhnxwqM8mkAdoKanoAgZy5qc1XnGCdqSwMOcJYCPzXE3w6356ekO9PiAuKi3XD+NyH2npXILFM0w1GvIbcH91Ew/iS4KHb/DFbfDsTa2Y3t1Ibn6NTCqbUSSfrdDBEimbLQ8P1Qwwk1gouQr07BFoprZRX7mBHG8Ia3M08kEbQ+ehX6vxgoYjIqp3aIwP0SWEbaPOUekzv7kbhbrhyx/kjiP7UqQL1fzpDX40oBk+jSIU0c+i9qPXxFj+MZrTaJAtUyBbB8c/rZkl7dksPmw==" | base64 -d > encrypted_secret_value
# 秘密鍵private-key.pemを使用して複合し、encrypted_secret_valueの平文を出力する
openssl rsautl -decrypt -inkey private-key.pem -in encrypted_secret_value

補足:扱うSecretsデータサイズが大きい場合

Secretsのデータが大きい場合、先述のopensslコマンドではエラーとなることがある。
その場合はSMIMEを使えばよく、各処理を以下のコマンドで置き換えれば回避することができる。

# 公開鍵・秘密鍵の生成
openssl req -x509 -nodes -newkey rsa:2048 -keyout private_ssl_key.pem -out public_key.pem -subj '/'

# 暗号化
openssl smime -encrypt -aes256 -in secret_value -binary -outform DEM -out encrypted_secret_value public_key

# 復号
openssl smime -decrypt -in encrypted_secret_value -binary -inform DEM -inkey private_ssl_key.pem -out secret_value

参考: https://www.laddy.info/2014/02/27497/

所感

できるだけシンプルに…と思ったのだけど、意外と複雑になってしまった。
とはいえ、これでGitHubのSecretsがわからなくなっても、堂々と手早く取り出すことができるようになったので満足。

センシティブな情報の取り扱いは、永遠の課題だなぁ…。


  1. これだけであれば、artifactとして保存するなどの回避方法もある ↩︎

関連記事


  1. GitHub Actionsでプルリクのコメントに複数行テキストを投稿する
  2. GitHub Actionsでエラーの時だけ特定の処理を実行する
  3. 既存コードへのCheckstyle導入におけるルールの選定
  4. Checkstyleで汎用的に使えそうなルールをピックアップしてみた
  5. JaCoCoでJavaのテストカバレッジのレポートを出力する
  6. Tera Termのマクロで、パスワードを扱う操作を自動化する
  7. HugoテンプレートをOGPやTwitter Cardsに対応する

comments powered by Disqus