MoTLab -GO Inc. Engineering Blog-MoTLab -GO Inc. Engineering Blog-

SOPS: Secrets OPerationS!

SRE
November 18, 2022

こんにちは、技術戦略部 SREグループのカンタンです!

データベースのパスワードやAPIサーバの認証情報など秘密情報をきちんと管理しないと漏洩が発生しセキュリティインシデントに繋がる可能性が高いでしょう。

数ヶ月前から、SREグループが扱っている秘密情報の管理方法をgit-cryptからsopsに切り替えました。運用が楽になり、セキュリティレベルが向上し、非常に満足しているためsops自体とSREグループの使い方を紹介させていただきたいと思います。


背景

SREグループでは、Terraform用の設定やKubernetesで動いているサービスの環境変数など秘密情報を暗号化した上で一つのgitリポジトリで一元管理しています。秘密情報を利用する際、暗号化ファイルを復号してからgrepなどで検索したり、Terraformプロジェクトを適用したり、環境変数をKubernetesのSecretに反映したりしています。

暗号化の仕組みとしてgit-cryptを数年利用していましたが、 以下のような課題がありました:

  • 運用が大変:復号権限を付与するにはユーザにGPG鍵を発行してもらって、全ての暗号化ファイルを再暗号化する必要がある
  • 細かいアクセス制御ができない:リポジトリの全てのファイルへの権限付与しかできず、特定のファイルにだけ権限を付与することができない
  • 監査ログが取れない:誰がいつどのファイルを復号したかわからない
  • セキュリティレベルが低い:gitリポジトリと復号権限を持っているユーザ一人のGPG鍵が漏洩してしまうと全ての秘密情報が漏洩してしまう。また、アクセス権限を解除しても、git履歴が見れる限り過去の秘密情報が見れてしまう

更に、開発者ができることをもっと広げたいと言う意図もあって、今までSREしか管理できなかった秘密情報を開発者に直接管理してもらうための安全なやり方を探していました。

  • 開発者が自分のサービスの環境変数を直接管理できる
  • 他のチームのサービスの情報を変更できないようにする

こういった懸念を解決するため、秘密情報の管理方法を完全にリニューアルすることになりました。

秘密情報の管理方法

秘密情報を管理するには主に2つのやり方があるかと思います。秘密情報を暗号化した上でgitリポジトリに保存するか、秘密情報をAWS Secret Manager、GCP Secret Manager、HashiCorp Vault など外部サービスに預けて管理する。それぞれのやり方のメリットとデメリットを次にまとめていきます。

暗号化した上でgitで秘密情報を管理

例:git-crypt、git-secret、sops

メリット

  • ❇️ 細かいバージョン管理ができる (コミット単位)
  • ❇️ 変更履歴をgit logなどで閲覧できる
  • ❇️ 複数バージョンの差分を確認できる (git diff)
  • ❇️ レビューがある程度できる (PR上でどのファイルを変更しようとしているかわかる、復号すれば中身もレビューできる)
  • ❇️ 秘密情報をその他情報と一元管理できる (例えば平文で良いTerraform .tf ファイルと秘密情報のTerraform変数を同じフォルダで管理)
  • ❇️ 秘密情報がコード化されているため、検索やコピペなどができて扱いやすい
  • ❇️ 慣れているgitフローで管理できる

デメリット

  • 🚸 権限管理が大変な場合がある(例えばgit-cryptやgit-secretを利用する場合)
  • 🚸 漏洩が発生した際に、暗号化キーのローテーションに手間がかかる場合がある(例えばgit-cryptやgit-secretを利用する場合)
  • 🚸 監査ログが簡単に取れない場合がある(例えばgit-cryptやgit-secretを利用する場合)
  • 🚸 権限を解除しても過去の秘密情報を復号できてしまう場合がある(例えばgit-cryptやgit-secretを利用する場合)
  • 🚸 暗号化アルゴリズムがセキュアであることを検証する必要がある
  • ⛔ 秘密情報を利用する際に復号した状態をローカルに保存しているため平文状態がずっと残るリスクがある

外部サービスを使って秘密情報を管理

例:AWS Secret Manager、GCP Secret Manager、HashiCorp Vault

メリット

  • ❇️ 暗号化を外部サービスに任せているため仕組みを気にする必要がない
  • ❇️ 権限管理が楽 (APIやGUIなどで管理可能)
  • ❇️ 監査ログが取れる
  • ❇️ 秘密情報が外部サービスの中にしか存在しないためセキュア (gitには存在しない)
  • ❇️ ファイルが漏洩した際の暗号化キーローテーションなどが不要

デメリット

  • 🚸 外部サービスが十分セキュアというのを確認する必要がある
  • 🚸 外部サービスのIAM管理に手間がかかる場合がある(例えばHashicorp Vaultを使う場合、AWS/GCPとは別のIAM管理が必要)
  • 🚸 変更履歴を簡単に閲覧できない場合がある
  • ⛔ 秘密情報のバージョン管理が大変
  • ⛔ レビューができない
  • ⛔ 秘密情報の同時変更に気づかないため上書きリスクがある
  • ⛔ 復号した状態の情報をローカルで持たないため、grepなどスクリプトが使えない
  • ⛔ 秘密情報を利用できるように、既存のツールを秘密情報管理外部サービスに合わせる必要がある(Terraformなど)
  • ⛔ コード化されない
  • ⛔ 秘密情報とその他情報が別管理になる

gitでの管理の方がメリットが多いため、秘密情報を引き続きgitで管理することにしました。ただし懸念が多かったgit-cryptからsopsというツールに切り替えたことで、管理方法がもっとセキュアになったうえ、運用が非常に楽になりました。これからsopsについて説明させていただきたいと思います!

SOPS: Secrets OPerationS

sops is an editor of encrypted files that supports YAML, JSON, ENV, INI and BINARY formats and encrypts with AWS KMS, GCP KMS, Azure Key Vault, age, and PGP. (demo)

sopsは様々な機能が詰まったファイルを暗号化するためのツールです。

初期設定後、sops file.yaml のようなコマンドを実行するだけでテキストエディタが開いて、秘密情報を記入して保存した後に以下のような暗号化ファイルが自動的に作成されます。

myapp1: ENC[AES256_GCM,data:Tr7o=,iv:1=,aad:No=,tag:k=]
app2:
    db:
        user: ENC[AES256_GCM,data:CwE4O1s=,iv:2k=,aad:o=,tag:w==]
        password: ENC[AES256_GCM,data:p673w==,iv:YY=,aad:UQ=,tag:A=]
    # private key for secret operations in app2
    key: |-
        ENC[AES256_GCM,data:Ea3kL5O5U8=,iv:DM=,aad:FKA=,tag:EA==]
an_array:
- ENC[AES256_GCM,data:v8jQ=,iv:HBE=,aad:21c=,tag:gA==]
- ENC[AES256_GCM,data:X10=,iv:o8=,aad:CQ=,tag:Hw==]
- ENC[AES256_GCM,data:KN=,iv:160=,aad:fI4=,tag:tNw==]
sops:
    kms:
    -   created_at: 1441570389.775376
        enc: CiC....Pm1Hm
        arn: arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
    -   created_at: 1441570391.925734
        enc: Ci...awNx
        arn: arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d
    pgp:
    -   fp: 85D77543B3D624B63CEA9E6DBC17301B491B3F21
        created_at: 1441570391.930042
        enc: |
            -----BEGIN PGP MESSAGE-----
            hQIMA0t4uZHfl9qgAQ//UvGAwGePyHuf2/zayWcloGaDs0MzI+zw6CmXvMRNPUsA
                            ...=oJgS
            -----END PGP MESSAGE-----

sops: キーの下に、そのファイルを暗号化するために利用されたバックエンド(AWS KMS、GPGなど)と暗号化キーのパブリック情報が保存されています。同じ sops file.yaml コマンドをもう一度実行すると、sopsがその情報をファイルから抽出して、バックエンドを使ってファイルを復号しテキストエディタに表示してくれます。sops: キーの上の情報が暗号化されているため、ファイルをgitで管理しても問題ないです。

sopsで特に注目したい特徴が下記になります:

  • YAML/JSONファイルが扱いやすい:YAML/JSONファイルに入っているkey-valueの中、keyをそのまま残しつつvalueだけを暗号化する仕組みになっているためレビューがしやすい
  • 権限管理が楽
    • AWS KMSやGCP KMSを使って暗号化できるため、既に利用しているAWSやGCPのIAMユーザ・ロール・サービスアカウントを活かせる
    • ファイル単位の細かい権限管理ができる(git-cryptの場合はリポジトリ単位のみ)
    • 権限の付与と削除はAWS/GCP側で行える(git-cryptは全てのファイルの再暗号化が必要)
  • 暗号化キーの操作がやりやすい:マスターキーの追加と削除データキーのローテーションが楽
  • AWSの様々な機能を対応している
  • 様々な暗号化仕組みを対応しているため方針変更に柔軟に対応可能

暗号化の仕組みの説明

sopsを利用する場合、暗号化・復号の仕組みを理解しないと暗号化キーの発行単位やファイルの分け方など判断しづらい部分があるためしっかり説明したいと思います。AWS KMSを使った場合の説明になりますが、GCPなど他のバックエンドも同じです。

sopsはエンベロープ暗号化を利用してファイルを暗号化しています。sopsを利用する前にAWS KMSなどを使ってマスターキーを作成します。暗号化ファイルを作成する際にsopsがランダムなデータキーを生成し、秘密情報をそのデータキーで暗号化しファイルに保存しています。データキーを安全に保存できるように、マスターキーを使ってデータキーを暗号化してファイルにも保存しています。

復号する際、ファイルに含まれている暗号化されたデータキーをマスターキーで復号します。復号されたデータキーを使ってファイルの中身を復号します。

新規ファイル作成

  1. sopsがランダムなデータキーを生成する
  2. AWS KMSのマスターキーを使ってデータキーを暗号化する
  3. 暗号化されたデータキーを安全にファイルに保存する
An image from Notion

秘密情報の暗号化

  1. ファイルから暗号化されたデータキーを抽出する
  2. AWS KMSを使ってデータキーを復号する
  3. 暗号化するkey-valueごとにランダムなInitialization Vector (IV) を生成する
  4. データキーとIVを使ってvalueを暗号化する
  5. IVと暗号化されたvalueをファイルに保存する
  6. IVは平文状態でファイルに保存されている
  7. ファイルの整合性を後から確認できるように、全てのkey-valueをベースに計算されたMACを暗号化してファイルに保存する
An image from Notion

秘密情報の復号

  1. ファイルから暗号化されたデータキーを抽出する
  2. AWS KMSを使ってデータキーを復号する
  3. ファイルに入っている全てのkey-valueをベースにMACを計算し暗号化して、ファイルに保存されているMACと比較することで整合性を保つ
  4. ファイルからIVと暗号化されたvalueを抽出する
  5. データキーとIVを使ってvalueを復号する
An image from Notion

複数のマスターキーを利用する場合

sopsでは同じファイルを複数マスターキーで管理できます。そうすることで、片方のマスターキーへのアクセスができなくなったとしても、もう一つのマスターキーにアクセスさえできれば復号可能になります。ある意味バックアップとして使える機能です(AWS KMSで管理しつつ、例えばオフラインで管理するAge鍵をバックアップとして設定しておく)。バックアップ以外の目的もあります:例えばチームごとにマスターキーを発行して、同じファイルを複数マスターキーで管理することでファイルを複数チームに共有できます。

仕組み自体が以下のようになります:

  • マスターキーの数と関係なく、データキーは一つしか生成されていない
  • 生成されたデータキーをそれぞれのマスターキーで暗号化してファイルに保存している
  • 暗号化されたデータキーを一つでも復号できればデータキーがわかるため秘密情報を復号できる
An image from Notion

権限付与

マスターキーにアクセスできるユーザがそのキーで暗号化されたファイルを全て復号できます。

AgeやGPG鍵をマスターキーとして使う場合、その鍵を物理的にアクセスする必要があります(ローカルに落とす必要があります)。あるユーザに権限を付与するには、実際のマスターキーを共有する形になるため、マスターキーの漏洩リスクがそれなりに高いです。

AWS KMS (GCP KMSも同様)の場合、マスターキーがAWSの中にしか存在していなくて、sopsを実行する際に暗号化したい内容をAWS KMSに渡して暗号化してもらったり、復号したい内容をAWS KMSに渡して復号してもらったりしています。マスターキーの内容を知る必要がなくて、暗号化と復号をAWS KMSに任せています。あるユーザに権限を付与するには、マスターキーに対してのAWS KMS Encrypt/Decrypt権限を付与すれば大丈夫です。マスターキーの内容を物理的にアクセスする必要がないため、マスターキーの漏洩リスクが0と近いのと、ユーザのAWS認証情報が漏洩した場合にそのユーザのAWS KMS権限を落とせば復号できなくなります。また、ファイルを復号する際にAWS CloudTrailにイベントが残るため、監査ログが取れます。

普段の利用に関しては、AgeやGPG鍵よりもAWS KMSやGCP KMSを使った方がセキュアです。

MoTでの使い方

sopsはとても便利なツールで、機能も多くて様々な利用方法がありますが、これから先はMoTでの使い方を紹介したいと思います。

設計・方針

暗号化コンテキスト

「権限付与」のところで説明があったように、マスターキーにアクセスできるユーザがそのキーで暗号化されたファイルを全て復号できます。

全てのファイルを単純に同じマスターキーで暗号化してしまうと、全てのファイルの復号権限を付与するかしないかという選択肢しかなくて、細かいアクセス制御を実現できないです。逆にファイルをそれぞれ別のマスターキーで暗号化すれば、ファイル単位の権限を付与できるようになりますが、ファイル数分のマスターキーを発行する必要があります。その場合マスターキーの管理が大変になるのと、AWS KMSを使うとキーごとに月額$1の料金が発生しますのでファイルが多いとそれなりの値段になります。

そこでAWS KMSの「暗号化コンテキスト」機能が登場します。暗号化コンテキストは environment=development, team=team-a のような自由に決めれるkey-valueのリストです。AWS KMSで暗号化する時、暗号化したい内容と合わせて暗号化コンテキストを渡すことで、復号する際に全く同じ暗号化コンテキストを渡さないと復号できないようになっています。更に、AWS IAMポリシーを定義する際に暗号化コンテキストを考慮したアクセス権限を付与できます。以下のサンプルの場合、 environment=development, team=team-a 暗号化コンテキストが指定された場合のみ権限を付与することになり、別の暗号化コンテキストが渡された場合は権限エラーになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AccessKMSKey",
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "arn:aws:kms:ap-northeast-1:ACCOUNT_ID:key/KMS_KEY_ID",
            "Condition": {
                "StringEquals": {
                    "kms:EncryptionContext:environment": "development",
                    "kms:EncryptionContext:team": "team-a"
                }
            }
        }
    ]
}

sopsコマンドのオプションに暗号化コンテキストを渡すことでファイルを特定のコンテキストで暗号化できます。

sops --encryption-context environment:development,team:team-a file.yaml

以下のような .sops.yaml ファイルを作れば、暗号化ルールを定義できてコマンドラインに何も指定しなくても良くなります。

creation_rules:
  - path_regex: /development/team-a/.* # ファイルパスのregex
    key_groups:
      - kms:
          - arn: 'AWS_KMS_MASTER_KEY_ARN'
            context: # 暗号化コンテキスト
              environment: development
              team: team-a

  - path_regex: /development/team-b/.*
    key_groups:
      - kms:
          - arn: 'AWS_KMS_MASTER_KEY_ARN'
            context: # 暗号化コンテキスト
              environment: development
              team: team-b

- path_regex: /production/team-a/.*
    key_groups:
      - kms:
          - arn: 'AWS_KMS_MASTER_KEY_ARN'
            context:
              environment: production
              team: team-a

  - path_regex: /production/team-b/.*
    key_groups:
      - kms:
          - arn: 'AWS_KMS_MASTER_KEY_ARN'
            context: # 暗号化コンテキスト
              environment: production
              team: team-b

この機能を使えば、ファイルごとに適切な暗号化コンテキストを設定すれば一つのAWS KMSマスターキーだけで全てのファイルを暗号化しても問題ないです。権限付与も非常に柔軟になります:「dev環境の全てのファイルの権限」、「prod環境の特定のチームのファイルの権限」、「あるチームの全てのファイルの権限」など。

MoT SREの方針

sopsを利用する際にSREグループで考えた方針を以下にまとめています。

  • sopsのバックエンドとしてAWS KMSを使う
    • 暗号化コンテキスト機能を使うため
    • AWS IAMを既に利用しているため
  • 全てのファイルを2つのマスターキーで暗号化する(同じ2つ)
    • 普段の作業で使うAWS KMSマスターキーを一つ
    • バックアップとしてオフラインに保管するAgeマスターキーを一つ
  • 暗号化コンテキストを使って細かい権限管理を実現する
    • environment:環境 (development, production, staging…)
    • namespace:チームと近い概念ですが組織変更を考慮するために抽象化された単位 (Kubernetesのネームスペース概念と同じ)
    • application:サービス名
    • security_level:求めているセキュリティレベルを表す(level_100, level_200 …)。ファイル内容によりますが、例えばsuperuserのパスワードが入ったファイルを最大のセキュリティレベルにして、サービスのAPIキーが入ったファイルをもう少し下のレベルに設定するなど
    • use:用途 (terraform, kubernetes…)。例えばdev環境のKubernetes設定だけに権限を付与するため
  • ファイルへのアクセス権限を暗号化コンテキストで実現する
    • 基本的に「environment」 x 「namespace」 x 「security_level」単位
    • 特殊ケースの場合、「application」や「use」も使う
  • 秘密情報が含まれているファイルの命名規則名
    • 暗号化ファイル: *.secret.enc.<extension> (例: app1.secret.enc.jsonapp2.secret.enc.yaml )
    • 復号されたファイル: *.secret.<extension> (例: app1.secret.jsonapp2.secret.yaml )
  • ファイルを利用する時以外、ファイルを平文状態でローカルで持たない

サンプルスクリプト

ファイルを平文状態でローカルで待たないようにしていますが、秘密情報をgrepで検索したい時やTerraformを実行したい時など一時的に復号したい場合もあります。

あるフォルダの全てのファイルを一時的に復号したり、変更のあったファイルだけを再暗号化したり、gitコンフリクトを自動的に解決したりするスクリプトをいくつか用意しています。

参考まで、ファイルの一括復号と再暗号化スクリプトサンプルを以下に記載します。

利用: .sops.yaml が設定されているフォルダから実行

./modify.sh my-folder

modify.sh

#!/usr/bin/env bash
set -euo pipefail

search_paths=${@:-.}

# --------------------
# Helpers
# --------------------

to_encrypted_file() {
  decrypted_file=$1
  echo "${decrypted_file/\.secret/.secret.enc}"
}

to_decrypted_file() {
  encrypted_file=$1
  echo "${encrypted_file/secret\.enc/secret}"
}

find_unencrypted_secret_files() {
  search_paths=$@
  find $search_paths* -type f \( -name '*\.secret*' ! -name '*\.secret\.enc*' \)
}

find_encrypted_secret_files() {
  search_paths=$@
  find $search_paths* -type f -name '*\.secret\.enc*'
}

confirm() {
  message=$1

  read -p "$message (Y/N)" -n 1 -r
  echo

  [[ $REPLY =~ ^[Yy]$ ]]
}

# --------------------
# Encryption
# --------------------

decrypt_file() {
  encrypted_file=$1
  decrypted_file="$(to_decrypted_file $encrypted_file)"

  echo "Decrypt file $encrypted_file into $decrypted_file"

  # clean previous file
  rm -f $decrypted_file

  # decrypt
  set +e
  sops --config /dev/null --decrypt "$encrypted_file" > "$decrypted_file"
  decryption_status=$?
  set -e

  if [[ "$decryption_status" != "0" ]]; then
    rm -f $decrypted_file
    exit 1
  fi
}

reencrypt_file() {
  decrypted_file=$1
  encrypted_file="$(to_encrypted_file $decrypted_file)"

  echo "Encrypt file $decrypted_file into $encrypted_file"

  # update encrypted file
  NEW_DECRYPTED=$decrypted_file EDITOR=./reencryption-editor.sh sops "$encrypted_file"

  # delete previous file
  echo "Delete file ${decrypted_file}"
  rm "$decrypted_file"
}

# reencrypt then delete decrypted secrets
reencrypt_files () {
  decryption_time=$1

  echo "--------------------"
  echo "Reencrypting secrets..."

  unencrypted_files="$(find_unencrypted_secret_files $search_paths)"

  while read -r file; do
    if [[ "$file" == "" ]]; then continue; fi

    file_modification_time=$(/usr/bin/stat -t %s -f %m $file)

    if [ $file_modification_time -gt $decryption_time ]; then
      reencrypt_file $file
    else
      echo "Skipping not-modified file $file"
    fi
  done <<< "$(echo -e "$unencrypted_files")"

  echo "------- done -------"
}

# If anything goes wrong, then delete decrypted secrets
handle_trap_exit () {
  exit_code=$?

  echo "--------------------"
  echo "Deleting unencrypted secrets..."

  unencrypted_files="$(find_unencrypted_secret_files $search_paths)"

  while read -r file; do
    if [[ "$file" == "" ]]; then continue; fi

    echo "Delete file $file"
    rm $file
  done <<< "$(echo -e "$unencrypted_files")"

  echo "------- done -------"

  if [ "$exit_code" != "0" ]; then
    echo "Error when decrypting secrets"
    exit 1
  fi
}

# --------------------
# Process
# --------------------
# dry-run
found_files=0

echo "Checking paths ${search_paths}"
echo "--------------------"

encrypted_files="$(find_encrypted_secret_files $search_paths)"

while read -r file; do
  if [[ "$file" == "" ]]; then continue; fi

  echo "[dry-run] $file will be decrypted"
  found_files=1
done <<< "$(echo -e "$encrypted_files")"

if [ "${found_files}" == "0" ]; then
  echo "No files to decrypt!"
  exit 0
fi

echo "--------------------"

found_files=0

unencrypted_files="$(find_unencrypted_secret_files $search_paths)"

while read -r file; do
  if [[ "$file" == "" ]]; then continue; fi

  echo "[dry-run] $file will be deleted"
  found_files=1
done <<< "$(echo -e "$unencrypted_files")"

if [ "${found_files}" != "0" ]; then
  echo "--------------------"
fi

# confirmation
confirm "All non-encrypted secrets will be overriden, continue ?"

# execution
trap handle_trap_exit EXIT

num_processes=10
i=0

while read -r file; do
  if [[ "$file" == "" ]]; then continue; fi

  i=$((i%num_processes)); ((i++==0)) && wait

  decrypt_file $file &
done <<< "$(echo -e "$encrypted_files")"

wait

decryption_time="$(date +%s)"

echo "------- done -------"

echo "Secrets are now decrypted and can be modified"

read -p "Press a key to reencrypt files and close this program..." -n 1 -r

reencrypt_files $decryption_time

reencryption-editor.sh

#!/usr/bin/env bash
set -eu

# copy new decrypted into file
cp $NEW_DECRYPTED $1

サンプル実行

$ ls secrets/                                                                                                                                                                                                                                                                                                                                     Thu Nov 17 13:42:08 2022
app1.secret.enc.yaml       passwords.secret.enc.yaml

$ ./modify.sh secrets                                                                                                             28.6s  Thu Nov 17 13:41:02 2022
Checking paths secrets
--------------------
[dry-run] secrets/passwords.secret.enc.yaml will be decrypted
[dry-run] secrets/app1.secret.enc.yaml will be decrypted
--------------------
All non-encrypted secrets will be overriden, continue ? (Y/N)y
Decrypt file secrets/passwords.secret.enc.yaml into secrets/passwords.secret.yaml
Decrypt file secrets/app1.secret.enc.yaml into secrets/app1.secret.yaml
------- done -------
Secrets are now decrypted and can be modified
Press a key to reencrypt files and close this program...

# -------
# 別ターミナルで、復号されたsecrets/passwords.secret.yamlファイルを編集する
# 編集後、元のターミナルでキーを押す
# -------

--------------------
Reencrypting secrets...
Skipping not-modified file secrets/app1.secret.yaml
Encrypt file secrets/passwords.secret.yaml into secrets/passwords.secret.enc.yaml
Delete file secrets/passwords.secret.yaml
------- done -------
--------------------
Deleting unencrypted secrets...
Delete file secrets/app1.secret.yaml
------- done -------

終わりに

秘密情報を管理するにはsopsがとても便利なツールで大変おすすめです。他のエンジニアにアクセス権限を柔軟に付与できるようになり、平文状態の秘密情報がローカルに保存されなくなり、既存ツールを全く変えずに今までのTerraformやKubernetes運用を継続でき、SREグループでsopsに切り替えてから数ヶ月経っていますが非常に満足しています。

最後にまとめると、sopsとAWS KMSを併用すると以下のメリットがあります:

  • ❇️ gitを活かせる:コミット単位の細かいバージョン管理、変更履歴、差分表示、レビュー
  • ❇️ 秘密情報がコード化されるため検索やコピペなどができて扱いやすい
  • ❇️ AWS KMSの暗号化コンテキストで細かい権限管理ができる
  • ❇️ AWS IAM権限で復号権限を簡単に落とせる(過去の秘密情報も含めて)
  • ❇️ AWS CloudTrailで監査ログが取れる
  • ❇️ スクリプトを用意すれば、自分の組織と合う使い方にできる
  • など!

秘密情報の管理方法に悩んでいる方へ、是非sopsを検討してみてください!この記事がご参考になれば幸いです!


We're Hiring!

📢
Mobility Technologies ではともに働くエンジニアを募集しています。

興味のある方は 採用ページ も見ていただけると嬉しいです。

Twitter @mot_techtalk のフォローもよろしくお願いします!