😘

Terraformによる秘密情報管理をどうするか@個人開発

2024/12/21に公開

秘密情報の管理って、難しいですよね。なんたって秘密なんですから。
管理してる時点で秘密漏れてるんちゃうか? みたいになりますよね。

というわけで、今回は個人開発において秘密情報をどう管理するか悩んだので調べ・考えたことをまとめたいと思います。

前提

  • terraformを利用する
  • AWSを利用する
  • パソコンは複数所持している
  • stateにも情報を残したくない
  • ソース上にはもちろん情報を残したくない

結論

先に今回たどり着いた結論を記載しようと思います。

1. 構築: terraformでのresource管理を行わない
2. 参照: データ参照にephemeralを利用する

terraformによる管理とかいってるのに、管理しないのかよ、っていうオチですみませんなんですけどね...
では、それぞれ以下に理由などを記載したいと思います。

terraformでのresource管理を行わない 理由

他にも色々と理由があるのですが、端的に言うと以下が理由です。

stateファイルから秘密情報をなくすことが出来なかったから

これだけだと味気ないので、そこに至るまでに何を考えたりしたいのかも書いていこうと思います。

秘密情報を環境変数に定義して、tfファイル内から秘密情報をなくす

terraform初心者が故の発想でしたね。

tfファイル内から秘密情報をなくしたとしても、結局stateファイルには環境変数から取り込んで実行した値がそのまま残ってしまいます。
なので、この方法では秘密情報を隠すことが出来ませんでした。

またこの方法だとterraformを実行する人は全員秘密情報を配布しなければterraformの実行ができなくなります。
秘密情報を隠したいのに、配布しないといけないとはこれ如何に...
これでは本末転倒ですね。

仮に採用するとしても、環境変数展開用のシェルスクリプトとか書いたり、それ用のroleを作ったりしないといけないので面倒くさいです。(手でちまちまやってらんないですからね)

対象の値にsensitive属性を付与する

これはoutputsから隠してくれるだけでstateファイルには普通に出力されるので駄目でした。

初期値をdummyにしてvalueはresource定義後にコンソールから変更する

次に考えたのは以下の方法。
これにより秘密情報のValueをterraformの管理対象から排除できるのではないかと考えたのですね。

resource "aws_ssm_parameter" "hoge" {
    value = "dummy"
	...
	lifecycle {
	    ignore_changes = [value]
	}
}

しかしこの方法ではstateから秘密情報を排除できませんでした。
管理コンソールから変更した直後は問題ありませんが、その後applyするとAWS上の実データの値でstateファイルのValueが更新されてしまいます。

ignore_changesは、その名前の通り「変更検知の対象から外す」だけで対象をstateの管理対象から外すわけではないんですね。
stateはどうやらAWS上に構築されているリソースの状態を正として状態を管理してくらしく、コンソールから変更したものも反映していくようです。

そうですよね。じゃないと状態の管理できませんもんね。

というわけで、この方法は諦めました。
いやぁ、この方法で行けると思ったのでとても残念でした...

ただこの方法はソースコード上から秘密情報を排除できるという点は優秀なので、その用途で利用する機会は結構あるんじゃないかと思いました。

データ参照にephemeralを利用する 理由

これに関しては理由もクソもないんですが、terraformのv1.10から追加されたこの機能が秘密情報を隠してくれるからです。
これを使って参照したものはstateファイルやterraform実行後のoutputsの出力から隠蔽してくれます。

そのためresource定義時に秘密情報を直接埋め込まないといけないものがあったときに、セキュアに値を埋め込むことが出来るようになりました。
例えばLambdaの環境変数とか埋めるときに便利ですね。

参照系はもうこれで解決です!

その他

その他に考えていたことをオマケ的に記載していきます。

そもそもstateから秘密情報を排除したいのか

正直これが一番悩ましいところです。
stateに秘密情報が残っていると嫌なのは、例えば以下のパターンがあります

  1. なにかの理由でstateが流出する
  2. stateを閲覧可能な人から情報が流出する

まず1なのですが、例えばbackendがprivateなs3だったとします。
privateなs3の情報が流出するとかありえるのか? という話です。

正直ほぼないでしょう、というのが個人的な感想です。

これが流出するケースは多分、このバケットをAPI経由で参照しているサービス側に脆弱性があるパターンとかですよねぇ。
ただterraformのstateを管理するバケットはその用途だけに使うと思うので、他のファイルも配置されてて同じAPIで参照先に指定したりしないと思うんですよね。

だから、怖いといえば怖いけど、本当に気にするほどか?? と思います。

2のパターンですが、これはちょっと怖いですね。
特にインフラ構築が専任チームの仕事ではなく、ほとんどのエンジニアがtfファイルを触っているような環境だと実質誰でも見れるみたいな状態になってしまいます。

なので、そこはチームや会社ごとにトータルのバランスを見て考えないといけなそうです。

秘密情報がtf管理外にあるデメリット

これは少人数・システム規模や数が小さい場合には、多分ほぼないです。
結局Secrets ManagerやParameter Storeがマスタ情報になり一元管理されるので、そこを見ればいいだけですから。

ただ人が増えたり、システムが大きく数が増えてくるとコンソールから探すのも一苦労になっていくるはずなので、共通のコードで管理したい欲求が生まれると思います。

そしてここで管理したい対象は実はValueではなくて、nameの方なんじゃないかなぁとは思います。
あとソース管理システムでdiffが取れて、チームで相互レビューが出来ることか。

なので、規模が大きくなるとtf管理されていないことのデメリットが大きくなっていきそうかなと思いました。

全員がstateを見れる状況だと、正直ソースコードに秘密情報をベタ書きにしてるのと変わらないですよね
privateなgithubに全部書かれてるのと、privateなbackendにすべて書かれてるので同じですからねぇ

仕事だったら自分はどうするか

すごく悩むんですが、おそらく以下の様にするだろうなぁと思いました。

  1. tf管理にはせずにコンソールから直接管理
  2. しんどくなってきたら、stateに秘密情報が残ることを許容してtf管理へ移行

あんまり意味ないけど一応暗号化bucketにしつつ、stateへの出力は許容すると思います。
でないと環境変数周りのオペレーションエラーが発生してシステムに障害が発生するようになりそうなので。

read系は今はephemeralがあるので、それ使えばOKですね。
最高です。これがないときはどうしてたんでしょうかね?

まぁ多分同仕様もないのでstateについては諦めてたんだと思いますけど...

まとめ

AWSやterraformを真面目に触りだして数日ですが、ホントにわからないことだらけですね。
そして難しいし、銀の弾丸がないので「さじ加減」を求められるのがとてもしんどいです。

まだまだ環境構築が終わらないので引き続き頑張りたいです。

Discussion