Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## Unreleased

Features:

* Add Tencent Cloud KMS support for encryption and decryption.
The integration supports environment variable authentication
(``TENCENTCLOUD_SECRET_ID``, ``TENCENTCLOUD_SECRET_KEY``),
optional STS token (``TENCENTCLOUD_TOKEN``),
configurable region and custom endpoint.
New CLI flags: ``--tencent-kms``, ``--add-tencent-kms``,
``--rm-tencent-kms``.
Environment variable: ``SOPS_TENCENT_KMS_IDS``.
Configuration file key: ``tencent_kms``.

## 3.11.0

Security fixes:
Expand Down
88 changes: 82 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -596,13 +596,63 @@ You can also configure HuaweiCloud KMS keys in the ``.sops.yaml`` config file:
hckms:
- tr-west-1:abc12345-6789-0123-4567-890123456789,tr-west-2:def67890-1234-5678-9012-345678901234

Encrypting using Tencent Cloud KMS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Tencent Cloud KMS integration requires credentials to be provided through
environment variables:

.. code:: bash

export TENCENTCLOUD_SECRET_ID="your-secret-id"
export TENCENTCLOUD_SECRET_KEY="your-secret-key"
# Optional: for temporary credentials (STS)
export TENCENTCLOUD_TOKEN="your-sts-token"
# Optional: specify region (default: ap-guangzhou)
export TENCENTCLOUD_REGION="ap-guangzhou"
# Optional: custom KMS endpoint (default: kms.tencentcloudapi.com)
# For CVM or TKE environments, use the internal endpoint for better performance:
# export TENCENTCLOUD_KMS_ENDPOINT="kms.internal.tencentcloudapi.com"
export TENCENTCLOUD_KMS_ENDPOINT="kms.tencentcloudapi.com"

Encrypting/decrypting with Tencent Cloud KMS requires a KMS key ID. You can get
the key ID from the Tencent Cloud console or using the Tencent Cloud API.

Now you can encrypt a file using:

.. code:: sh

$ sops encrypt --tencent-kms xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx test.yaml > test.enc.yaml

Or using the environment variable:

.. code:: sh

$ export SOPS_TENCENT_KMS_IDS="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ sops encrypt test.yaml > test.enc.yaml

And decrypt it using:

.. code:: sh

$ sops decrypt test.enc.yaml

You can also configure Tencent Cloud KMS keys in the ``.sops.yaml`` config file:

.. code:: yaml

creation_rules:
- path_regex: \.tencent\.yaml$
tencent_kms:
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Adding and removing keys
~~~~~~~~~~~~~~~~~~~~~~~~

When creating new files, ``sops`` uses the PGP, KMS and GCP KMS defined in the
command line arguments ``--kms``, ``--pgp``, ``--gcp-kms``, ``--hckms`` or ``--azure-kv``, or from
command line arguments ``--kms``, ``--pgp``, ``--gcp-kms``, ``--hckms``, ``--tencent-kms`` or ``--azure-kv``, or from
the environment variables ``SOPS_KMS_ARN``, ``SOPS_PGP_FP``, ``SOPS_GCP_KMS_IDS``,
``SOPS_HUAWEICLOUD_KMS_IDS``, ``SOPS_AZURE_KEYVAULT_URLS``. That information is stored in the file under the
``SOPS_HUAWEICLOUD_KMS_IDS``, ``SOPS_TENCENT_KMS_IDS``, ``SOPS_AZURE_KEYVAULT_URLS``. That information is stored in the file under the
``sops`` section, such that decrypting files does not require providing those
parameters again.

Expand Down Expand Up @@ -646,9 +696,9 @@ disabled by supplying the ``-y`` flag.

The ``rotate`` command generates a new data encryption key and reencrypt all values
with the new key. At the same time, the command line flag ``--add-kms``, ``--add-pgp``,
``--add-gcp-kms``, ``--add-hckms``, ``--add-azure-kv``, ``--rm-kms``, ``--rm-pgp``, ``--rm-gcp-kms``,
``--rm-hckms`` and ``--rm-azure-kv`` can be used to add and remove keys from a file. These flags use
the comma separated syntax as the ``--kms``, ``--pgp``, ``--gcp-kms``, ``--hckms`` and ``--azure-kv``
``--add-gcp-kms``, ``--add-hckms``, ``--add-tencent-kms``, ``--add-azure-kv``, ``--rm-kms``, ``--rm-pgp``, ``--rm-gcp-kms``,
``--rm-hckms``, ``--rm-tencent-kms`` and ``--rm-azure-kv`` can be used to add and remove keys from a file. These flags use
the comma separated syntax as the ``--kms``, ``--pgp``, ``--gcp-kms``, ``--hckms``, ``--tencent-kms`` and ``--azure-kv``
arguments when creating new files.

Use ``updatekeys`` if you want to add a key without rotating the data key.
Expand Down Expand Up @@ -824,7 +874,7 @@ stdout.
Using .sops.yaml conf to select KMS, PGP and age for new files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is often tedious to specify the ``--kms`` ``--gcp-kms`` ``--hckms`` ``--pgp`` and ``--age`` parameters for creation
It is often tedious to specify the ``--kms`` ``--gcp-kms`` ``--hckms`` ``--tencent-kms`` ``--pgp`` and ``--age`` parameters for creation
of all new files. If your secrets are stored under a specific directory, like a
``git`` repository, you can create a ``.sops.yaml`` configuration file at the root
directory to define which keys are used for which filename.
Expand Down Expand Up @@ -870,6 +920,10 @@ can manage the three sets of configurations for the three types of files:
- path_regex: \.hckms\.yaml$
hckms: tr-west-1:abc12345-6789-0123-4567-890123456789,tr-west-2:def67890-1234-5678-9012-345678901234

# tencent_kms files using Tencent Cloud KMS
- path_regex: \.tencent\.yaml$
tencent_kms: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# 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
Expand Down Expand Up @@ -1875,6 +1929,15 @@ To directly specify a single key group, you can use the following keys:
- tr-west-1:abc12345-6789-0123-4567-890123456789
- tr-west-1:def67890-1234-5678-9012-345678901234

* ``tencent_kms`` (list of strings): list of Tencent Cloud KMS key IDs.
Example:

.. code:: yaml

creation_rules:
- tencent_kms:
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

To specify a list of key groups, you can use the following key:

* ``key_groups`` (list of key group objects): a list of key group objects.
Expand Down Expand Up @@ -1904,6 +1967,8 @@ To specify a list of key groups, you can use the following key:
- http://my.vault/v1/sops/keys/secondkey
hckms:
- tr-west-1:abc12345-6789-0123-4567-890123456789
tencent_kms:
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

merge:
- pgp:
Expand Down Expand Up @@ -1992,6 +2057,17 @@ A key group supports the following keys:

- key_id: tr-west-1:abc12345-6789-0123-4567-890123456789

* ``tencent_kms`` (list of objects): list of Tencent Cloud KMS key IDs.
Every object must have the following key:

* ``key_id`` (string): the key ID.

Example:

.. code:: yaml

- key_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

* ``age`` (list of strings): list of Age public keys.

* ``pgp`` (list of strings): list of PGP/GPG key fingerprints.
Expand Down
86 changes: 66 additions & 20 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ import (
"github.com/getsops/sops/v3/hckms"
"github.com/getsops/sops/v3/hcvault"
"github.com/getsops/sops/v3/keys"
"github.com/getsops/sops/v3/tencentkms"
"github.com/getsops/sops/v3/keyservice"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/logging"

"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/stores"
"github.com/getsops/sops/v3/stores/dotenv"
Expand Down Expand Up @@ -91,7 +93,8 @@ func main() {
},
}
app.Name = "sops"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, HuaweiCloud KMS, Azure Key Vault, age, and GPG support"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Tencent Cloud KMS, HuaweiCloud KMS, Azure Key Vault, age, and GPG support"

app.ArgsUsage = "sops [options] file"
app.Version = version.Version
app.Authors = []cli.Author{
Expand All @@ -110,7 +113,14 @@ func main() {
(You need to setup Google application default credentials. See
https://developers.google.com/identity/protocols/application-default-credentials)

To encrypt or decrypt a document with Tencent Cloud KMS, specify the
Tencent Cloud KMS key ID in the --tencent-kms flag or in the
SOPS_TENCENT_KMS_IDS environment variable.
(You need to setup Tencent Cloud credentials via TENCENTCLOUD_SECRET_ID,
TENCENTCLOUD_SECRET_KEY, optional TENCENTCLOUD_TOKEN for STS, and TENCENTCLOUD_REGION)

To encrypt or decrypt a document with HuaweiCloud KMS, specify the

HuaweiCloud KMS key ID (format: region:key-uuid) in the --hckms flag or in the
SOPS_HUAWEICLOUD_KMS_IDS environment variable.
(You need to setup HuaweiCloud credentials via environment variables:
Expand Down Expand Up @@ -955,6 +965,7 @@ func main() {
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},

cli.StringFlag{
Name: "hc-vault-transit",
Usage: "comma separated list of vault's key URI (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev')",
Expand All @@ -970,6 +981,11 @@ func main() {
Usage: "comma separated list of age recipients",
EnvVar: "SOPS_AGE_RECIPIENTS",
},
cli.StringFlag{
Name: "tencent-kms",
Usage: "comma separated list of Tencent Cloud KMS key IDs",
EnvVar: "SOPS_TENCENT_KMS_IDS",
},
cli.StringFlag{
Name: "input-type",
Usage: "currently json, yaml, dotenv and binary are supported. If not set, sops will use the file's extension to determine the type",
Expand Down Expand Up @@ -1306,6 +1322,7 @@ func main() {
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},

cli.StringFlag{
Name: "hc-vault-transit",
Usage: "comma separated list of vault's key URI (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev')",
Expand All @@ -1321,6 +1338,11 @@ func main() {
Usage: "comma separated list of age recipients",
EnvVar: "SOPS_AGE_RECIPIENTS",
},
cli.StringFlag{
Name: "tencent-kms",
Usage: "comma separated list of Tencent Cloud KMS key IDs",
EnvVar: "SOPS_TENCENT_KMS_IDS",
},
cli.StringFlag{
Name: "input-type",
Usage: "currently json, yaml, dotenv and binary are supported. If not set, sops will use the file's extension to determine the type",
Expand Down Expand Up @@ -1704,21 +1726,22 @@ func main() {
Name: "aws-profile",
Usage: "The AWS profile to use for requests to AWS",
},
cli.StringFlag{
Name: "gcp-kms",
Usage: "comma separated list of GCP KMS resource IDs",
EnvVar: "SOPS_GCP_KMS_IDS",
},
cli.StringFlag{
Name: "hckms",
Usage: "comma separated list of HuaweiCloud KMS key IDs (format: region:key-uuid)",
EnvVar: "SOPS_HUAWEICLOUD_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},
cli.StringFlag{
Name: "gcp-kms",
Usage: "comma separated list of GCP KMS resource IDs",
EnvVar: "SOPS_GCP_KMS_IDS",
},
cli.StringFlag{
Name: "hckms",
Usage: "comma separated list of HuaweiCloud KMS key IDs (format: region:key-uuid)",
EnvVar: "SOPS_HUAWEICLOUD_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},

cli.StringFlag{
Name: "hc-vault-transit",
Usage: "comma separated list of vault's key URI (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev')",
Expand All @@ -1734,6 +1757,11 @@ func main() {
Usage: "comma separated list of age recipients",
EnvVar: "SOPS_AGE_RECIPIENTS",
},
cli.StringFlag{
Name: "tencent-kms",
Usage: "comma separated list of Tencent Cloud KMS key IDs",
EnvVar: "SOPS_TENCENT_KMS_IDS",
},
cli.BoolFlag{
Name: "in-place, i",
Usage: "write output back to the same file instead of stdout",
Expand Down Expand Up @@ -1810,6 +1838,14 @@ func main() {
Name: "rm-pgp",
Usage: "remove the provided comma-separated list of PGP fingerprints from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-tencent-kms",
Usage: "add the provided comma-separated list of Tencent Cloud KMS key IDs to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-tencent-kms",
Usage: "remove the provided comma-separated list of Tencent Cloud KMS key IDs from the list of master keys on the given file",
},
cli.BoolFlag{
Name: "ignore-mac",
Usage: "ignore Message Authentication Code during decryption",
Expand Down Expand Up @@ -2235,7 +2271,7 @@ func getEncryptConfig(c *cli.Context, fileName string, inputStore common.Store,
}, nil
}

func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, hckmsOptionName string, azureKvOptionName string, hcVaultTransitOptionName string, ageOptionName string) ([]keys.MasterKey, error) {
func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, hckmsOptionName string, azureKvOptionName string, hcVaultTransitOptionName string, ageOptionName string, tencentKmsOptionName string) ([]keys.MasterKey, error) {
var masterKeys []keys.MasterKey
for _, k := range kms.MasterKeysFromArnString(c.String(kmsOptionName), kmsEncryptionContext, c.String("aws-profile")) {
masterKeys = append(masterKeys, k)
Expand Down Expand Up @@ -2274,16 +2310,19 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO
for _, k := range ageKeys {
masterKeys = append(masterKeys, k)
}
for _, k := range tencentkms.MasterKeysFromKeyIDString(c.String(tencentKmsOptionName)) {
masterKeys = append(masterKeys, k)
}
return masterKeys, nil
}

func getRotateOpts(c *cli.Context, fileName string, inputStore common.Store, outputStore common.Store, svcs []keyservice.KeyServiceClient, decryptionOrder []string) (rotateOpts, error) {
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-hckms", "add-azure-kv", "add-hc-vault-transit", "add-age")
addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-hckms", "add-azure-kv", "add-hc-vault-transit", "add-age", "add-tencent-kms")
if err != nil {
return rotateOpts{}, err
}
rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-hckms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age")
rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-hckms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age", "rm-tencent-kms")
if err != nil {
return rotateOpts{}, err
}
Expand Down Expand Up @@ -2433,6 +2472,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
var hcVaultMkKeys []keys.MasterKey
var hckmsMkKeys []keys.MasterKey
var ageMasterKeys []keys.MasterKey
var tencentkmsMkKeys []keys.MasterKey
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
if c.String("encryption-context") != "" && kmsEncryptionContext == nil {
return nil, common.NewExitError("Invalid KMS encryption context format", codes.ErrorInvalidKMSEncryptionContextFormat)
Expand Down Expand Up @@ -2488,7 +2528,12 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
ageMasterKeys = append(ageMasterKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("hckms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" {
if c.String("tencent-kms") != "" {
for _, k := range tencentkms.MasterKeysFromKeyIDString(c.String("tencent-kms")) {
tencentkmsMkKeys = append(tencentkmsMkKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("hckms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" && c.String("tencent-kms") == "" {
conf := optionalConfig
var err error
if conf == nil {
Expand All @@ -2512,6 +2557,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
group = append(group, pgpKeys...)
group = append(group, hcVaultMkKeys...)
group = append(group, ageMasterKeys...)
group = append(group, tencentkmsMkKeys...)
log.Debugf("Master keys available: %+v", group)
return []sops.KeyGroup{group}, nil
}
Expand Down
Loading
Loading