他の人には読めない形式でGitHubのSecretsの値を読み出す
GitHubのSecretsに保存されている値をチームメンバーが誰もわからなくて、安全に読み出すために試行錯誤したときのメモ。
比較的容易かつ汎用的にしたつもりだが、もっと簡単でよいやり方があるかもしれない。
目的・想定場面
GitHubのSecretsの値を、誰も覚えていないので現在の値を読み出したい。
GitHub Actionsを使用すればSecretsを読み出すことは可能であるが、行儀よくやるには意外と難易度が高い。
その理由は以下。
- GitHub ActionsではSecretsの値を出力しようとすると、マスクされる 1
- Secretsの値はセンシティブな情報なので、できるだけ知られたくない
- Read権限のみを持つ人には知られないようにしたいが、GitHub Actionsのワークフローファイルや実行ログはRead権限のみで読むことができてしまう
今回は、行儀よく(=堂々と言えるような、問題のない方法で)GitHubに格納されているSecretsを取得する。
なお、リポジトリへの書き込み権を持っている(=GitHub Actionsでワークフローを実行可能である)ことを前提としている。
方針
秘密鍵・公開鍵を使って読み出す。
より具体的には、以下を順番に実行する。
- ローカルで公開鍵および秘密鍵を準備(生成)
- GitHub Actionsのワークフローとして、公開鍵を使ってSecretsの値を暗号化・出力させる
- ローカルで秘密鍵を用いて、Secretsの値を復号
これを図示すると以下の通り。(図の記法は雰囲気)
バイナリデータや改行文字を扱うのが煩わしいときは、都度BASE64エンコードを使用する。
ちなみに、GitHub Actionsにおいてopenssl
やbase64
は特にインストールせずに利用することが可能である。
実際にやってみた
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でエンコードして出力したもの。
出力されたテキストは改行文字が入っているため、以下のように取り除く必要がある。
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がわからなくなっても、堂々と手早く取り出すことができるようになったので満足。
センシティブな情報の取り扱いは、永遠の課題だなぁ…。
-
これだけであれば、artifactとして保存するなどの回避方法もある ↩︎