Eng (なりたい)

はやく エンジニア になりたい

SOPSを試してみる

クレデンシャルなどの情報もGitで管理したい…!! とくに GitOps などを採用しているとそう感じるケースも多いと思います。(僕はよく思っていました) そんなときの解決方法の一つであるSOPSを試してみました。

↓の本で紹介されていて知りました。ツール自体はかなり前からあるみたい

www.oreilly.co.jp

動作確認した環境は macOS Catalina 10.15.5 です。

Install SOPS

まずは sops をインストールします。

brew install sops
$ sops -v
sops 3.5.0 (latest)

暗号化の対象になるファイルを作成

今回は簡単なユーザー名とパスワードが入ったファイルを想定します。

$ mkdir config
$ cd config

config/dev.yaml

user: dev-user
pass: dev-pass

暗号化のための鍵を作成

参考: Google: google_kms_secret - Terraform by HashiCorp

  • 簡単化のために
    • 3環境用のモジュール化は見逃してください…(devだけ動かします)
    • remote state は見逃してください…
$ cd ..
$ mkdir terraform
$ cd terraform

terraform/kms_dev.tf

resource "google_kms_key_ring" "key_ring" {
  name     = "sops-key-ring"
  location = "asia-northeast1-b"
}

resource "google_kms_crypto_key" "my_crypto_key" {
  name     = "sops-crypto-key"
  key_ring = google_kms_key_ring.my_key_ring.self_link
}

プロバイダ用のファイルも作成

terraform/provider.tf

provider "google" {
  project = "kaito2"
  region  = "asia-northeast1"
}

// cloud kms を有効化
resource "google_project_service" "kms" {
  service = "cloudkms.googleapis.com"
}
$ terraform init
$ terraform plan
...
Plan: 2 to add, 0 to change, 0 to destroy.
...
$ terraform apply
...
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
$ gcloud kms keyrings list --location asia-northeast1
NAME
projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring

$ gcloud kms keys list --keyring sops-key-ring --location asia-northeast1
NAME                                                                                         PURPOSE          ALGORITHM                    PROTECTION_LEVEL  LABELS  PRIMARY_ID  PRIMARY_STATE
projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key  ENCRYPT_DECRYPT  GOOGLE_SYMMETRIC_ENCRYPTION  SOFTWARE                  1           ENABLED

ちゃんと鍵が作成されていることが確認できました。

対象ファイルを暗号化

鍵を指定せずに実行すると怒られます。

$ cd ../config
$ sops -e dev.yaml
config file not found and no keys provided through command line options

GCP の場合は --gcp-kms オプションにリソースIDを渡す必要がある(or SOPS_GCP_KMS_IDS という名前の環境変数に設定する)。

リソースIDとは: Object hierarchy  |  Cloud KMS Documentation  |  Google Cloud

コマンドを以下のように変更 (何も指定しないと標準出力に暗号化されたファイルの内容が出力される。)

$ sops -e --gcp-kms projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key dev.yaml
user: ENC[AES256_GCM,data:8Hug2XT/PP8=,iv:X6/VCucFyTtqaspP20OOKbBm43AuFvVCN+mA7uReKTw=,tag:GTTIklpZw+kfQK+eamw1bQ==,type:str]
pass: ENC[AES256_GCM,data:Fw5s9NJVxY8=,iv:JTkKRLiSKa7i2o+Ek20Dq6+YUpxdUWPm2halpUtzi6o=,tag:4l57RVbGH1oaKdO+4zE80A==,type:str]
sops:
    kms: []
    gcp_kms:
    -   resource_id: projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key
        created_at: '2020-07-13T11:42:45Z'
        enc: CiQAIyu+rA1vIggweC/+b2fWXzFVDlRYL9utDh9znmBKOoip8VcSSQCqguh30vH6TCl/mhT+AgucZ2sIRJwthwXk+M1GIzOIDvFoXCUHY1VvVyfzaSXCKhkw8boV4EW8QDqYEDyX1n6NVR5kIiSxSBQ=
    azure_kv: []
    lastmodified: '2020-07-13T11:42:46Z'
    mac: ENC[AES256_GCM,data:BXAavE6OhzKSfdmRE5cQmvyEKga0pnnSOAQLYmnjdadlRTV/TuDhSlriYNenEFXw4+RCHurL2xZfY3cOoqwuct6lZz2ATm81yzqjtymuH63xFG80DqjJRgKFQ+wBuggLPasKyWq8PHUQEr/0CEVZ/u9LgVO3CoJS5gWNISLzrow=,iv:KnaYCHB8r+clN1iVn0yCJnAKfI3r7h/H+sSCji++/Ic=,tag:/OzY47i++dfBO3VkdBiaUQ==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.5.0

コマンドごとに --gcp-kms オプションを指定するのも面倒なので .sops.yaml という設定ファイルを設置することで sops がそれを読み込んでよしなにしてくれる。

See: mozilla/sops

config/.sops.yaml

creation_rules:
        - path_regex: \.dev\.yaml$
          gcp_kms: projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key

コンフィグファイルを設定したので --gcp-kms オプションなしでも暗号化できるようになりました。

$ sops -e dev.yaml
user: ENC[AES256_GCM,data:cxkJBKyiQ4c=,iv:m00uQzik0OBw0tf5es4j1mZH+TM2JxynjifOhkW+ZHE=,tag:Jxtj4cfRe+TIdz3Vp9lw7w==,type:str]
pass: ENC[AES256_GCM,data:JUcITsSaKqc=,iv:cbNXopbCJPGtFbSkwn0TAXUKN0ojSjcMQrQJ5DpFOWo=,tag:i4/ey1aJh99PtZovpHU6Ww==,type:str]
sops:
    kms: []
    gcp_kms:
    -   resource_id: projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key
        created_at: '2020-07-13T11:48:46Z'
        enc: CiQAIyu+rN+NkKTu3H/riwZ4NsNWh5SjmWiZQbp13qyaj8vPfdgSSQCqguh3JyE5RlKHVWKUkJ/cVRL4jNyKnIAMc6MUMZdeXURJ+I2tFuXRZRVbJpHKTf1CV4K0sKPdJyQwVvjdzbJAA2CrOZgdupw=
    azure_kv: []
    lastmodified: '2020-07-13T11:48:47Z'
    mac: ENC[AES256_GCM,data:/I+KswiR7VsJYDZJMwbUn1M/ygbLmbIdCuUVKR9uaZ+SFSudpU0zqX0mLg9R9jz5fB8t7JkcAPkXK5QiWJywvnE5YjtU3IsjrydNb7lEa630tqB0pEP8J4co+dGh9MzvyDQsldvwrREx9Ln8B3RfdyPaufYv7RfVqwBbWkgIYv0=,iv:g2jiRLD0wJYcj1OmhOzqDxOu5DWCcPTml9ROniyfXtQ=,tag:xXemqikO8oz8N8tlPUM+6A==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.5.0

SOPS はデフォルトですべての値を暗号化しますが、例えば user の値は暗号化したくないなどの要件がある場合はオプションによって実現できます。

See: mozilla/sops

config/.sops.yaml を以下のように書き直します

creation_rules:
  - path_regex: dev\.yaml
    encrypted_regex: pass
    gcp_kms: projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key

再度暗号化を実行すると、 user の値は暗号化されておらず、pass の値は暗号化されていることが確認できます。

$ sops -e dev.yaml
user: dev-user
pass: ENC[AES256_GCM,data:nPihbY9Qe+o=,iv:naSvswd7v1Kdnq7VFfj2A3KT3SRV6HtLp2lTHFro3Ks=,tag:dtRf4pW0grYJqWBoNzuS7g==,type:str]
sops:
    kms: []
    gcp_kms:
    -   resource_id: projects/kaito2/locations/asia-northeast1/keyRings/sops-key-ring/cryptoKeys/sops-crypto-key
        created_at: '2020-07-13T11:53:47Z'
        enc: CiQAIyu+rFdLYVJKYgTiwH9L2sGwet7ugxWIlUPj39YhyyRR5ZISSQCqguh3cc4CB2tIC8KUhCa+5SXIw7HTpx1NP/FVBRIsXdscXHMnwn0FEgx2uH8MBrLGyv+Opb+WnomXWBZoBO+xQdDNOx5uvoI=
    azure_kv: []
    lastmodified: '2020-07-13T11:53:48Z'
    mac: ENC[AES256_GCM,data:liFOktDxSb/phDHyha8ollNe6fXlZkQYfhxiBPaKZJDuUmDBBw6d7DrQIF/lg1b4FBundJ5l9SW/m5PK58yeLNbzTqTwl/ACXH69M4cE+GQZqi4HRYdMa5hfe7VTwYn+TbKL3DHZFavPWl/Nih6by5PL8ooJds4Z7+Ey28Z5M0A=,iv:0HM9a2wrxJHV9ZALxQYoc5s6Kd2miADVwax8hAig29k=,tag:ABAxVKdOI/tJEt6JIvwIXA==,type:str]
    pgp: []
    encrypted_regex: pass
    version: 3.5.0

-i オプションを追加するとファイルを直接暗号化して置き換えます。

$ sops -e -i dev.yaml
# dev.yaml が書き換わっている

復号する場合は以下のコマンドを実行します。

sops -d -i dev.yaml

なので CI などでは config/ ディレクトリに移動し、上記のコマンドを実行すれば、必要な鍵を利用する権限があるかチェックされます。そして、権限がある場合は復号が実行されます。

実際にデプロイする流れはまた次回書きます。

所感

決して機能がリッチなわけでは無いですが、シンプルで挙動もわかりやすく、使い勝手のいいツールだと感じました。

carlpett/terraform-provider-sops なども便利そうなので試してみたいです… 特に、コンフィグファイルの可読性を落とさない点と、複数のクラウドの差異を吸収してくれる点は個人的に良いと思います。

よく使われている同じ目的のツールとしては bitnami-labs/sealed-secrets があるようなので、そちらとも比較してみたいです。