SOPSで秘密情報ファイルを安全に管理する

記事タイトルとURLをコピーする

技術1課の水本です。

アプリケーション開発において、シークレット(秘密情報)の受け渡しは誰もが課題にするところではないでしょうか。

  • dotenvファイル(Nuxtなど)
  • database.yml / master.key(Rails)

DevOpsというワードが飛び交っている今でも、インフラ担当は「なるべくアプリチームの使い勝手を変えないまま、安全に管理する方法」を考えておられると思います。

今回はその方法のバリエーションのひとつとして、「SOPS」を用いた暗号化について紹介します。

SOPSとは?

SOPS(Secrets OPerationS)とはMozilla(Firefoxなどの開発元)が公開している暗号化ツールです。

github.com

暗号化ツールというのは他にも存在しますが、SOPSはPGP鍵での暗号化機能の他、以下の特長を持ちます。

  1. 主要クラウド(AWS、Google Cloud、Azure)の鍵サービスで発行した鍵を用いての暗号化に対応
  2. ファイルの種類を判別して値だけを暗号化済値に差し替えるので、暗号化済みファイルでも内容が読める(対応ファイル:YAML/JSON/Dotenv/INI)

何が便利なのか?

「AWSならSSMパラメーターストアみたいに、各種クラウドにもシークレットの専用管理サービスがあるのでは?」と思われるでしょう。

しかし、アプリ開発チームが必ずしもAWSの操作に長けているわけではなく、「なるべくAWSは触らずに楽に開発したい」との要望が出たときに考えられる手段は「シークレットはファイル化し、Gitのpushに連動して暗号化する」だと考えます。

例えば、以下の条件の環境があるとしましょう。

  • アプリのシークレットを.envファイルに格納している
  • .envにはDB認証情報が書かれており、GitHubへのアップは禁止

この場合、下記の通りに自動化することで、安全にシークレットの受け渡しが可能であり、アプリ開発チームは特にAWSを操作せず、安全にシークレットをインフラに受け渡すことが可能になります。

  1. 非公開なS3を作成する(シークレット管理用)
  2. アプリコードを格納したGitHubリポジトリに、.env.enc.envにリネームした形で暗号化してS3へアップロードするCIを設定
  3. 2をトリガーとして.enc.envとアプリコードを入手する後続ジョブをスタート
  4. .enc.env復号して.env
  5. 4をアプリコードにマージしてインフラにデプロイ

実際に暗号化してみる

では実際に暗号化をしてみます。

準備

下記が必要ですので事前に準備ください。

  1. SOPSをインストール済
  2. AWS CLIセットアップ済みで、正しくプロファイルの設定まで完了している
  3. 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を用いた秘密情報ファイル管理方法の紹介でした。

水本 正敏(執筆記事の一覧)

エンタープライズクラウド部 ソリューションアーキテクト1課

国内ITベンダーのカスタマーエンジニアからAWSに魅了されサーバーワークスへ。