技術1課の水本です。
アプリケーション開発において、シークレット(秘密情報)の受け渡しは誰もが課題にするところではないでしょうか。
- dotenvファイル(Nuxtなど)
- database.yml / master.key(Rails)
DevOpsというワードが飛び交っている今でも、インフラ担当は「なるべくアプリチームの使い勝手を変えないまま、安全に管理する方法」を考えておられると思います。
今回はその方法のバリエーションのひとつとして、「SOPS」を用いた暗号化について紹介します。
SOPSとは?
SOPS(Secrets OPerationS)とはMozilla(Firefoxなどの開発元)が公開している暗号化ツールです。
暗号化ツールというのは他にも存在しますが、SOPSはPGP鍵での暗号化機能の他、以下の特長を持ちます。
- 主要クラウド(AWS、Google Cloud、Azure)の鍵サービスで発行した鍵を用いての暗号化に対応
- ファイルの種類を判別して値だけを暗号化済値に差し替えるので、暗号化済みファイルでも内容が読める(対応ファイル:YAML/JSON/Dotenv/INI)
何が便利なのか?
「AWSならSSMパラメーターストアみたいに、各種クラウドにもシークレットの専用管理サービスがあるのでは?」と思われるでしょう。
しかし、アプリ開発チームが必ずしもAWSの操作に長けているわけではなく、「なるべくAWSは触らずに楽に開発したい」との要望が出たときに考えられる手段は「シークレットはファイル化し、Gitのpushに連動して暗号化する」だと考えます。
例えば、以下の条件の環境があるとしましょう。
- アプリのシークレットを
.env
ファイルに格納している .env
にはDB認証情報が書かれており、GitHubへのアップは禁止
この場合、下記の通りに自動化することで、安全にシークレットの受け渡しが可能であり、アプリ開発チームは特にAWSを操作せず、安全にシークレットをインフラに受け渡すことが可能になります。
- 非公開なS3を作成する(シークレット管理用)
- アプリコードを格納したGitHubリポジトリに、
.env
を.enc.env
にリネームした形で暗号化してS3へアップロードするCIを設定 - 2をトリガーとして
.enc.env
とアプリコードを入手する後続ジョブをスタート .enc.env
復号して.env
に- 4をアプリコードにマージしてインフラにデプロイ
実際に暗号化してみる
では実際に暗号化をしてみます。
準備
下記が必要ですので事前に準備ください。
- SOPSをインストール済
- AWS CLIセットアップ済みで、正しくプロファイルの設定まで完了している
- 1から暗号化復号化できるKMS鍵が発行済み(ARNを控えてください)
暗号化
では、下記のファイル.env
を暗号化してみましょう。
このファイルは適当に作ったものです。
DBHOSTNAME="mygreatdbhost" DBUSERNAME="mydbmasteruser" DBPASSWORD="mydbmasterpassword"
DB情報がそのまま入ってしまってます。危険ですね。
(本来はこんなことは無いと思いますが)
では、このファイルに対して暗号化を行ってみます。
方法はシンプルで、
sops -e --kms (KMSのARN) (--aws-profile AWS CLIのプロファイル名。省略可能) (ファイル名) > (暗号化後ファイル名)
です。
$ sops -e --kms arn:aws:kms:ap-northeast-1:123412341234:alias/sops-demo --aws-profile swx-labo .env > .enc.env
暗号化ファイル.enc.env
はこんな感じになります。
DBHOSTNAME=ENC[AES256_GCM,data:QBQJ3t3reViojLI7NMSZ,iv:x5NcyhKlWfj34g031ByWwi/eFKfjCs3WZMSmtfOGRrg=,tag:DZ+wuOaJm33xt7RUm5UQjA==,type:str] DBUSERNAME=ENC[AES256_GCM,data:wpuYMykNW3c7AEBy1dvgnA==,iv:s3JJ99TShKOY1XdGvNuAy8b5DYSFsEppq9ayrCBhlbQ=,tag:Cr8+/IK67KO2ZLY5B66rFg==,type:str] DBPASSWORD=ENC[AES256_GCM,data:EA7pw5sObLqNJIl/4t47j41SAEQ=,iv:uQEhScWwXgF8JipQ8iL759GYbo5bAoB4dZ+NKobHhNM=,tag:/A/XPCoJ6g4bHwy29LMxhg==,type:str] sops_unencrypted_suffix=_unencrypted sops_version=3.7.1 sops_mac=ENC[AES256_GCM,data:j3XkbxFu1nPtKbZCwiGPOC7VpZxBqM5+wafkP57+YLbhT8AksbgHntC2CQDhF9O+b3aAzUKJf1t4WNBXMM/YA7Koy77kKaHu+tex7JzG/DUNGTQXsUZrqQXUc3A2yAkj24hHAAM4B3tk4zC9Qah81Abymla9s2kYnpXuD0lPyOU=,iv:xqL466FIwlHDfHhapgmFmpyBjnTo9O/CJR7IBB4VFeI=,tag:GZZcB78ARVSFS1MlPHGgRg==,type:str] sops_lastmodified=2021-10-21T06:52:49Z sops_kms__list_0__map_arn=arn:aws:kms:ap-northeast-1:123412341234:alias/sops-demo sops_kms__list_0__map_created_at=2021-10-21T06:52:49Z sops_kms__list_0__map_enc=AQICAHhaAtv1/ZjvWfP/a+ng4YhCpQSY/iMr6eOwRzlD9G6QSAE0G9HESBSt8x/bK1zG4ClHAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM1D+VhC8Lau1mKFV4AgEQgDu19BtTezYjIUYY9oCzp9buFaiz8XNMtoe/zRxkllxewBwDw/C9MQoYIAQyg/FU+J126iSFTJSVHHSMTw== sops_kms__list_0__map_aws_profile=swx-labo
暗号化前と比べて変化がありますね。
- キー名はそのままに、値が暗号化されている
sops_
で始まるキーが追加されている- 暗号化管理・復号化に使うメタデータ
DBHOSTNAME=ENC[AES256_GCM,data:QBQJ3t3reViojLI7NMSZ,iv:x5NcyhKlWfj34g031ByWwi/eFKfjCs3WZMSmtfOGRrg=,tag:DZ+wuOaJm33xt7RUm5UQjA==,type:str] DBUSERNAME=ENC[AES256_GCM,data:wpuYMykNW3c7AEBy1dvgnA==,iv:s3JJ99TShKOY1XdGvNuAy8b5DYSFsEppq9ayrCBhlbQ=,tag:Cr8+/IK67KO2ZLY5B66rFg==,type:str] DBPASSWORD=ENC[AES256_GCM,data:EA7pw5sObLqNJIl/4t47j41SAEQ=,iv:uQEhScWwXgF8JipQ8iL759GYbo5bAoB4dZ+NKobHhNM=,tag:/A/XPCoJ6g4bHwy29LMxhg==,type:str]
しっかりDB接続情報は分からなくなっていますね。
復号
復号の際は鍵情報をメタデータから取得するので、特に指示は不要です。
sops -d .enc.env > .env
なお、暗号化ファイルを直接編集することも可能です。
$EDITOR
のエディタが開かれます。
sops .enc.env
注意事項
最初の例に挙げておいてなんなのですが、試しにRailsから作ったdatabase.ymlを暗号化して復号したところ、どうやら<<: *default
の表記を正しく解釈できないようなので、「可読性がなくなっても良いから暗号化したい!」という場合は、--input-type binary
を付与して暗号化したほうが良さそうです。(私はSOPSに渡す前にbase64を経由させることで対応しました。)
以上、SOPSを用いた秘密情報ファイル管理方法の紹介でした。