getsops/sops
GitHub: getsops/sops
一个支持多云 KMS 和 PGP 的文件加密编辑器,能够加密 YAML/JSON 等文件中的敏感值并保留结构,适合在 Git 中安全存储密钥。
Stars: 20995 | Forks: 1006
# SOPS: Secrets OPerationS
**SOPS** 是一个加密文件编辑器,支持 YAML、JSON、ENV、INI 和 BINARY 格式,并使用 AWS KMS、GCP KMS、Azure Key Vault、HuaweiCloud KMS、age 和 PGP 进行加密。
(`demo `_)
## .. image:: https://i.imgur.com/X0TM5NI.gif
.. image:: https://pkg.go.dev/badge/github.com/getsops/sops/v3.svg
:target: https://pkg.go.dev/github.com/getsops/sops/v3
## 下载
### 稳定版本
最新稳定版本的二进制文件和包可在 `https://github.com/getsops/sops/releases `_ 获取。
### 开发分支
对于喜欢尝鲜的用户,`main` 分支中提供了不稳定的功能,您可以从源码安装:
.. code:: bash
```
$ mkdir -p $GOPATH/src/github.com/getsops/sops/
$ git clone https://github.com/getsops/sops.git $GOPATH/src/github.com/getsops/sops/
$ cd $GOPATH/src/github.com/getsops/sops/
$ make install
```
(需要 Go >= 1.19)
如果您没有安装 Go,请使用以下命令进行设置:
.. code:: bash
```
$ {apt,yum,brew} install golang
$ echo 'export GOPATH=~/go' >> ~/.bashrc
$ source ~/.bashrc
$ mkdir $GOPATH
```
或者使用适合您系统和 shell 的变体。
要将 **SOPS** 用作库,请查看 `decrypt package `_。
.. sectnum::
.. contents:: 目录
## 使用说明
有关 SOPS 的快速介绍,请查看此 Youtube 教程:
.. image:: https://img.youtube.com/vi/V2PRhxphH2w/0.jpg
:target: https://www.youtube.com/watch?v=V2PRhxphH2w
如果您使用的是 AWS KMS,请在 IAM 控制台中创建一个或多个主密钥,并将它们(以逗号分隔)导出到 **SOPS_KMS_ARN** 环境变量中。建议至少使用两个位于不同区域的主密钥。
.. code:: bash
```
export SOPS_KMS_ARN="arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e,arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d"
```
SOPS 使用 `aws-sdk-go-v2 `_ 与 AWS KMS 通信。它会自动从 ``~/.aws/credentials`` 文件中读取凭证,该文件可以使用 ``aws configure`` 命令创建。
下面是 ``~/.aws/credentials`` 文件的一个示例:
.. code:: sh
```
$ cat ~/.aws/credentials
[default]
aws_access_key_id = AKI.....
aws_secret_access_key = mw......
```
除了 ``~/.aws/credentials`` 文件外,您还可以使用 ``AWS_ACCESS_KEY_ID`` 和 ``AWS_SECRET_ACCESS_KEY`` 环境变量来指定您的凭证:
.. code:: bash
```
export AWS_ACCESS_KEY_ID="AKI......"
export AWS_SECRET_ACCESS_KEY="mw......"
```
有关更多信息和额外的环境变量,请参阅 `specifying credentials `_。
如果您想使用 PGP,请将公钥的指纹(以逗号分隔)导出到 **SOPS_PGP_FP** 环境变量中。
.. code:: bash
```
export SOPS_PGP_FP="85D77543B3D624B63CEA9E6DBC17301B491B3F21,E60892BB9BD89A69F759A1A0A3D652173B763E8F"
```
注意:您可以同时使用 PGP 和 KMS。
然后只需以文件路径为参数调用 ``sops edit``。它将透明地处理加密/解密并在编辑器中打开明文文件
.. code:: sh
```
$ sops edit mynewtestfile.yaml
mynewtestfile.yaml doesn't exist, creating it.
please wait while an encryption key is being generated and stored in a secure fashion
file written to mynewtestfile.yaml
```
编辑将在 ``$SOPS_EDITOR`` 或 ``$EDITOR`` 设置的任何编辑器中进行,如果未设置,则使用 vim、nano 或 vi。
请记住,SOPS 将等待编辑器退出,然后尝试重新加密文件。某些 GUI 编辑器(atom、sublime)会生成子进程然后立即退出。它们通常有一个选项,可以在退出前等待主编辑器窗口关闭。有关更多信息,请参阅 `#127 `_。
生成的加密文件如下所示:
.. code:: 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-----
```
加密/解密密钥的副本安全地存储在每个 KMS 和 PGP 块中。只要其中一种 KMS 或 PGP 方法仍可用,您就能够访问您的数据。
要以 ``cat`` 方式解密文件,请使用 ``-d`` 标志:
.. code:: sh
```
$ sops decrypt mynewtestfile.yaml
```
SOPS 加密文件包含解密其内容所需的信息。SOPS 用户只需要有效的 AWS 凭证和对 KMS 密钥的必要权限。
鉴于此,SOPS 用户只需要以下命令:
.. code:: sh
```
$ sops edit
```
`` 将被打开、解密、传递给文本编辑器(默认为 vim)、如果被修改则加密,并保存回其原始位置。除了实际编辑外,所有这些步骤对用户都是透明的。
可以尝试可用解密方法的顺序可以通过 ``--decryption-order`` 选项或 **SOPS_DECRYPTION_ORDER** 环境变量指定,以逗号分隔的列表形式。默认顺序是 ``age,pgp``。首先尝试离线方法,然后是其余方法。
### 使用开发 PGP 密钥进行测试
如果您想测试 **SOPS** 而无需进行大量设置,可以使用仓库中提供的示例文件和 pgp 密钥:
```
$ git clone https://github.com/getsops/sops.git
$ cd sops
$ gpg --import pgp/sops_functional_tests_key.asc
$ sops edit example.yaml
```
最后这一步将使用测试私钥解密 ``example.yaml``。
### 使用 GnuPG 子密钥加密
如果您想使用特定的 GnuPG 子密钥进行加密,仅向 SOPS 提供子密钥的确切密钥 ID 是不够的,因为 GnuPG 可能会使用 *另一个* 子密钥来加密文件密钥。要强制 GnuPG 使用特定的子密钥,您需要在密钥指纹后附加 ``!``。
.. code:: yaml
```
creation_rules:
- pgp: >-
85D77543B3D624B63CEA9E6DBC17301B491B3F21!,
E60892BB9BD89A69F759A1A0A3D652173B763E8F!
```
请注意,自 SOPS 3.9.3 起,此功能才正确传递给 GnuPG。
### 使用 age 加密
`age `_ 是一个简单、现代且安全的文件加密工具。如果可能,建议使用 age 代替 PGP。
您可以使用 ``--age`` 选项或 **SOPS_AGE_RECIPIENTS** 环境变量为一个或多个 age 接收者(以逗号分隔)加密文件:
.. code:: sh
```
$ sops encrypt --age age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw test.yaml > test.enc.yaml
```
当使用相应的身份解密文件时,SOPS 将在用户配置目录的 ``sops`` 子目录中查找名为 ``keys.txt`` 的文本文件。
- **Linux**
- 在 ``$XDG_CONFIG_HOME/sops/age/keys.txt`` 中查找 ``keys.txt``;
- 如果未设置 ``$XDG_CONFIG_HOME``,则回退到 ``$HOME/.config/sops/age/keys.txt``。
- **macOS**
- 在 ``$XDG_CONFIG_HOME/sops/age/keys.txt`` 中查找 ``keys.txt``;
- 如果未设置 ``$XDG_CONFIG_HOME``,则回退到 ``$HOME/Library/Application Support/sops/age/keys.txt``。
- **Windows**
- 在 `%AppData%\\sops\\age\\keys.txt`` 中查找 ``keys.txt``。
您可以通过以下方式覆盖默认查找:
- 设置环境变量 **SOPS_AGE_KEY_FILE**;
- 设置 **SOPS_AGE_KEY** 环境变量;
- 通过设置 **SOPS_AGE_KEY_CMD** 环境变量来提供输出 age 密钥的命令。
此命令可以从 **SOPS_AGE_RECIPIENT** 环境变量中读取要返回私钥的 age 接收者。
此密钥文件的内容应为 age X25519 身份列表,每行一个。以 ``#`` 开头的行被视为注释并被忽略。将依次尝试每个身份,直到其中一个能够解密数据。
SOPS 还支持通过 age 使用 SSH 密钥加密。在加密文件时,您可以使用 SSH 公钥("ssh-ed25519 AAAA...","ssh-rsa AAAA...")作为 age 接收者。
解密文件时,SOPS 将尝试按以下方式获取 SSH 私钥:
- 从环境变量 **SOPS_AGE_SSH_PRIVATE_KEY_FILE** 中指定的路径。
- 从环境变量 **SOPS_AGE_SSH_PRIVATE_KEY_CMD** 中指定的命令的输出。
.. note:: 此命令的输出必须提供未受密码保护的密钥。
- 从 ``~/.ssh/id_ed25519``。
- 从 ``~/.ssh/id_rsa``。
请注意,仅支持 ``ssh-rsa`` 和 ``ssh-ed25519``。
可以将 age 接收者列表添加到 ``.sops.yaml`` 中:
.. code:: yaml
```
creation_rules:
- age: >-
age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c,
age1qe5lxzzeppw5k79vxn3872272sgy224g2nzqlzy3uljs84say3yqgvd0sw
```
在添加或删除 age 接收者时,也可以使用 ``updatekeys``。例如:
.. code:: sh
$ sops updatekeys secret.enc.yaml
2022/02/09 16:32:02 Syncing keys for file /iac/solution1/secret.enc.yaml
The following changes will be made to the file's groups:
Group 1
age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
+++ age1qe5lxzzeppw5k79vxn3872272sgy224g2nzqlzy3uljs84say3yqgvd0sw
Is this okay? (y/n):y
2022/02/09 16:32:04 File /iac/solution1/secret.enc.yaml synced with new keys
### 使用 GCP KMS 加密
GCP KMS 支持使用 `Application Default Credentials `_ 和 OAuth 2.0 token 进行授权。
应用程序默认凭证优先于访问令牌使用。
使用应用程序默认凭证,您可以通过以下方式进行授权:
如果您已经使用以下方式登录
.. code:: sh
```
$ gcloud auth login
```
您可以使用 sdk 启用应用程序默认凭证:
.. code:: sh
```
$ gcloud auth application-default login
```
使用 OAuth tokens,您可以通过以下方式进行授权:
.. code:: sh
```
$ export GOOGLE_OAUTH_ACCESS_TOKEN=
```
或者,如果您已登录,则可以通过生成访问令牌进行授权:
.. code:: sh
```
$ export GOOGLE_OAUTH_ACCESS_TOKEN="$(gcloud auth print-access-token)"
```
默认情况下,SOPS 使用 gRPC 客户端与 GCP KMS 通信。您可以选择通过设置 ``SOPS_GCP_KMS_CLIENT_TYPE`` 环境变量来切换到 REST 客户端:
.. code:: sh
```
$ export SOPS_GCP_KMS_CLIENT_TYPE=rest # Use REST client
$ export SOPS_GCP_KMS_CLIENT_TYPE=grpc # Use gRPC client (default)
```
使用 GCP KMS 进行加密/解密需要 KMS ResourceID。您可以使用云控制台获取 ResourceID,或者使用 gcloud sdk 创建一个:
.. code:: sh
```
$ gcloud kms keyrings create sops --location global
$ gcloud kms keys create sops-key --location global --keyring sops --purpose encryption
$ gcloud kms keys list --location global --keyring sops
# 你应该看到
NAME PURPOSE PRIMARY_STATE
projects/my-project/locations/global/keyRings/sops/cryptoKeys/sops-key ENCRYPT_DECRYPT ENABLED
```
现在您可以使用以下命令加密文件:
```
$ sops encrypt --gcp-kms projects/my-project/locations/global/keyRings/sops/cryptoKeys/sops-key test.yaml > test.enc.yaml
```
并使用以下命令解密它:
```
$ sops decrypt test.enc.yaml
```
### 使用 Azure Key Vault 加密
Azure Key Vault 集成使用 `default credential chain `_,它会按此顺序尝试几种身份验证方法:
1. `Environment credentials `_
i. 带有客户端密密的服务主体
ii. 带有证书的服务主体
iii. 带有用户名和密码的用户
iv. 多租户应用程序的配置
2. `Workload Identity credentials `_
3. `Managed Identity credentials `_
4. `Azure CLI credentials `_
例如,您可以使用以下环境变量的服务主体:
.. code:: bash
```
AZURE_TENANT_ID
AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
```
您可以像这样使用 CLI 创建服务主体:
.. code:: sh
```
$ az ad sp create-for-rbac -n my-keyvault-sp
{
"appId": "",
"displayName": "my-keyvault-sp",
"name": "http://my-keyvault-sp",
"password": "",
"tenant": ""
}
```
`appId` 是客户端 ID,`password` 是客户端密钥。
使用 Azure Key Vault 进行加密/解密需要密钥的资源标识符。其格式如下:
```
https://${VAULT_URL}/keys/${KEY_NAME}/${KEY_VERSION}
```
您可以省略版本,只保留一个尾部斜杠,这将使用密钥的最新版本:
```
https://${VAULT_URL}/keys/${KEY_NAME}/
```
要从命令行创建 Key Vault 并为其分配服务主体权限:
.. code:: sh
```
# 如果你没有资源组,请创建一个:
$ az group create --name sops-rg --location westeurope
# Key Vault 名称是全局唯一的,因此请生成一个:
$ keyvault_name=sops-$(uuidgen | tr -d - | head -c 16)
# 创建 Vault、密钥,并授予 service principal 访问权限:
$ az keyvault create --name $keyvault_name --resource-group sops-rg --location westeurope
$ az keyvault key create --name sops-key --vault-name $keyvault_name --protection software --ops encrypt decrypt
$ az keyvault set-policy --name $keyvault_name --resource-group sops-rg --spn $AZURE_CLIENT_ID \
--key-permissions encrypt decrypt
# 读取 key id:
$ az keyvault key show --name sops-key --vault-name $keyvault_name --query key.kid
https://sops.vault.azure.net/keys/sops-key/some-string
```
现在您可以使用以下命令加密文件:
```
$ sops encrypt --azure-kv https://sops.vault.azure.net/keys/sops-key/some-string test.yaml > test.enc.yaml
```
或者,不带版本:
```
$ sops encrypt --azure-kv https://sops.vault.azure.net/keys/sops-key/ test.yaml > test.enc.yaml
```
并使用以下命令解密它:
```
$ sops decrypt test.enc.yaml
```
### 从其他程序加密和解密
在脚本或其他程序中使用 ``sops`` 时,经常会有不希望将加密或解密的数据写入磁盘的情况。避免这种情况的最佳方法是通过 stdin 将数据传递给 SOPS,并让 SOPS 将数据写入 stdout。默认情况下,加密和解密操作已经将数据写入 stdout。要通过 stdin 传递数据,您不需要提供输入文件名。对于加密,您还必须提供带有文件名的 ``--filename-override`` 选项。文件名将用于确定输入和输出类型,并选择正确的创建规则。
从 stdin 解密数据的最简单方法如下:
.. code:: sh
```
$ cat encrypted-data | sops decrypt > decrypted-data
```
默认情况下,``sops`` 根据提供的文件名确定输入和输出格式。由于在这种情况下未提供文件名,``sops`` 将使用二进制存储,该存储期望 JSON 输入并在解密时输出二进制数据。这通常不是您想要的。
为了避免这种情况,您可以提供带有 ``--filename-override`` 的文件名,或者通过适当地传递 ``--input-type`` 和 ``--output-type`` 来显式控制输入和输出格式:
.. code:: sh
```
$ cat encrypted-data | sops decrypt --filename-override filename.yaml > decrypted-data
$ cat encrypted-data | sops decrypt --input-type yaml --output-type yaml > decrypted-data
```
在这两种情况下,``sops`` 都会假设您提供是 YAML 格式,并且也会将解密后的数据编码为 YAML。第二种形式允许对输入和输出使用不同的格式。
对于加密,需要注意的是,SOPS 也使用文件名从 ``.sops.yaml`` 中查找正确的创建规则。因此,您必须提供 ``--filename-override`` 参数,该参数允许您告诉 SOPS 使用哪个文件名来匹配创建规则:
.. code:: sh
```
$ echo 'foo: bar' | sops encrypt --filename-override path/filename.sops.yaml > encrypted-data
```
SOPS 将在 ``.sops.yaml`` 中找到与 ``path/filename.sops.yaml`` 匹配的创建规则,并使用该规则加密来自 stdin 的数据。此文件名也将用于确定输入和输出存储。一如既往,可以通过传递 ``--input-type`` 来调整输入存储类型,通过传递 ``--output-type`` 来调整输出存储类型:
.. code:: sh
```
$ echo foo=bar | sops encrypt --filename-override path/filename.sops.yaml --input-type dotenv > encrypted-data
```
### 使用 Hashicorp Vault 加密
我们假设您有一个(或多个)Vault 实例正在运行,并且您对其拥有特权访问权限。有关如何部署安全的 Vault 实例的说明,请参阅 Hashicorp 的官方文档。
要在本地轻松部署 Vault:(请勿在生产环境中执行此操作!!!)
.. code:: sh
```
$ docker run -d -p8200:8200 vault:1.2.0 server -dev -dev-root-token-id=toor
```
.. code:: sh
```
$ # Substitute this with the address Vault is running on
$ export VAULT_ADDR=http://127.0.0.1:8200
$ # this may not be necessary in case you previously used `vault login` for production use
$ export VAULT_TOKEN=toor
$ # to check if Vault started and is configured correctly
$ vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 1
Threshold 1
Version 1.2.0
Cluster Name vault-cluster-618cc902
Cluster ID e532e461-e8f0-1352-8a41-fc7c11096908
HA Enabled false
$ # It is required to enable a transit engine if not already done (It is suggested to create a transit engine specifically for SOPS, in which it is possible to have multiple keys with various permission levels)
$ vault secrets enable -path=sops transit
Success! Enabled the transit secrets engine at: sops/
$ # Then create one or more keys
$ vault write sops/keys/firstkey type=rsa-4096
Success! Data written to: sops/keys/firstkey
$ vault write sops/keys/secondkey type=rsa-2048
Success! Data written to: sops/keys/secondkey
$ vault write sops/keys/thirdkey type=chacha20-poly1305
Success! Data written to: sops/keys/thirdkey
$ sops encrypt --hc-vault-transit $VAULT_ADDR/v1/sops/keys/firstkey vault_example.yml
$ cat < .sops.yaml
creation_rules:
- path_regex: \.dev\.yaml$
hc_vault_transit_uri: "$VAULT_ADDR/v1/sops/keys/secondkey"
- path_regex: \.prod\.yaml$
hc_vault_transit_uri: "$VAULT_ADDR/v1/sops/keys/thirdkey"
EOF
$ sops encrypt --verbose prod/raw.yaml > prod/encrypted.yaml
```
### 使用 HuaweiCloud KMS 加密
HuaweiCloud KMS 集成使用 `default credential provider chain `_,它会按此顺序尝试几种身份验证方法:
1. 环境变量:``HUAWEICLOUD_SDK_AK``,``HUAWEICLOUD_SDK_SK``,``HUAWEICLOUD_SDK_PROJECT_ID``
2. 位于 ``~/.huaweicloud/credentials`` 的凭证文件
3. 实例元数据(在 HuaweiCloud 实例上运行时)
例如,您可以使用环境变量:
.. code:: bash
```
export HUAWEICLOUD_SDK_AK="your-access-key"
export HUAWEICLOUD_SDK_SK="your-secret-key"
export HUAWEICLOUD_SDK_PROJECT_ID="your-project-id"
```
或者,您可以在 ``~/.huaweicloud/credentials`` 创建一个凭证文件:
.. code:: sh
```
$ cat ~/.huaweicloud/credentials
[default]
ak = your-access-key
sk = your-secret-key
project_id = your-project-id
```
使用 HuaweiCloud KMS 进行加密/解密需要格式为 ``region:key-uuid`` 的 KMS 密钥 ID。您可以从 HuaweiCloud 控制台或使用 HuaweiCloud API 获取密钥 ID。密钥 ID 格式为 ``region:key-uuid``,其中:
- ``region`` 是 HuaweiCloud 区域(例如 ``tr-west-1``,``cn-north-1``)
- ``key-uuid`` 是 KMS 密钥的 UUID(例如 ``abc12345-6789-0123-4567-890123456789``)
现在您可以使用以下命令加密文件:
.. code:: sh
```
$ sops encrypt --hckms tr-west-1:abc12345-6789-0123-4567-890123456789 test.yaml > test.enc.yaml
```
或者使用环境变量:
.. code:: sh
```
$ export SOPS_HUAWEICLOUD_KMS_IDS="tr-west-1:abc12345-6789-0123-4567-890123456789"
$ sops encrypt test.yaml > test.enc.yaml
```
并使用以下命令解密它:
.. code:: sh
```
$ sops decrypt test.enc.yaml
```
您也可以在 ``.sops.yaml`` 配置文件中配置 HuaweiCloud KMS 密钥:
.. code:: yaml
```
creation_rules:
- path_regex: \.hckms\.yaml$
hckms:
- tr-west-1:abc12345-6789-0123-4567-890123456789,tr-west-2:def67890-1234-5678-9012-345678901234
```
### 添加和删除密钥
创建新文件时,``sops`` 使用命令行参数 ``--kms``、``--pgp``、``--gcp-kms``、``--hckms`` 或 ``--azure-kv`` 中定义的 PGP、KMS 和 GCP KMS,或者从环境变量 ``SOPS_KMS_ARN``、``SOPS_PGP_FP``、``SOPS_GCP_KMS_IDS``、``SOPS_HUAWEICLOUD_KMS_IDS``、``SOPS_AZURE_KEYVAULT_URLS`` 中获取。该信息存储在文件的 ``sops`` 部分下,这样解密文件就不需要再次提供这些参数。
主 PGP 和 KMS 密钥可以通过以下三种方式之一从 ``sops`` 文件中添加或删除:
1. 通过使用 ``.sops.yaml`` 文件和 ``updatekeys`` 命令。
2. 通过使用命令行标志。
3. 通过直接编辑文件。
SOPS 团队推荐使用 ``updatekeys`` 方法。
## ``updatekeys`` 命令
``updatekeys`` 命令使用 `.sops.yaml <#using-sops-yaml-conf-to-select-kms-pgp-for-new-files>`_ 配置文件来更新(添加或删除)加密文件中的相应密钥。请注意,下面的示例使用 `Block Scalar yaml construct `_ 来构建以空格分隔的列表。
.. code:: yaml
```
creation_rules:
- pgp: >-
85D77543B3D624B63CEA9E6DBC17301B491B3F21,
FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4
```
.. code:: sh
```
$ sops updatekeys test.enc.yaml
```
SOPS 将提示您确认要进行的更改。可以通过提供 ``-y`` 标志来禁用此交互。
## ``rotate`` 命令
``rotate`` 命令生成一个新的数据加密密钥,并使用新密钥重新加密所有值。同时,命令行标志 ``--add-kms``、``--add-pgp``、``--add-gcp-kms``、``--add-hckms``、``--add-azure-kv``、``--rm-kms``、``--rm-pgp``、``--rm-gcp-kms``、``--rm-hckms`` 和 ``--rm-azure-kv`` 可用于从文件中添加和删除密钥。这些标志在创建新文件时使用与 ``--kms``、``--pgp``、``--gcp-kms``、``--hckms`` 和 ``--azure-kv`` 参数相同的逗号分隔语法。
如果您想在不轮换数据密钥的情况下添加密钥,请使用 ``updatekeys``。
.. code:: sh
```
# 向文件添加新的 pgp key 并轮换 data key
$ sops rotate -i --add-pgp 85D77543B3D624B63CEA9E6DBC17301B491B3F21 example.yaml
# 从文件中移除 pgp key 并轮换 data key
$ sops rotate -i --rm-pgp 85D77543B3D624B63CEA9E6DBC17301B491B3F21 example.yaml
```
## 直接编辑
或者,在调用 ``sops edit`` 时使用 **-s** 标志将在编辑时显示主密钥。此方法可用于在 ``sops`` 部分下添加或删除 ``kms`` 或 ``pgp`` 密钥。
例如,要向文件添加 KMS 主密钥,请在编辑时添加以下条目:
.. code:: yaml
```
sops:
kms:
- arn: arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
```
同样,要添加 PGP 主密钥,我们添加其指纹:
.. code:: yaml
```
sops:
pgp:
- fp: 85D77543B3D624B63CEA9E6DBC17301B491B3F21
```
保存文件时,SOPS 将更新其元数据并使用新添加的主密钥加密数据密钥。被删除的条目只是从文件中删除。
删除密钥时,建议使用 ``-r`` 轮换数据密钥,否则,被删除密钥的所有者可能在过去已经访问过数据密钥。
### KMS AWS Profiles
如果您想使用特定的配置文件,可以使用 `aws_profile`:
.. code:: yaml
```
sops:
kms:
- arn: arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
aws_profile: foo
```
如果未设置 AWS 配置文件,将使用默认凭证。
同样,在任何 KMS 命令中,可以在命令行中设置 `--aws-profile` 标志。
### 在各种 AWS 账户中担任角色和使用 KMS
SOPS 能够通过在每个账户中担任角色来使用多个 AWS 账户中的 KMS。能够担任角色是 AWS 的一个很好的功能,它允许管理员在账户之间建立信任关系,通常是从最安全的账户到最不安全的账户。在我们的用例中,我们使用角色来表示允许 Master AWS 账户的用户使用开发和暂存 AWS 账户中的 KMS 主密钥。使用角色,单个文件可以使用多个账户中的 KMS 密钥进行加密,从而提高了可靠性和易用性。
您可以通过将每个 KMS 主密钥绑定到允许用户在每个账户中担任的角色来使用各种账户中的密钥。`IAM roles `_ 文档详细介绍了如何在 AWS 端进行配置。
从 SOPS 的角度来看,您只需要指定 KMS 密钥必须与其 ARN 一起担任的角色,如下所示:
.. code:: yaml
```
sops:
kms:
- arn: arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
role: arn:aws:iam::927034868273:role/sops-dev-xyz
```
该角色必须具有使用 KMS 调用 Encrypt 和 Decrypt 的权限。下面显示了一个示例策略。
.. code:: json
```
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Principal": {
"AWS": [
"arn:aws:iam::927034868273:role/sops-dev-xyz"
]
}
}
```
您可以通过将角色附加到主密钥的 ARN(用 **+** 号分隔)来在 ``--kms`` 标志和 ``SOPS_KMS_ARN`` 变量中指定角色:
```
+
arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500+arn:aws:iam::927034868273:role/sops-dev-xyz
```
### AWS KMS Encryption Context
SOPS 能够使用 `AWS KMS key policy and encryption context `_ 来细化对给定 KMS 主密钥的访问控制。
创建新文件时,可以通过以逗号分隔的键值对列表在 ``--encryption-context`` 标志中指定加密上下文:
.. code:: sh
```
$ sops edit --encryption-context Environment:production,Role:web-server test.dev.yaml
```
Encrypt Context 字符串的格式为 ``:,:,...``
加密上下文将存储在文件元数据中,解密时不需要提供。
加密上下文可以与 KMS Key Policies 结合使用,以定义只能访问给定上下文的角色。下面显示了一个示例策略:
.. code:: json
```
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/RoleForExampleApp"
},
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:EncryptionContext:AppName": "ExampleApp",
"kms:EncryptionContext:FilePath": "/var/opt/secrets/"
}
}
}
```
### 密钥轮换
建议定期更新数据密钥。``sops`` 通过 ``rotate`` 命令支持密钥轮换。对现有文件调用它会导致 ``sops`` 使用新数据密钥重新加密文件,然后使用文件中定义的各种 KMS 和 PGP 主密钥加密该数据密钥。
添加 ``-i`` 选项将轮换后的文件写回,而不是将其打印到 stdout。
.. code:: sh
```
$ sops rotate example.yaml
```
### 使用 .sops.yaml conf 为新文件选择 KMS、PGP 和 age
为所有新文件的创建指定 ``--kms`` ``--gcp-kms`` ``--hckms`` ``--pgp`` 和 ``--age`` 参数通常很繁琐。如果您的密钥存储在特定目录下(如 ``git`` 仓库),您可以在根目录下创建一个 ``.sops.yaml`` 配置文件来定义哪些密钥用于哪些文件名。
.. note::
文件需要命名为 ``.sops.yaml``。其他名称(即 ``.sops.yml``)不会被 SOPS 自动发现。您需要传递 ``--config .sops.yml`` 选项才能使其被拾取。
让我们举个例子:
* 名为 **something.dev.yaml** 的文件应使用一组 KMS A、PGP 和 age
* 名为 **something.prod.yaml** 的文件应使用另一组 KMS B、PGP 和 age
* 其他文件使用第三组 KMS C 和 PGP
* 所有文件都位于 **mysecretrepo/something.{dev,prod,gcp}.yaml** 下
在这些情况下,放置在 **mysecretrepo/.sops.yaml** 的文件可以管理三种类型文件的三组配置:
.. code:: yaml
```
# creation rules 按顺序评估,首个匹配项生效
creation_rules:
# upon creation of a file that matches the pattern *.dev.yaml,
# KMS set A as well as PGP and age is used
- path_regex: \.dev\.yaml$
kms: 'arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500,arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e+arn:aws:iam::361527076523:role/hiera-sops-prod'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
age: 'age129h70qwx39k7h5x6l9hg566nwm53527zvamre8vep9e3plsm44uqgy8gla'
# prod files use KMS set B in the PROD IAM, PGP and age
- path_regex: \.prod\.yaml$
kms: 'arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e+arn:aws:iam::361527076523:role/hiera-sops-prod,arn:aws:kms:eu-central-1:361527076523:key/cb1fab90-8d17-42a1-a9d8-334968904f94+arn:aws:iam::361527076523:role/hiera-sops-prod'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
age: 'age129h70qwx39k7h5x6l9hg566nwm53527zvamre8vep9e3plsm44uqgy8gla'
hc_vault_uris: "http://localhost:8200/v1/sops/keys/thirdkey"
# gcp files using GCP KMS
- path_regex: \.gcp\.yaml$
gcp_kms: projects/mygcproject/locations/global/keyRings/mykeyring/cryptoKeys/thekey
# hckms files using HuaweiCloud KMS
- path_regex: \.hckms\.yaml$
hckms: tr-west-1:abc12345-6789-0123-4567-890123456789,tr-west-2:def67890-1234-5678-9012-345678901234
# Finally, if the rules above have not matched, this one is a
# catchall that will encrypt the file using KMS set C as well as PGP
# The absence of a path_regex means it will match everything
- kms: 'arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500,arn:aws:kms:us-west-2:142069644989:key/846cfb17-373d-49b9-8baf-f36b04512e47,arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
```
在 **mysecretrepo** 下创建任何文件时,无论是在根目录还是子目录下,SOPS 都会递归查找 ``.sops.yaml`` 文件。如果找到一个,则将要创建的文件的文件名与配置文件的文件名正则表达式进行比较。选择第一个匹配的正则表达式,并使用其 KMS 和 PGP 密钥来加密文件。需要注意的是,``.sops.yaml`` 的查找是从工作目录 (CWD) 开始的,而不是从加密文件的目录开始(参见 `Issue 242 `_)。
``path_regex`` 检查加密文件相对于 ``.sops.yaml`` 配置文件的路径。这是另一个例子:
* 位于目录 **development** 下的文件应使用一组 KMS A
* 位于目录 **production** 下的文件应使用另一组 KMS B
* 其他文件使用第三组 KMS C
.. code:: yaml
```
creation_rules:
# upon creation of a file under development,
# KMS set A is used
- path_regex: .*/development/.*
kms: 'arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500,arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e+arn:aws:iam::361527076523:role/hiera-sops-prod'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
# prod files use KMS set B in the PROD IAM
- path_regex: .*/production/.*
kms: 'arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e+arn:aws:iam::361527076523:role/hiera-sops-prod,arn:aws:kms:eu-central-1:361527076523:key/cb1fab90-8d17-42a1-a9d8-334968904f94+arn:aws:iam::361527076523:role/hiera-sops-prod'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
# other files use KMS set C
- kms: 'arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500,arn:aws:kms:us-west-2:142069644989:key/846cfb17-373d-49b9-8baf-f36b04512e47,arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e'
pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4'
```
现在创建一个具有正确密钥的新文件非常简单
.. code:: sh
```
$ sops edit .prod.yaml
```
请注意,如果在 SOPS 命令行或环境变量中传递了 KMS 或 PGP 参数,则会忽略配置文件。
### 指定不同的 GPG 可执行文件
SOPS 检查 ``SOPS_GPG_EXEC`` 环境变量。如果指定,它将尝试使用那里设置的可执行文件,而不是默认的 ``gpg``。
示例:将以下内容放入您的 ``~/.bashrc``
.. code:: bash
```
SOPS_GPG_EXEC = 'your_gpg_client_wrapper'
```
### 密钥组
默认情况下,SOPS 使用每个主密钥加密文件的数据密钥,这样如果任何主密钥可用,就可以解密文件。
但是,有时需要访问多个主密钥才能解密文件。这可以通过密钥组来实现。
在 SOPS 中使用密钥组时,数据密钥被分成多个部分,以便需要来自多个组的密钥才能解密文件。SOPS 使用 Shamir's Secret Sharing 来分割数据密钥,使每个密钥组拥有一个片段,该组中的每个密钥都可以解密该片段,并且需要可配置数量的片段(阈值)来解密并拼凑完整的数据密钥。使用多个密钥组解密文件时,SOPS 会按顺序遍历密钥组,并在每个组中尝试使用该组的主密钥恢复数据密钥的片段。一旦恢复了片段,SOPS 就会移动到下一个组,直到恢复了足够的片段以获得完整的数据密钥。
默认情况下,阈值设置为密钥组的数量。例如,如果您在 SOPS 文件中配置了三个密钥组,并且您没有覆盖默认阈值,则需要来自这三个组中每个组的一个主密钥才能解密文件。
密钥组的管理是通过 ``sops groups`` 命令完成的。
例如,您可以将具有3 个 PGP 密钥和 3 个 KMS 密钥的新密钥组添加到文件 ``my_file.yaml`` 中:
.. code:: sh
```
$ sops groups add --file my_file.yaml --pgp fingerprint1 --pgp fingerprint2 --pgp fingerprint3 --kms arn1 --kms arn2 --kms arn3
```
或者您可以从 ``my_file.yaml`` 中删除第 1 个组(组号 0,因为组是从零开始索引的):
.. code:: sh
```
$ sops groups delete --file my_file.yaml 0
```
密钥组也可以在 ``.sops.yaml`` 配置文件中指定,如下所示:
.. code:: yaml
```
creation_rules:
- path_regex: .*keygroups.*
key_groups:
# First key group
- pgp:
- fingerprint1
- fingerprint2
kms:
- arn: arn1
role: role1
context:
foo: bar
- arn: arn2
aws_profile: myprofile
# Second key group
- pgp:
- fingerprint3
- fingerprint4
kms:
- arn: arn3
- arn: arn4
# Third key group
- pgp:
- fingerprint5
```
有了这个配置,我们可以像往常一样创建一个新的加密文件,并且可以选择提供 ``--shamir-secret-sharing-threshold`` 命令行标志来覆盖默认阈值。然后,SOPS 会将数据密钥分成三个部分(根据密钥组的数量)并使用在每个组中找到的主密钥加密每个片段。
例如:
.. code:: sh
```
$ sops edit --shamir-secret-sharing-threshold 2 example.json
```
或者,您可以在 ``.sops.yaml`` 配置中使用 ``shamir_threshold`` 为每个创建规则配置 Shamir 阈值:
.. code:: yaml
```
creation_rules:
- path_regex: .*keygroups.*
shamir_threshold: 2
key_groups:
# First key group
- pgp:
- fingerprint1
- fingerprint2
kms:
- arn: arn1
role: role1
context:
foo: bar
- arn: arn2
aws_profile: myprofile
# Second key group
- pgp:
- fingerprint3
- fingerprint4
kms:
- arn: arn3
- arn: arn4
# Third key group
- pgp:
- fingerprint5
```
然后运行 ``sops edit example.json``。
阈值(``shamir_threshold``)设置为 2,因此此配置将需要来自三个不同密钥组中其中两个的主密钥才能解密文件。
然后您可以像解密任何其他 SOPS 文件一样解密文件:
.. code:: sh
```
$ sops decrypt example.json
```
### 密钥服务
在某些情况下,您可能希望在没有直接访问 PGP 密钥等加密密钥的机器上运行 SOPS。``sops`` 密钥服务允许您转发套接字,以便 SOPS 可以访问存储在远程机器上的加密密钥。这类似于 GPG Agent,但更便携。
SOPS 使用客户端-服务器方法来加密和解密数据密钥。默认情况下,SOPS 在进程中运行本地密钥服务。SOPS 使用密钥服务客户端向密钥服务发送加密或解密请求,然后由密钥服务执行操作。请求是使用 gRPC 和 Protocol Buffers 发送的。请求包含应执行操作的密钥标识符以及明文或加密的数据密钥。请求不包含任何加密密钥、公钥或私钥。
**警告:密钥服务连接当前不使用任何类型的身份验证或加密。因此,建议您确保以其他方式对连接进行身份验证和加密,例如通过 SSH 隧道。**
每当我们尝试加密或解密数据密钥时,SOPS 将首先尝试使用本地密钥服务(除非它被禁用),如果失败,它将尝试所有其他远程密钥服务,直到成功为止。
您可以通过运行 ``sops keyservice`` 启动密钥服务服务器。
您可以使用 ``--keyservice`` 选项指定 ``sops`` 二进制文件使用的密钥服务。此标志可以指定多次,因此您可以使用多个密钥服务。或者,可以通过设置 ``SOPS_KEYSERVICE`` 环境变量来指定单个密钥服务。可以使用 ``--enable-local-keyservice=false`` 或通过将 ``SOPS_ENABLE_LOCAL_KEYSERVICE`` 环境变量设置为 ``false`` 来禁用本地密钥服务。
例如,要使用本地密钥服务和位于 ``/tmp/sops.sock`` 的 unix 套接字上公开的密钥服务解密文件,您可以运行:
.. code:: sh
```
$ sops decrypt --keyservice unix:///tmp/sops.sock file.yaml
```
如果您只想使用位于 ``/tmp/sops.sock`` 的 unix 套接字上公开的密钥服务而不使用本地密钥服务,您可以运行:
.. code:: sh
```
$ sops decrypt --enable-local-keyservice=false --keyservice unix:///tmp/sops.sock file.yaml
```
### 审计
有时,用户希望在他们控制的环境中知道哪些文件被谁访问过。出于这个原因,SOPS 可以生成审计日志来记录加密文件上的活动。启用后,当文件被解密时,SOPS 会将日志条目写入预先配置的 PostgreSQL 数据库。日志包括时间戳、运行 SOPS 的用户名以及被解密的文件。
为了启用审计,您必须首先使用 ``audit/schema.sql`` 中的 schema 创建数据库和凭证。此 schema 定义了存储审计事件的表和一个名为 ``sops`` 的角色,该角色只有向审计事件表添加条目的权限。角色 ``sops`` 的默认密码是 ``sops``。您应该更改此密码。
创建数据库后,您必须告诉 SOPS 如何连接到它。因为我们不希望 SOPS 的用户能够控制审计,所以审计配置文件位置是不可配置的,必须位于 ``/etc/sops/audit.yaml``。此文件应具有严格的权限,以便只有 root 用户可以修改它。
例如,要启用对在 localhost 上运行、使用用户 ``sops`` 和密码 ``sops`` 的名为 ``sops`` 的 PostgreSQL 数据库的审计,``/etc/sops/audit.yaml`` 应具有以下内容:
.. code:: yaml
```
backends:
postgres:
- connection_string: "postgres://sops:sops@localhost/sops?sslmode=verify-full"
```
您可以在 `PostgreSQL docs `_ 中找到有关 ``connection_string`` 格式的更多信息。
在上面的 YAML 中的 ``postgres`` 映射条目下是一个列表,因此可以提供多个后端,SOPS 将记录到所有这些后端:
.. code:: yaml
```
backends:
postgres:
- connection_string: "postgres://sops:sops@localhost/sops?sslmode=verify-full"
- connection_string: "postgres://sops:sops@remotehost/sops?sslmode=verify-full"
```
### 将输出保存到文件
默认情况下,SOPS 只是将所有输出转储到标准输出。我们可以使用 ``--output`` 标志,后跟文件名,将输出保存到指定的文件。
注意,同时使用 ``--in-place`` 和 ``--output`` 标志将导致错误。
### 将 Secrets 传递给其他进程
除了将 secrets 写入标准输出和磁盘上的文件外,SOPS 还有两个命令用于将解密的 secrets 传递给新进程:``exec-env`` 和 ``exec-file``。这些命令将分别把所有输出放入子进程的环境中和临时文件中。例如,如果程序在其环境中查找凭证,则可以使用 ``exec-env`` 来确保解密的内容仅对该进程可用,并且永远不会写入磁盘。
.. code:: sh
```
# 将 secrets 打印到 stdout 以确认值
$ sops decrypt out.json
{
"database_password": "jf48t9wfw094gf4nhdf023r",
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
"AWS_SECRET_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
# 解密 out.json 并运行命令
# 该命令打印环境变量并运行一个使用它的脚本
$ sops exec-env out.json 'echo secret: $database_password; ./database-import'
secret: jf48t9wfw094gf4nhdf023r
# 启动一个在其环境中包含 secrets 的 shell
$ sops exec-env out.json 'sh'
sh-3.2# echo $database_password
jf48t9wfw094gf4nhdf023r
# 该 secret 在其他任何地方都无法访问
sh-3.2$ exit
$ echo your password: $database_password
your password:
```
如果您希望将进程信号发送到命令,例如,如果您正在运行 ``exec-env`` 来启动服务器并且您的服务器处理 SIGTERM,那么可以使用 ``--same-process`` 标志来指示 ``sops`` 在同一进程中而不是子进程中启动您的命令。这使用 ``execve`` 系统调用,并在类 Unix 系统上受支持。
如果您想运行的命令只对文件进行操作,您可以使用 ``exec-file``。默认情况下,SOPS 将使用 FIFO 将解密文件的内容传递给新程序。使用 FIFO,secrets 仅在内存中传递,这有两个好处:明文 secrets 永远不会触及磁盘,并且子进程只能读取一次 secrets。在不适用的环境中,例如在没有 FIFO 的 Windows 等平台上,或者需要长期提供给子进程的 secret 文件,可以使用 ``--no-fifo`` 标志来指示 SOPS 使用传统的临时文件,该文件将在进程执行完成后被清理。``exec-file`` 的行为类似于 ``find(1)``,因为 ``{}`` 用作命令中的占位符,该占位符将被替换为临时文件路径(无论是 FIFO 还是实际文件)。
.. code:: sh
```
# 操作与之前相同的文件,但这次作为文件
$ sops exec-file out.json 'echo your temporary file: {}; cat {}'
your temporary file: /tmp/.sops894650499/tmp-file
{
"database_password": "jf48t9wfw094gf4nhdf023r",
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
"AWS_SECRET_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
# 启动一个 shell,其中包含指向临时文件的变量 TMPFILE
$ sops exec-file --no-fifo out.json 'TMPFILE={} sh'
sh-3.2$ echo $TMPFILE
/tmp/.sops506055069/tmp-file291138648
sh-3.2$ cat $TMPFILE
{
"database_password": "jf48t9wfw094gf4nhdf023r",
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
"AWS_SECRET_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
sh-3.2$ ./program --config $TMPFILE
sh-3.2$ exit
# 尝试打开之前的临时文件
$ cat /tmp/.sops506055069/tmp-file291138648
cat: /tmp/.sops506055069/tmp-file291138648: No such file or directory
```
此外,在类 unix 平台上,``exec-env`` 和 ``exec-file`` 都支持在执行新程序之前通过 ``--user `` 标志降低权限。这在加密文件仅可由 root 读取但目标程序不需要 root 权限即可运行的情况下特别有用。应尽可能使用此标志以提高安全性。
要覆盖 ``exec-file`` 中的默认文件名 (``tmp-file``),请使用 ``--filename `` 参数。
.. code:: sh
```
# 当前用户无法读取该加密文件
$ cat out.json
cat: out.json: Permission denied
# 以 root 身份执行 sops,解密 secrets,然后放弃权限
$ sudo sops exec-env --user nobody out.json 'sh'
sh-3.2$ echo $database_password
jf48t9wfw094gf4nhdf023r
# 已放弃权限,仍然无法加载原始文件
sh-3.2$ id
uid=4294967294(nobody) gid=4294967294(nobody) groups=4294967294(nobody)
sh-3.2$ cat out.json
cat: out.json: Permission denied
```
### 使用 publish 命令
``sops publish $file`` 将文件发布到预先配置的目标(位于 SOPS 配置文件中)。此外,支持类似于创建规则的重加密规则。
此命令需要 ``.sops.yaml`` 配置文件。以下是一个示例:
.. code:: yaml
```
destination_rules:
- s3_bucket: "sops-secrets"
path_regex: s3/*
recreation_rule:
pgp: F69E4901EDBAD2D1753F8C67A64535C4163FB307
- gcs_bucket: "sops-secrets"
path_regex: gcs/*
recreation_rule:
pgp: F69E4901EDBAD2D1753F8C67A64535C4163FB307
- vault_path: "sops/"
vault_kv_mount_name: "secret/" # default
vault_kv_version: 2 # default
path_regex: vault/*
omit_extensions: true
```
上述配置将把 ``s3/*`` 下的所有文件放入 S3 存储桶 ``sops-secrets``,把 ``gcs/*`` 下的所有文件放入 GCS 存储桶 ``sops-secrets``,并将 ``vault/*`` 下所有文件的内容放入 Vault 的 KV 存储中的 ``secrets/sops/`` 路径下。对于将发布到 S3 和 GCS 的文件,它将解密它们并使用 ``F69E4901EDBAD2D1753F8C67A64535C4163FB307`` pgp 密钥重新加密它们。
您可以使用类似以下的命令将文件部署到 S3:``sops publish s3/app.yaml``
要递归发布所选目录中的所有文件,您需要指定 ``--recursive`` 标志。
如果您不希望文件扩展名出现在目标 secret 路径中,请使用 ``--omit-extensions`` 标志或 ``.sops.yaml`` 中目标规则中的 ``omit_extensions: true``。
## 发布到 Vault
您可以在目标规则中为 Vault 设置一些设置。第一个是 ``vault_path``,这是必需的。其他是可选的,它们是 ``vault_address``、``vault_kv_mount_name``、``vault_kv_version``。
SOPS 使用 Hashicorp 提供的官方 Vault API,该 API 使用 `environment variables `_ 来配置客户端。
如果您的 Vault KV 安装在 ``secret/`` 以外的位置,则使用 ``vault_kv_mount_name``。
``vault_kv_version`` 支持 ``1`` 和 ``2``,默认值为 ``2``。
如果目标 secret 路径已存在于 Vault 中并且包含与源文件相同的数据,则它将被跳过。
以下是发布到 Vault 的示例(使用带有本地 Vault 开发实例的 token 认证)。
.. code:: sh
```
$ export VAULT_TOKEN=...
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ sops decrypt vault/test.yaml
example_string: bar
example_number: 42
example_map:
key: value
$ sops publish vault/test.yaml
uploading /home/user/sops_directory/vault/test.yaml to http://127.0.0.1:8200/v1/secret/data/sops/test.yaml ? (y/n): y
$ vault kv get secret/sops/test.yaml
====== Metadata ======
Key Value
--- -----
created_time 2019-07-11T03:32:17.074792017Z
deletion_time n/a
destroyed false
version 3
========= Data =========
Key Value
--- -----
example_map map[key:value]
example_number 42
example_string bar
```
## 关于类型的重要信息
### YAML, JSON, ENV 和 INI 类型扩展
SOPS 使用文件扩展名来决定对文件内容使用哪种加密方法。``YAML``、``JSON``、``ENV`` 和 ``INI`` 文件被视为数据树,并从文件中提取键/值以仅加密叶值。树结构也用于检查文件的完整性。
因此,如果使用特定格式加密文件,则需要以相同的格式解密。实现这一点的最简单方法是在加密文件后保留原始文件扩展名。例如:
.. code:: sh
```
$ sops encrypt -i myfile.json
$ sops decrypt myfile.json
```
如果您想在文件加密后更改文件的扩展名,则需要在解密时为 ``sops`` 提供 ``--input-type`` 标志。例如:
.. code:: sh
```
$ sops encrypt myfile.json > myfile.json.enc
$ sops decrypt --input-type json myfile.json.enc
```
在 stdin 上操作时,请按如下方式使用 ``--input-type`` 和 ``--output-type`` 标志:
.. code:: sh
```
$ cat myfile.json | sops decrypt --input-type json --output-type json
```
### JSON 和 JSON_binary 缩进
默认情况下,SOPS 使用一个 ``tab`` 缩进 ``JSON`` 文件。但是,您可以通过使用额外的 ``--indent=2`` CLI 选项或在 ``.sops.yaml`` 中使用以下代码配置来将此默认行为更改为使用 ``spaces``。
特殊值 ``0`` 禁用缩进,``-1`` 使用单个制表符。
.. code:: yaml
stores:
json:
indent: 2
json_binary:
indent: 2
### YAML 缩进
默认情况下,SOPS 使用 4 个空格缩进 ``YAML`` 文件。但是,您可以通过使用额外的 ``--indent=2`` CLI 选项或在 ``.sops.yaml`` 中配置来更改此默认行为:
.. code:: yaml
stores:
yaml:
indent: 2
.. note::
SOPS 使用的 YAML emitter 仅支持 2 到 9 之间的值。如果您指定 1 或 10 及更大的值,缩进将为 2。
### YAML anchors
SOPS 仅支持 ``YAML`` 众多类型的一个子集。加密包含字符串、数字和布尔值的 YAML 文件可以正常工作,但包含 anchors 的文件将不起作用,因为 anchors 在加载时重新定义了文件的结构。
此文件在 SOPS 中将不起作用:
.. code:: yaml
```
bill-to: &id001
street: |
123 Tornado Alley
Suite 16
city: East Centerville
state: KS
ship-to: *id001
```
SOPS 使用值的路径作为 AEAD 加密中的附加数据,因此由 anchors 生成的动态路径会破坏身份验证步骤。
JSON 和 TEXT 文件类型不支持 anchors,因此没有此限制。
### YAML Streams
``YAML`` 支持在单个文件中包含多个“文档”,而 ``JSON`` 等格式不支持。SOPS 能够处理这两种情况。这意味着以下多文档将按预期加密:
.. code:: yaml-stream
```
---
data: foo
---
data: bar
```
请注意,``sops`` 元数据(即哈希等)是为物理文件而不是每个内部“文档”计算的。
### 顶级数组
不支持 ``YAML`` 和 ``JSON`` 顶级数组,因为 SOPS 需要顶级 ``sops`` 键来存储其元数据。
此文件在 SOPS 中将不起作用:
.. code:: yaml
```
---
- some
- array
- elements
```
但是这个可以工作,因为 ``sops`` 键可以添加在与 ``data`` 键相同的级别。
.. code:: yaml
```
data:
- some
- array
- elements
```
同样,对于 ``JSON`` 数组,此文档将不起作用:
.. code:: json
```
[
"some",
"array",
"elements"
]
```
但这一个可以正常工作:
.. code:: json
```
{
"data": [
"some",
"array",
"elements"
]
}
```
## 示例
请查看 `examples folder `_ 以获取 CI 环境中 SOPS 的详细用例。下面的部分描述了常见用例的具体技巧。
创建新文件
下面的命令使用由 KMS 和 PGP 加密的数据密钥创建一个新文件。
.. code:: sh
```
$ sops edit --kms "arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500" --pgp C9CAB0AF1165060DB58D6D6B2653B624D620786D /path/to/new/file.yaml
```
### 加密现有文件
与上一个命令类似,我们告诉 SOPS 使用一个 KMS 和一个 PGP 密钥。路径指向现有的明文文件,因此我们给 ``sops`` 标志 ``-e`` 来加密文件,并将输出重定向到目标文件。
.. code:: sh
```
$ export SOPS_KMS_ARN="arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500"
$ export SOPS_PGP_FP="C9CAB0AF1165060DB58D6D6B2653B624D620786D"
$ sops encrypt /path/to/existing/file.yaml > /path/to/new/encrypted/file.yaml
```
使用 ``-d`` 解密文件。
.. code:: sh
```
$ sops decrypt /path/to/new/encrypted/file.yaml
```
### 就地加密或解密文件
``sops`` 可以在加密或解密后替换原始文件,而不是重定向 ``-e`` 或 ``-d`` 的输出。
.. code:: sh
```
# file.yaml 是明文
$ sops encrypt -i /path/to/existing/file.yaml
# file.yaml 现已加密
$ sops decrypt -i /path/to/existing/file.yaml
# file.yaml 恢复为明文
```
### 加密二进制文件
SOPS 的主要用例是加密 YAML、JSON、ENV 和 INI 配置文件,但它也能够管理二进制文件。加密二进制文件时,SOPS 将数据作为字节读取,对其进行加密,将加密的 base64 存储在 ``tree['data']`` 下,并将结果写入 JSON。
请注意,加密数据的 base64 编码实际上可能使加密文件大于明文文件。
就地加密/解密也适用于二进制文件。
.. code:: sh
```
$ dd if=/dev/urandom of=/tmp/somerandom bs=1024
count=512
512+0 records in
512+0 records out
524288 bytes (524 kB) copied, 0.0466158 s, 11.2 MB/s
$ sha512sum /tmp/somerandom
9589bb20280e9d381f7a192000498c994e921b3cdb11d2ef5a986578dc2239a340b25ef30691bac72bdb14028270828dad7e8bd31e274af9828c40d216e60cbe /tmp/somerandom
$ sops encrypt -i /tmp/somerandom
please wait while a data encryption key is being generated and stored securely
$ sops decrypt -i /tmp/somerandom
$ sha512sum /tmp/somerandom
9589bb20280e9d381f7a192000498c994e921b3cdb11d2ef5a986578dc2239a340b25ef30691bac72bdb14028270828dad7e8bd31e274af9828c40d216e60cbe /tmp/somerandom
```
### 提取文档树的子部分
SOPS 可以通过在 ``--extract`` 命令行标志中提供路径来提取 YAML 或 JSON 文档的特定部分。这对于提取特定值(如密钥)而无需额外的解析器很有用。
.. code:: sh
```
$ sops decrypt --extract '["app2"]["key"]' ~/git/svc/sops/example.yaml
-----BEGIN RSA PRIVATE KEY-----
MIIBPAIBAAJBAPTMNIyHuZtpLYc7VsHQtwOkWYobkUblmHWRmbXzlAX6K8tMf3Wf
ImcbNkqAKnELzFAPSBeEMhrBN0PyOC9lYlMCAwEAAQJBALXD4sjuBn1E7Y9aGiMz
bJEBuZJ4wbhYxomVoQKfaCu+kH80uLFZKoSz85/ySauWE8LgZcMLIBoiXNhDKfQL
vHECIQD6tCG9NMFWor69kgbX8vK5Y+QL+kRq+9HK6yZ9a+hsLQIhAPn4Ie6HGTjw
fHSTXWZpGSan7NwTkIu4U5q2SlLjcZh/AiEA78NYRRBwGwAYNUqzutGBqyXKUl4u
Erb0xAEyVV7e8J0CIQC8VBY8f8yg+Y7Kxbw4zDYGyb3KkXL10YorpeuZR4LuQQIg
bKGPkMM4w5blyE1tqGN0T7sJwEx+EUOgacRNqM2ljVA=
-----END RSA PRIVATE KEY-----
```
树路径语法使用常规 python 字典语法,没有变量名。通过命名来提取键,通过编号来提取数组元素。
.. code:: sh
```
$ sops decrypt --extract '["an_array"][1]' ~/git/svc/sops/example.yaml
secretuser2
```
### 在文档树中设置子部分
SOPS 可以通过在 ``set`` 命令中提供路径和值来设置 YAML 或 JSON 文档的特定部分。这对于设置特定值(如密钥)而无需编辑器很有用。
.. code:: sh
```
$ sops set ~/git/svc/sops/example.yaml '["app2"]["key"]' '"app2keystringvalue"'
```
树路径语法使用常规 python 字典语法,没有变量名。通过命名来设置键,通过编号来设置数组元素。
.. code:: sh
```
$ sops set ~/git/svc/sops/example.yaml '["an_array"][1]' '"secretuser2"'
```
该值必须格式化为 json。
.. code:: sh
```
$ sops set ~/git/svc/sops/example.yaml '["an_array"][1]' '{"uid1":null,"uid2":1000,"uid3":["bob"]}'
```
您还可以从文件或 stdin 提供值:
.. code:: sh
```
# 从文件提供值
$ echo '{"uid1":null,"uid2":1000,"uid3":["bob"]}' > /tmp/example-value
$ sops set --value-file ~/git/svc/sops/example.yaml '["an_array"][1]' /tmp/example-value
# 从 stdin 提供值
$ echo '{"uid1":null,"uid2":1000,"uid3":["bob"]}' | sops set --value-stdin ~/git/svc/sops/example.yaml '["an_array"][1]'
```
### 取消设置文档树的子部分
对称地,SOPS 可以通过在 ``unset`` 命令中提供路径来取消设置 YAML 或 JSON 文档的特定部分。这对于取消设置特定值(如密钥)而无需编辑器很有用。
.. code:: sh
```
$ sops unset ~/git/svc/sops/example.yaml '["app2"]["key"]'
```
树路径语法使用常规 python 字典语法,没有变量名。通过命名来设置键,通过编号来设置数组元素。
.. code:: sh
```
$ sops unset ~/git/svc/sops/example.yaml '["an_array"][1]'
```
### 在 git 中以明文显示差异
您很可能希望将加密文件存储在版本控制的仓库中。SOPS 可以与 git 一起使用,以在显示版本之间的差异时解密文件。这对于查看更改或可视化历史记录非常方便。
要将 SOPS 配置为在 diff 期间解密文件,请在仓库的根目录下创建一个 ``.gitattributes`` 文件,其中包含过滤器和命令。
.. code:: text
```
*.yaml diff=sopsdiffer
```
这里我们只关心 YAML 文件。``sopsdiffer`` 是一个任意名称,我们在仓库的 git 配置文件中将其映射到 SOPS 命令。
.. code:: sh
```
$ git config diff.sopsdiffer.textconv "sops decrypt"
$ grep -A 1 sopsdiffer .git/config
[diff "sopsdiffer"]
textconv = "sops decrypt"
```
有了这个设置,调用 ``git diff`` 将在显示差异之前解密目标文件的先前版本和当前版本。它甚至适用于 git 客户端界面,因为它们在后台调用 git diff!
### 仅加密文件的一部分
注意:这仅适用于 YAML、JSON、ENV 和 INI 文件,不适用于 BINARY 文件。
默认情况下,SOPS 加密 YAML、JSON、ENV 或 INI 文件的所有值,并将键保留为明文。在某些情况下,您可能希望排除某些值不被加密。这可以通过向文件的任何键添加后缀 **_unencrypted** 来实现。设置后,设置 **_unencrypted** 后缀的键下的所有值将保留为明文。
请注意,虽然是明文,但未加密的内容仍会添加到文件的校验和中,因此不能在 SOPS 外部修改,否则会破坏文件完整性检查。
可以使用 ``--mac-only-encrypted`` 标志或 ``.sops.yaml`` 配置文件修改此行为,这使 SOPS 仅对其加密的值计算 MAC,而不是所有值。
可以使用 ``--unencrypted-suffix`` 选项将未加密后缀设置为不同的值。
相反,您可以通过向 YAML 或 JSON 文件中的那些键添加选定的后缀并将其传递给 ``--encrypted-suffix`` 选项来选择仅加密某些值。
第三种方法是使用 ``--encrypted-regex``,它将只加密与提供的正则表达式匹配的键下的值。例如,此命令:
.. code:: sh
```
$ sops encrypt --encrypted-regex '^(data|stringData)$' k8s-secrets.yaml
```
将加密包含 kubernetes secrets 的 YAML 文件中 ``data`` 和 ``stringData`` 键下的值。它不会加密帮助您浏览文件的其他值,例如包含 secrets 名称的 ``metadata``。
相反,您可以选择使用 ``--unencrypted-regex`` 选项仅保留某些键不被加密,这将使与提供的正则表达式匹配的那些键的值不被加密。例如,此命令:
.. code:: sh
```
$ sops encrypt --unencrypted-regex '^(description|metadata)$' k8s-secrets.yaml
```
将不会加密包含 kubernetes secrets 的 YAML 文件中 ``description`` 和 ``metadata`` 键下的值,同时加密其他所有内容。
对于 YAML 文件,另一种方法是使用 ``--encrypted-comment-regex``,它将仅加密具有与提供的正则表达式匹配的前导注释的注释和值。
相反,您可以选择使用 ``--unencrypted-comment-regex`` 选项仅保留某些键不被加密,当它们具有前导注释或同一行上的尾随注释且与提供的正则表达式匹配时,这将使值和注释不被加密。
您也可以在 ``.sops.yaml`` 配置文件中指定这些选项。
注意:这六个选项 ``--unencrypted-suffix``、``--encrypted-suffix``、``--encrypted-regex``、``--unencrypted-regex``、``--encrypted-comment-regex`` 和 ``--unencrypted-comment-regex`` 是互斥的,不能都在同一个文件中使用。
## 配置文件格式
本节描述 SOPS 配置文件的格式。
文件必须命名为 ``.sops.yaml``(不是 ``.sops.yml``!),SOPS 将在当前工作目录及其父目录中查找它,使用找到的第一个 ``.sops.yaml`` 文件。
可以通过传递 ``--config`` 全局选项或设置 ``SOPS_CONFIG`` 环境变量将特定文件设置为配置文件。
配置文件必须采用 `YAML format `__。
支持以下顶级键:
* ``creation_rules``:创建规则对象列表。
* ``destination_rules``:目标规则对象列表。
* ``stores``:存储的配置对象。
以下小节描述了如何使用这些属性。
### 创建规则对象
创建规则对象具有三种类型的键:
#. 确定创建规则是否匹配的键。
#. 确定用于加密的身份(密钥)(组)的键。
#. 确定文件的哪些部分以及如何加密的键。
## 匹配
与文件匹配相关的键是:
* ``path_regex``:匹配要加密的文件的正则表达式。
如果未指定,此创建规则将匹配所有文件。
## 身份
可以直接指定单个密钥组的身份,也可以指定密钥组列表。
如果给出了密钥组列表,则忽略单个设置。
要直接指定单个密钥组,可以使用以下键:
* ``kms``(逗号分隔的字符串或字符串列表):AWS 主密钥列表。
* ``aws_profile``(字符串):用于 AWS KMS 密钥的 AWS profile。
示例:
.. code:: yaml
creation_rules:
- kms:
- arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
- arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d
aws_profile: foo
* ``age``(逗号分隔的字符串或字符串列表):Age 公钥列表。
示例:
.. code:: yaml
creation_rules:
- age:
- age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
- age1qe5lxzzeppw5k79vxn3872272sgy224g2nzqlzy3uljs84say3yqgvd0sw
* ``pgp``(逗号分隔的字符串或字符串列表):PGP/GPG 密钥指纹列表。
示例:
.. code:: yaml
creation_rules:
- pgp:
- 85D77543B3D624B63CEA9E6DBC17301B491B3F21!
- E60892BB9BD89A69F759A1A0A3D652173B763E8F!
* ``gcp_kms``(逗号分隔的字符串或字符串列表):GCP KMS ResourceID 列表。
示例:
.. code:: yaml
creation_rules:
- gcp_kms:
- projects/mygcproject/locations/global/keyRings/mykeyring/cryptoKeys/thekey
* ``azure_keyvault``(逗号分隔的字符串或字符串列表):Azure Key Vault 资源标识符列表。
示例:
.. code:: yaml
creation_rules:
- azure_keyvault:
- https://vault.url/keys/key-name/key-version # 带版本的密钥
- https://vault.url/keys/key-name/ # 不带版本的密钥,将使用最新版本
* ``hc_vault_transit_uri``(逗号分隔的字符串或字符串列表):HashiCorp Vault transit URI 列表。
示例:
.. code:: yaml
creation_rules:
- hc_vault_transit_uri:
- http://my.vault/v1/sops/keys/secondkey
* ``hckms``(字符串列表):HuaweiCloud KMS 密钥 ID 列表(格式:``:``)。
示例:
.. code:: yaml
creation_rules:
- hckms:
- tr-west-1:abc12345-6789-0123-4567-890123456789
- tr-west-1:def67890-1234-5678-9012-345678901234
要指定密钥组列表,可以使用以下键:
* ``key_groups``(密钥组对象列表):密钥组对象列表。
有关此类资源应如何表示,请参见下文。
示例:
.. code:: yaml
creation_rules:
- key_groups:
- kms:
- arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
- arn:aws:kms:ap-southeast-1:656532927350:key/9006a8aa-0fa6-4c14-930e-a2dfb916de1d
aws_profile: foo
age:
- age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
- age1qe5lxzzeppw5k79vxn3872272sgy224g2nzqlzy3uljs84say3yqgvd0sw
pgp:
- 85D77543B3D624B63CEA9E6DBC17301B491B3F21!
- E60892BB9BD89A69F759A1A0A3D652173B763E8F!
gcp_kms:
- projects/mygcproject/locations/global/keyRings/mykeyring/cryptoKeys/thekey
azure_keyvault:
- https://vault.url/keys/key-name/key-version # 带版本的密钥
- https://vault.url/keys/key-name/ # 不带版本的密钥,将使用最新版本
hc_vault_transit_uri:
- http://my.vault/v1/sops/keys/secondkey
hckms:
- tr-west-1:abc12345-6789-0123-4567-890123456789
merge:
- pgp:
- 85D77543B3D624B63CEA9E6DBC17301B491B3F21!
- age:
- age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
- gcp_kms:
- projects/mygcproject/locations/global/keyRings/mykeyring/cryptoKeys/thekey
azure_keyvault:
- https://vault.url/keys/key-name-version
## 密钥组对象
密钥组包含多个身份(密钥),类似于创建规则对象。
拥有多个密钥组允许使用 `Shamir's secret sharing `__,它将文件的加密密钥分成多个部分,需要多个身份才能访问文件。
密钥组支持以下键:
* ``kms``(对象列表):AWS 主密钥列表。
每个对象必须具有以下键:
* ``arn``(字符串):主密钥的 ARN。
* ``role``(字符串,可省略):密钥的角色。
* ``context``(将字符串映射到字符串的对象):密钥的加密上下文。
* ``aws_profile``(字符串):AWS profile。
示例:
.. code:: yaml
- arn: arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500
role: arn:aws:iam::927034868273:role/sops-dev-xyz
context:
Environment: production
Role: web-server
aws_profile: foo
* ``gcp_kms``(对象列表):GCP KMS 资源 ID 列表。
每个对象必须具有以下键:
* ``resource_id``(字符串):资源 ID。
示例:
.. code:: yaml
- resource_id: projects/mygcproject/locations/global/keyRings/mykeyring/cryptoKeys/thekey
* ``azure_keyvault``(对象列表):Azure Key Vault 资源标识符列表。
每个对象必须具有以下键:
* ``vaultUrl``(字符串):vault URL。
* ``key``(字符串):密钥名称。
* ``version``(字符串,可为空):要使用的密钥版本。
如果为空,将在加密时使用最新密钥。
示例:
.. code:: yaml
- vaultUrl: https://vault.url
key: key-name
version: key-version
- vaultUrl: https://vault.url
key: key-name
version: ""
* ``hc_vault``(字符串列表):HashiCorp Vault transit URI 列表。
* ``hckms``(对象列表):HuaweiCloud KMS 密钥 ID 列表。
每个对象必须具有以下键:
* ``key_id``(字符串):格式为 ``:`` 的密钥 ID。
示例:
.. code:: yaml
- key_id: tr-west-1:abc12345-6789-0123-4567-890123456789
* ``age``(字符串列表):Age 公钥列表。
* ``pgp``(字符串列表):PGP/GPG 密钥指纹列表。
* ``merge``:密钥组对象列表。
这些将被合并(通过连接相同类型的密钥)到此密钥组中。
此属性允许使用 YAML anchors、aliases 和 overrides 连接密钥组。
## 设置
以下键配置加密设置:
* ``shamir_threshold``(整数,默认 ``0``):必须为 ``0``(禁用)或大于或等于 2 的整数。
确定解密文件密钥必须存在的密钥组数量。
* ``mac_only_encrypted``(布尔值,默认 ``false``):如果设置为 ``true``,则只有加密的字符串才会计入文件的 MAC。
如果设置为 ``false``,未加密的值也将成为 MAC 计算的一部分。
以下键配置文件中应加密的特定值。
请注意,最多可以使用这些键中的一个。
* ``unencrypted_suffix``(字符串):如果键的后缀 **不** 是此后缀,则值被加密。
所有其他值 **被加密**。
注释总是被加密。
* ``encrypted_suffix``(字符串):如果键的后缀 **是** 此后缀,则值被加密。
所有其他值 **不被加密**。
注释总是被加密。
* ``unencrypted_regex``(字符串):如果键 **不匹配** 此正则表达式,则值被加密。
所有其他值 **被加密**。
注释总是被加密。
* ``encrypted_regex``(字符串):如果键 **匹配** 此正则表达式,则值被加密。
所有其他值 **不被加密**。
注释总是被加密。
* ``unencrypted_comment_regex``(字符串):如果值或注释具有与此正则表达式匹配的前导注释(或同一行上的尾随注释),则不会被加密。
所有其他值和注释被加密。
* ``encrypted_comment_regex``(字符串):如果值或注释具有与此正则表达式匹配的前导注释(或同一行上的尾随注释),则会被加密。
所有其他注释和值不被加密。
匹配的注释本身不被加密。
### 目标规则对象
尚未记录。
.. TODO!
.. type destinationRule struct {
.. PathRegex string `yaml:"path_regex"`
.. S3Bucket string `yaml:"s3_bucket"`
.. S3Prefix string `yaml:"s3_prefix"`
.. GCSBucket string `yaml:"gcs_bucket"`
.. GCSPrefix string `yaml:"gcs_prefix"`
.. VaultPath string `yaml:"vault_path"`
.. VaultAddress string `yaml:"vault_address"`
.. VaultKVMountName string `yaml:"vault_kv_mount_name"`
.. VaultKVVersion int `yaml:"vault_kv_version"`
.. RecreationRule creationRule `yaml:"recreation_rule,omitempty"`
.. OmitExtensions bool `yaml:"omit_extensions"`
.. }
### 存储配置对象
存储配置对象可以具有以下键:
* ``dotenv``:这是一个对象。目前不支持任何键。
* ``ini``:这是一个对象。目前不支持任何键。
* ``json_binary``:这是一个对象,支持以下键:
* ``indent``(整数;默认 ``-1``):以空格数使用的缩进。
``0`` 表示没有缩进(所有内容将在一行中),
``-1`` 表示使用单个制表符缩进。
* ``json``:这是一个对象,支持以下键:
* ``indent``(整数;默认 ``-1``):以空格数使用的缩进。
``0`` 表示没有缩进(所有内容将在一行中),
``-1`` 表示使用单个制表符缩进。
* ``yaml``:这是一个对象,支持以下键:
* ``indent``(整数;默认 ``4``):以空格数使用的缩进。
sops 使用的 YAML emitter 仅支持 ``2`` 到 ``9`` 之间的值。
如果您指定 ``1`` 或 ``10`` 及更大的值,缩进将为 ``2``。
## 加密协议
当 SOPS 创建文件时,它会生成一个随机的 256 位数据密钥,并要求每个 KMS 和 PGP 主密钥加密该数据密钥。数据密钥的加密版本存储在 ``sops`` 元数据下的 ``sops.kms`` 和 ``sops.pgp`` 中。
对于 KMS:
.. code:: yaml
```
sops:
kms:
- enc: CiC6yCOtzsnFhkfdIslYZ0bAf//gYLYCmIu87B3sy/5yYxKnAQEBAQB4usgjrc7JxYZH3SLJWGdGwH//4GC2ApiLvOwd7Mv+cmMAAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAyGdRODuYMHbA8Ozj8CARCAO7opMolPJUmBXd39Zlp0L2H9fzMKidHm1vvaF6nNFq0ClRY7FlIZmTm4JfnOebPseffiXFn9tG8cq7oi
enc_ts: 1439568549.245995
arn: arn:aws:kms:us-east-1:656532927350:key/920aff2e-c5f1-4040-943a-047fa387b27e
```
对于 PGP:
.. code:: yaml
```
sops:
pgp:
- fp: 85D77543B3D624B63CEA9E6DBC17301B491B3F21
created_at: 1441570391.930042
enc: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQIMA0t4uZHfl9qgAQ//UvGAwGePyHuf2/zayWcloGaDs0MzI+zw6CmXvMRNPUsA
pAgRKczJmDu4+XzN+cxX5Iq9xEWIbny9B5rOjwTXT3qcUYZ4Gkzbq4MWkjuPp/Iv
qO4MJaYzoH5YxC4YORQ2LvzhA2YGsCzYnljmatGEUNg01yJ6r5mwFwDxl4Nc80Cn
RwnHuGExK8j1jYJZu/juK1qRbuBOAuruIPPWVdFB845PA7waacG1IdUW3ZtBkOy3
O0BIfG2ekRg0Nik6sTOhDUA+l2bewCcECI8FYCEjwHm9Sg5cxmP2V5m1mby+uKAm
kewaoOyjbmV1Mh3iI1b/AQMr+/6ZE9MT2KnsoWosYamFyjxV5r1ZZM7cWKnOT+tu
KOvGhTV1TeOfVpajNTNwtV/Oyh3mMLQ0F0HgCTqomQVqw5+sj7OWAASuD3CU/dyo
pcmY5Qe0TNL1JsMNEH8LJDqSh+E0hsUxdY1ouVsg3ysf6mdM8ciWb3WRGxih1Vmf
unfLy8Ly3V7ZIC8EHV8aLJqh32jIZV4i2zXIoO4ZBKrudKcECY1C2+zb/TziVAL8
qyPe47q8gi1rIyEv5uirLZjgpP+JkDUgoMnzlX334FZ9pWtQMYW4Y67urAI4xUq6
/q1zBAeHoeeeQK+YKDB7Ak/Y22YsiqQbNp2n4CKSKAE4erZLWVtDvSp+49SWmS/S
XgGi+13MaXIp0ecPKyNTBjF+NOw/I3muyKr8EbDHrd2XgIT06QXqjYLsCb1TZ0zm
xgXsOTY3b+ONQ2zjhcovanDp7/k77B+gFitLYKg4BLZsl7gJB12T8MQnpfSmRT4=
=oJgS
-----END PGP MESSAGE-----
```
然后 SOPS 在新创建的文件上打开文本编辑器。用户向文件添加数据并在完成后保存它。
保存时,SOPS 将整个文件作为键/值树浏览。每次 SOPS 遇到叶值(没有子项的值)时,它都会使用数据密钥和 256 位随机初始化向量使用 AES256_GCM 加密该值。
每个文件使用单个数据密钥加密文档的所有值,但每个值接收唯一的初始化向量并具有唯一的身份验证数据。
附加数据用于保证加密数据和树结构的完整性:加密树时,键名被连接成一个字节字符串,用作加密值时的 AEAD 附加数据。我们假设键不携带敏感信息,并且将它们保留为明文可以更好地进行差异比较和整体可读性。
任何有效的 KMS 或 PGP 主密钥以后都可以解密数据密钥并访问数据。
多个主密钥允许在不共享主密钥的情况下共享加密文件,并提供灾难恢复解决方案。使用 SOPS 的推荐方法是在不同区域拥有两个 KMS 主密钥和一个 PGP 公钥,并将私钥离线存储。如果万一两个 KMS 主密钥都丢失了,您始终可以使用 PGP 私钥恢复加密数据。
### 消息认证码 (MAC)
除了使用键作为附加数据验证树的分支外,SOPS 还计算所有值的 MAC 以确保没有欺诈性地添加或删除任何值。MAC 使用 AES_GCM 和数据密钥加密存储在 tree -> ``sops`` -> ``mac`` 下。
可以使用 ``--mac-only-encrypted`` 标志或 ``.sops.yaml`` 配置文件修改此行为,这使 SOPS 仅对其加密的值计算 MAC,而不是所有值。
## 动机
📝 **维护者的说明**
本节由 SOPS 的原作者在 Mozilla 工作时撰写。此处保留用于历史原因并提供项目的技术背景。它不一定代表当前维护者的观点,他们目前也不隶属于 Mozilla。
自动化将 secrets 和凭证分发给基础设施组件是一个难题。我们知道如何加密 secrets 并在人类之间共享,但将这种信任扩展到系统是困难的。特别是当这些系统遵循 devops 原则并在没有人为干预的情况下创建和销毁时。问题归结为建立刚刚加入基础设施的系统的初始信任,并为其提供配置自身所需的 secrets 访问权限。
### 初始信任
在许多基础设施中,即使是高度动态的基础设施,初始信任也是由人类建立的。一个例子是 Puppet 通过颁发证书的方式:当新系统尝试加入 Puppetmaster 时,管理员必须默认手动批准系统所需证书的颁发。这很麻烦,许多 puppetmaster 被配置为自动签署新证书以解决该问题。这显然不建议,也远非理想。
AWS 提供了一种更灵活的方法来信任新系统。它使用强大的角色和身份机制。在 AWS 中,可以验证新系统在创建时已被授予特定角色,并且可以将该角色映射到特定资源。管理员不是直接信任新系统,而是信任 AWS 权限模型及其自动化基础设施。只要 AWS 密钥是安全的,并且 AWS API 是安全的,我们就可以假设信任得到维护并且系统是他们所说的那样。
### KMS、信任和 secrets 分发
使用 AWS 信任模型,我们可以创建对 Amazon 的 Key Management Service (KMS) 的细粒度访问控制。KMS 是一项使用 AES_GCM 加密和解密数据的服务,使用的密钥对服务的用户永远不可见。每个 KMS 主密钥都有一组基于角色的访问控制,并且各个角色被允许使用主密钥进行加密或解密。KMS 通过将密钥分发问题转移到可以使用 AWS 信任模型解决的访问控制问题来帮助解决该问题。
### 操作要求
当 Mozilla 的 Services Operations 团队开始重新审视将 secrets 分发给 EC2 实例的问题时,我们设定了一个目标,即存储这些 secrets 直到最后一刻才加密,直到它们需要在目标系统上解密。与许多其他运营足够复杂自动化的组织一样,我们发现这是一个具有许多先决条件的难题:
1. Secrets 必须存储在 YAML 文件中以便轻松集成到 hiera 中
2. Secrets 必须存储在 GIT 中,并且当构建新的 CloudFormation 堆栈时,当前 HEAD 被固定到该堆栈。(这允许在 GIT 中更改 secrets 而不影响可能会自动伸缩的当前堆栈)。
3. 条目必须单独加密。将整个文件作为 blob 加密会使 git 冲突解决几乎不可能。单独加密每个条目更易于管理。
4. Secrets 必须始终在磁盘上加密(管理员笔记本电脑、上游 git repo、jenkins 和 S3),并且仅在目标系统上解密
SOPS 可用于加密 YAML、JSON、ENV、INI 和 BINARY 文件。在 BINARY 模式下,文件内容被视为 blob,与 PGP 加密整个文件的方式相同。然而,在 YAML、JSON、ENV 和 INI 模式下,文件内容被作为树操作,其中键以明文存储,值被加密。hiera-eyaml 做类似的事情,多年来我们学会了欣赏它的好处,即:
* 差异是有意义的。如果文件的单个值被修改,只有该值会显示在差异中。差异仍然仅限于显示加密数据,但该信息已经比指示整个文件已更改更细粒度。
* 冲突更容易解决。如果多个用户在同一个加密文件上工作,只要他们不修改相同的值,更改就很容易合并。这是对 PGP 加密方法的改进,在 PGP 加密方法中,当多个用户在同一个文件上工作时,经常发生无法解决的冲突。
### OpenPGP 集成
OpenPGP 因是过时的加密协议而受到很多负面报道,虽然确实如此,但真正让我们寻找替代方案的是管理和向系统分发密钥的困难。使用 KMS,我们管理对 API 的权限,而不是密钥,这更容易做到。
但 PGP 还没有消亡,我们仍然严重依赖它作为备份解决方案:我们所有的文件都使用 KMS 和一个 PGP 公钥加密,其私钥被安全存储,以便在我们丢失所有 KMS 主密钥的紧急情况下进行紧急解密。
SOPS 可以完全在没有 KMS 的情况下使用,就像您使用加密的 PGP 文件一样:通过引用有权访问该文件的每个人的公钥。
可以通过在创建新文件时向 SOPS 提供以逗号分隔的公钥列表来轻松完成此操作:
.. code:: sh
```
$ sops edit --pgp "E60892BB9BD89A69F759A1A0A3D652173B763E8F,84050F1D61AF7C230A12217687DF65059EF093D3,85D77543B3D624B63CEA9E6DBC17301B491B3F21" mynewfile.yaml
```
## 威胁模型
使用 SOPS 存储的数据的安全性与最弱的加密机制强。值使用 AES256_GCM 加密,这是当今已知的最强对称加密算法。数据密钥使用 KMS(也使用 AES256_GCM)或 PGP(使用 RSA 或 ECDSA 密钥)加密。
从最可能到最不可能,威胁如下:
### 泄露的 AWS 凭证授予对 KMS 主密钥的访问权限
有权访问 AWS 控制台的攻击者可以授予自己访问用于加密 ``sops`` 数据密钥的 KMS 主密钥之一的权限。应通过使用强控制(例如多因素身份验证)保护 AWS 访问以及定期审计授予 AWS 用户的权限来缓解此威胁。
### 泄露的 PGP 密钥
PGP 密钥通常被处理不当,要么是因为所有者将它们从一台机器复制到另一台机器,要么是因为密钥被遗忘在攻击者获得访问权限的未使用机器上。使用 PGP 加密时,SOPS 用户应特别照顾 PGP 私钥,并尽可能将其存储在智能卡或离线。
### 被因式分解的 RSA 密钥
SOPS 不对 PGP 密钥的大小或类型施加任何限制。弱的 PGP 密钥,例如 512 位 RSA,可能会被攻击者因式分解以获取私钥并解密数据密钥。SOPS 用户应依赖强密钥,例如 2048+ 位 RSA 密钥或 256+ 位 ECDSA 密钥。
### 弱 AES 密码学
AES256_GCM 中的漏洞可能会潜在地泄露 SOPS 加密文件使用的数据密钥或 KMS 主密钥。虽然今天不存在此类漏洞,但我们建议用户保持其加密文件合理私密。
## 向后兼容性
SOPS 将在主要版本上保持向后兼容性,这意味着对 1.X 和 2.X 分支(当前)带来的所有改进将维护 **1.0** 中引入的文件格式。
## 安全
请使用 `GitHub's advisory form `_ 私下报告任何安全问题。
## 许可证
Mozilla Public License Version 2.0
## 作者
SOPS 最初于 2015 年作为 Mozilla 的一个项目启动,并于 2023 年被慷慨地捐赠给 CNCF 作为沙箱项目,现在由 `new group of maintainers `_ 管理。
该项目的原作者包括:
* Adrian Utrilla @autrilla
* Julien Vehent @jvehent
此外,该项目由 AJ Bahnken @ajvb 维护了很长时间,
如果没有众多 `贡献者 `_ 的贡献,这是不可能实现的。
## 致谢
SOPS 的灵感来源于 `hiera-eyaml `_,
`credstash `_,
`sneaker `_,
`password store `_ 以及多年来手动管理
## PGP 加密文件的经历……
.. image:: docs/images/cncf-color-bg.svg
:width: 400
:alt: CNCF Sandbox Project
**我们是一个** `Cloud Native Computing Foundation `_ **沙箱项目。**
标签:Age加密, AWS KMS, Azure Key Vault, DevOps工具, DevSecOps, DNS解析, Env加密, EVTX分析, EVTX分析, GCP KMS, Go, Infrastructure as Code, INI加密, JSON加密, KMS, PGP, ProjectDiscovery, Ruby工具, StruQ, YAML加密, 上游代理, 加密工具, 安全助手, 安全合规, 安全管理, 密钥轮换, 开源项目, 敏感数据, 数据保护, 文件编辑器, 日志审计, 网络代理, 配置加密