APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【Blog Week】開発環境の機密情報をgpgで暗号化したら、secureかつ楽になりました!

開発環境では機密情報を平文で書いてませんか?

どうも、iTOC事業部MBS部の小野志峰です。

早速ですが、みなさんは開発環境では機密情報を平文で書いてませんか? すみません、私は去年くらいまで平文で書くこともありました。
当然、その現場のポリシーを満たす運用ではあるのですが、それにしても改善したいとは思ってたのです。
そこで、gpgを使って1回のpassword入力だけで、環境変数に展開する方法を導入しました!
開発環境はlinuxです。

悩み

私は業務でansibleを多用しています。
ansibleにはansible-vaultという機能があり、機器のlogin情報などを暗号化することができます。
復号したいときはpasswordを入力すればいいのですが、try & errorを繰り返す検証の過程では、都度入力するのが中々面倒でして。

passwordをファイルに書いておいてそれを都度読ませることも可能ですが、それでは平文保存になってしまいます。
scriptを経由して、環境変数を取ってくることも可能ですが、loginするたびに環境変数にexportするのも手間だし、
.bash_profileとかvenvのactivateファイルに直接書くと結局それも平文保存になってしまうという。 現場のポリシーではOKとされていても、個人的にはなんとなく落ち着かないんですよね。

みなさまも機密情報の取り扱いで同じような悩みを抱えたことはありませんか?

私の解決策はgpgでした

この悩みを解決する方法はつまり以下を満たせばよいわけです。

  • passwordで暗号化/復号できる
  • 開発環境にloginしているときだけ環境変数に機密情報が展開される
    • 暗号化されたファイルが開きっぱなしにならない

それがgpgと.bash_profileのようなlogin時に動くscriptとを組み合わせて実現できました!

手順

環境はrocky9.1とUbuntu 22.04.2の両方で検証しました。

以下の流れで実装していきます。

  1. 必要なpackageのinstall
  2. 暗号化するファイルの用意
  3. ファイルの暗号化
  4. 暗号化したファイルの検証および復号
  5. login scriptへの組み込み
  6. 正常系テスト
  7. 異常系テスト

必要なpackageのinstall

Rhel系

sudo dnf install -y gnupg pinentry

ubuntu

sudo apt install -y gnupg pinentry-tty

暗号化するファイルの用意

今回は2つのpasswordを暗号化してみます。
そして、いちいちpasswordを覚える必要もなくなるので、折角だから無意味なhashにしてしまいます。

# readコマンドを使って、historyに残さずhashの元を作る
$ read pass

# shasumでhash化
$ echo -n $pass | shasum -a 256
46192db316984c6ed59507d7f2d826933f85ddadaa6738501fd5ae24e9884621

こんな調子で、2つのpasswordを用意しました。

ここでechoコマンドを使ってファイルを用意しては、historyに残ってしまうので、
viなりでファイルを開いて編集してください。

ANSIBLE_VAULT_PASS="46192db316984c6ed59507d7f2d826933f85ddadaa6738501fd5ae24e9884621"
AWX_PASSWORD="f3ddbfd17502483cb22823de35ecf80f0bb70ab0efdda083c84e67e2a242bea9"

これを、.vaultというファイル名で保存しました。

ファイルの暗号化

さて、作成したファイルを暗号化します。

$ gpg --cipher-algo AES256 --compress-algo none --symmetric --no-symkey-cache .vault

# password入力に遷移。2回入力します。

┌─────────────────────────────────────────────────────┐
│ Enter passphrase                                    │
│                                                     │
│                                                     │
│ Passphrase: _______________________________________ │
│                                                     │
│       <OK>                             <Cancel>     │
└─────────────────────────────────────────────────────┘

そうすると.vault.gpgというファイルが生成されました。

optionも説明します

  • --cipher-algo AES256: 暗号化アルゴリズムをAES256に設定(2023/10/20段階でgpgで使えるアルゴリズムの中では最強だそうで)
  • --compress-algo none: 無圧縮とする(今回は復号速度を全く重視しないので、無圧縮の方が強くて良い)。
  • --symmetric: passwordで暗号化するだけの共通鍵の作成。
  • --no-symkey-cache 入力されたpasswordをcacheしない。

暗号化したファイルの検証および復号

では暗号化前と暗号化後でファイルを比較してみます。

暗号化前ファイル

$ od -An -c .venv/.vault

# 以下出力
   A   N   S   I   B   L   E   _   V   A   U   L   T   _   P   A
   S   S   =   "   4   6   1   9   2   d   b   3   1   6   9   8
   4   c   6   e   d   5   9   5   0   7   d   7   f   2   d   8
   2   6   9   3   3   f   8   5   d   d   a   d   a   a   6   7
   3   8   5   0   1   f   d   5   a   e   2   4   e   9   8   8
   4   6   2   1   "  \n   A   W   X   _   P   A   S   S   W   O
   R   D   =   "   f   3   d   d   b   f   d   1   7   5   0   2
   4   8   3   c   b   2   2   8   2   3   d   e   3   5   e   c
   f   8   0   f   0   b   b   7   0   a   b   0   e   f   d   d
   a   0   8   3   c   8   4   e   6   7   e   2   a   2   4   2
   b   e   a   9   "  \n

暗号化したファイル

$ od -An -c .venv/.vault.gpg

# 以下出力
 214  \r 004  \t 003 002   :   7 311 351 363 232   n   / 377 322
 300 035 001 332 034 001 346   Z   |   2 205 211   "   F 224 213
 325 336 263   - 212 316 236 203 021 316 200   M 202   9 260 271
 205 372 305 327   t   ( 261   4 305   7 360 263   j   V   d  \a
 005 266 220 377   U   d 025  \f   = 036   = 273   v 322 260 242
 225 002 325   2 314 031 200 302 263 252 006   q   0 307 240 267
   S   @ 235 310 001   P 311   [   e 024   ( 347 242   F   T 024
 356   4 034  \f 352 310   l 366 311   2 241   W   0   J   r 230
 264 212   o 036 331 256   ;   D   H 333   x 230 276 317 207   D
 303 017 024   i   ^  \r 333 252 024 337   - 021 373 305   W 202
   & 270   ? 025   #   > 320 273   M 247 246   _   }   h 367   q
 277 032 375 263   7   K   V   ` 220 035 303   o   ; 201   ^   i
 025   Y   E 330 276   d   e 341   3   ' 035 327 222 322 373   7
   P 310 233 304 340   " 032   x 343 323 315 232 244 232 226   ^
   / 036 262   H 336 303 325   e   8   ] 216 354   w 021   R

暗号化されてますね!

では、復号してみます。

$ gpg --decrypt --no-symkey-cache .vault.gpg 

# password入力を求められます。
 ┌──────────────────────────────────────────────────────┐
 │ Enter passphrase                                     │
 │                                                      │
 │                                                      │
 │ Passphrase: ________________________________________ │
 │                                                      │
 │       <OK>                              <Cancel>     │
 └──────────────────────────────────────────────────────┘

# passwordの入力後、以下のように出力されます。
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
ANSIBLE_VAULT_PASS="46192db316984c6ed59507d7f2d826933f85ddadaa6738501fd5ae24e9884621"
AWX_PASSWORD="f3ddbfd17502483cb22823de35ecf80f0bb70ab0efdda083c84e67e2a242bea9"

これは、暗号化したファイルの復号結果を出力しているだけで、暗号化されたファイルはそのままです。

login scriptへの組み込み

私はvenvを起動した時に環境変数に展開されたいので、作成したgpgファイルの内容をexportするコマンドを .venv/bin/activate に追記します。
もちろん、.bash_profileでも使える仕組みです。

.vault.gpg.venvに移動させます。
また、暗号化前の.vaultは用済みなので、削除してしまいます。
※機密情報を追加したいときは新たにファイルを作って、復号した機密情報達と新規の機密情報を記載して、再び暗号化すればよいのです。

$ mv .vault.gpg some_project/.venv

$ rm .vault

そして、.venv/bin/activateを編集して以下のコード1行を適当な場所に配置します。
「適当な場所ってどこよ」と言われそうですが、私はexport PS1のblockが終わったあたりに書いてます。

# Export credential vars from gpg file
export $(gpg --decrypt --no-symkey-cache $VIRTUAL_ENV/.vault.gpg 2> /dev/null | xargs -0) &> /dev/null

正常系テスト

いよいよ、venvを呼び出してみます。
既にvenvを起動していたら、一度exitで抜け出てから実行します。

$ poetry shell

# password入力を求められます。
 ┌──────────────────────────────────────────────────────┐
 │ Enter passphrase                                     │
 │                                                      │
 │                                                      │
 │ Passphrase: ________________________________________ │
 │                                                      │
 │       <OK>                              <Cancel>     │
 └──────────────────────────────────────────────────────┘

# venvに入ったらprintenvしてみます。
(.venv)$ printenv | grep ANSIBLE

# 出力結果
ANSIBLE_VAULT_PASS="46192db316984c6ed59507d7f2d826933f85ddadaa6738501fd5ae24e9884621"

(.venv)$ printenv | grep AWX

# 出力結果
AWX_PASSWORD="f3ddbfd17502483cb22823de35ecf80f0bb70ab0efdda083c84e67e2a242bea9"

ちゃんとexportされてますね。

では、venvから抜けてprintenvして、環境外でexportされてないか確認してみます。

# venvから抜ける
(.venv)$ exit

$ printenv | grep ANSIBLE

$ printenv | grep AWX

# 出力結果は共になし

よし!

異常系テスト

では、仮想環境に入るときに、passwordを間違えてみます。

$ poetry bash

# passwordを間違えてみます
 ┌──────────────────────────────────────────────────────┐
 │ Enter passphrase                                     │
 │                                                      │
 │                                                      │
 │ Passphrase: ________________________________________ │
 │                                                      │
 │       <OK>                              <Cancel>     │
 └──────────────────────────────────────────────────────┘

# venvに入ったらprintenvしてみます。
(.venv)$ printenv | grep ANSIBLE

(.venv)$ printenv | grep AWX

# 出力結果は共になし

ばっちりですね。

活用例

ansible-vaultへの自動password投入

さて、私が元々やりたかったのは、ansible-vaultに自動でpasswordを渡すことです。
まず、passwordを環境変数からechoするscriptを作成します。

echo $ANSIBLE_VAULT_PASS

vault_pass.shとして保存しました。 そして、これをansible.cfgに登録してやります。

[defaults]
vault_password_file=./vault_pass.sh

これで、毎度passwordを入力しなくてもansible-vaultで暗号化された機器login情報などを復号できるようになりました!

そのほか私の事例

サーバ上で暗号化して登録するような機密情報を、開発環境でも使いたいというパターンは、全部この方法で解決できると思ってます。

私は、gitlab runnerのpipelineでAWXのworkflow templateをAPIから叩いてtestしているので、tokenを生成するためにAWXのlogin passwordを登録しています。
(ご安心ください、tokenは毎回revokeしてます!)
開発環境からも叩きたいので、同じ変数名でexportしてます。

あとは、AWXに登録しているNETBOXのtokenとか、そういうのもですね。

こんなこともできます

メンバーが同じようにusernameとpasswordを登録していれば、 手順書にこんな書き方してても、そのままコピペで使えちゃいます。

# curlのbasic認証してみたり
$ curl --basic -u $username:$password https://api.example.com/

# ftpだったり
$ ftp://$username:$password@ftpserver/.

手順書を途中までコピペして、手打ちでuser名とpasswordを入力して、またコピペして...って、インフラエンジニアならきっとやったことありますよね。
あの苦しみから解放されるのです!

おわりに

APCのTech Blogでは珍しい小手先テクの紹介でしたが、たまには「今日から使える!」みたいなのも良いのではないでしょうか。

さて、私たちiTOC事業部は、ネットワーク技術を軸に自動化やセキュリティなど、お客様の課題解決をご支援しております。
お気軽にご相談下さい!

www.ap-com.co.jp

また、一緒に働く仲間も募集中です! まだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp