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
84 changes: 72 additions & 12 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/getsops/sops/v3/stores"
"github.com/getsops/sops/v3/stores/dotenv"
"github.com/getsops/sops/v3/stores/json"
"github.com/getsops/sops/v3/tencentkms"
"github.com/getsops/sops/v3/version"
)

Expand Down Expand Up @@ -97,7 +98,7 @@ func main() {
{Name: "CNCF Maintainers"},
}
app.UsageText = `sops is an editor of encrypted files that supports AWS KMS, GCP, AZKV,
PGP, and Age
PGP, Tencent Cloud KMS,and Age

To encrypt or decrypt a document with AWS KMS, specify the KMS ARN
in the -k flag or in the SOPS_KMS_ARN environment variable.
Expand Down Expand Up @@ -126,6 +127,12 @@ func main() {
https://docs.microsoft.com/en-us/go/azure/azure-sdk-go-authorization#use-environment-based-authentication.
The user/sp needs the key/encrypt and key/decrypt permissions.)

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.
The format is 'keyId' (e.g., '93866e69-9755-11ef-8e65-52540089bc41').
(Authentication is based on TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY environment variables.)

To encrypt or decrypt using age, specify the recipient in the -a flag,
or in the SOPS_AGE_RECIPIENTS environment variable.

Expand All @@ -135,12 +142,12 @@ func main() {
To use multiple KMS or PGP keys, separate them by commas. For example:
$ sops -p "10F2...0A, 85D...B3F21" file.yaml

The -p, -k, --gcp-kms, --hc-vault-transit, and --azure-kv flags are only
The -p, -k, --gcp-kms, --hc-vault-transit, --tencent-kms, and --azure-kv flags are only
used to encrypt new documents. Editing or decrypting existing documents
can be done with "sops file" or "sops decrypt file" respectively. The KMS and
PGP keys listed in the encrypted documents are used then. To manage master
keys in existing documents, use the "add-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit}"
and "rm-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit}" flags with --rotate
keys in existing documents, use the "add-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit,tencent-kms}"
and "rm-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit,tencent-kms}" flags with --rotate
or the updatekeys command.

To use a different GPG binary than the one in your PATH, set SOPS_GPG_EXEC.
Expand Down Expand Up @@ -570,6 +577,10 @@ func main() {
Name: "gcp-kms",
Usage: "the GCP KMS Resource ID the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "tencent-kms",
Usage: "the Tencent Cloud KMS key ID the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "azure-kv",
Usage: "the Azure Key Vault key URL the new group should contain. Can be specified more than once",
Expand Down Expand Up @@ -602,6 +613,7 @@ func main() {
vaultURIs := c.StringSlice("hc-vault-transit")
azkvs := c.StringSlice("azure-kv")
ageRecipients := c.StringSlice("age")
tencentKms := c.StringSlice("tencent-kms")
if c.NArg() != 0 {
return common.NewExitError(fmt.Errorf("error: no positional arguments allowed"), codes.ErrorGeneric)
}
Expand Down Expand Up @@ -641,6 +653,11 @@ func main() {
group = append(group, key)
}
}

for _, keyID := range tencentKms {
group = append(group, tencentkms.NewMasterKeyFromKeyID(keyID))
}

inputStore, err := inputStore(c, c.String("file"))
if err != nil {
return toExitError(err)
Expand Down Expand Up @@ -953,6 +970,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 @@ -1158,6 +1180,16 @@ 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.StringFlag{
Name: "filename-override",
Usage: "Use this filename instead of the provided argument for loading configuration, and for determining input type and output type",
Expand All @@ -1184,8 +1216,8 @@ func main() {
return toExitError(err)
}
if _, err := os.Stat(fileName); os.IsNotExist(err) {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-tencent-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-tencent-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
return common.NewExitError(fmt.Sprintf("Error: cannot add or remove keys on non-existent file %q, use the `edit` subcommand instead.", fileName), codes.CannotChangeKeysFromNonExistentFile)
}
}
Expand Down Expand Up @@ -1271,6 +1303,11 @@ func main() {
Usage: "comma separated list of GCP KMS resource IDs",
EnvVar: "SOPS_GCP_KMS_IDS",
},
cli.StringFlag{
Name: "tencent-kms",
Usage: "comma separated list of Tencent Cloud KMS key IDs",
EnvVar: "SOPS_TENCENT_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
Expand Down Expand Up @@ -1684,6 +1721,11 @@ func main() {
Usage: "comma separated list of Azure Key Vault URLs",
EnvVar: "SOPS_AZURE_KEYVAULT_URLS",
},
cli.StringFlag{
Name: "tencent-kms",
Usage: "comma separated list of Tencent Cloud KMS key IDs",
EnvVar: "SOPS_TENCENT_KMS_IDS",
},
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 Down Expand Up @@ -1735,6 +1777,14 @@ func main() {
Name: "rm-azure-kv",
Usage: "remove the provided comma-separated list of Azure Key Vault key URLs 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.StringFlag{
Name: "add-kms",
Usage: "add the provided comma-separated list of KMS ARNs to the list of master keys on the given file",
Expand Down Expand Up @@ -1861,8 +1911,8 @@ func main() {
return toExitError(err)
}
if _, err := os.Stat(fileName); os.IsNotExist(err) {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-tencent-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-tencent-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
return common.NewExitError(fmt.Sprintf("Error: cannot add or remove keys on non-existent file %q, use `--kms` and `--pgp` instead.", fileName), codes.CannotChangeKeysFromNonExistentFile)
}
if isEncryptMode || isDecryptMode || isRotateMode {
Expand Down Expand Up @@ -2191,7 +2241,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, azureKvOptionName string, hcVaultTransitOptionName string, ageOptionName string) ([]keys.MasterKey, error) {
func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName 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 All @@ -2209,6 +2259,9 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO
for _, k := range azureKeys {
masterKeys = append(masterKeys, k)
}
for _, k := range tencentkms.MasterKeysFromKeyIDString(c.String(tencentKmsOptionName)) {
masterKeys = append(masterKeys, k)
}
hcVaultKeys, err := hcvault.NewMasterKeysFromURIs(c.String(hcVaultTransitOptionName))
if err != nil {
return nil, err
Expand All @@ -2228,11 +2281,11 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO

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-azure-kv", "add-hc-vault-transit", "add-age")
addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "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-azure-kv", "rm-hc-vault-transit", "rm-age")
rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age", "rm-tencent-kms")
if err != nil {
return rotateOpts{}, err
}
Expand Down Expand Up @@ -2381,6 +2434,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
var azkvKeys []keys.MasterKey
var hcVaultMkKeys []keys.MasterKey
var ageMasterKeys []keys.MasterKey
var tencentKmsKeys []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 All @@ -2404,6 +2458,11 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
azkvKeys = append(azkvKeys, k)
}
}
if c.String("tencent-kms") != "" {
for _, k := range tencentkms.MasterKeysFromKeyIDString(c.String("tencent-kms")) {
tencentKmsKeys = append(tencentKmsKeys, k)
}
}
if c.String("hc-vault-transit") != "" {
hcVaultKeys, err := hcvault.NewMasterKeysFromURIs(c.String("hc-vault-transit"))
if err != nil {
Expand All @@ -2427,7 +2486,7 @@ 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("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" {
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && 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 @@ -2447,6 +2506,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
group = append(group, kmsKeys...)
group = append(group, cloudKmsKeys...)
group = append(group, azkvKeys...)
group = append(group, tencentKmsKeys...)
group = append(group, pgpKeys...)
group = append(group, hcVaultMkKeys...)
group = append(group, ageMasterKeys...)
Expand Down
35 changes: 28 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/publish"
"github.com/getsops/sops/v3/tencentkms"
"go.yaml.in/yaml/v3"
)

Expand Down Expand Up @@ -129,13 +130,14 @@ type configFile struct {
}

type keyGroup struct {
Merge []keyGroup `yaml:"merge"`
KMS []kmsKey `yaml:"kms"`
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
AzureKV []azureKVKey `yaml:"azure_keyvault"`
Vault []string `yaml:"hc_vault"`
Age []string `yaml:"age"`
PGP []string `yaml:"pgp"`
Merge []keyGroup `yaml:"merge"`
KMS []kmsKey `yaml:"kms"`
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
AzureKV []azureKVKey `yaml:"azure_keyvault"`
Vault []string `yaml:"hc_vault"`
Age []string `yaml:"age"`
PGP []string `yaml:"pgp"`
TencentKMS []tencentKmsKey `yaml:"tencent_kms"`
}

type gcpKmsKey struct {
Expand All @@ -155,6 +157,10 @@ type azureKVKey struct {
Version string `yaml:"version"`
}

type tencentKmsKey struct {
KeyID string `yaml:"key_id"`
}

type destinationRule struct {
PathRegex string `yaml:"path_regex"`
S3Bucket string `yaml:"s3_bucket"`
Expand All @@ -178,6 +184,7 @@ type creationRule struct {
GCPKMS interface{} `yaml:"gcp_kms"` // string or []string
AzureKeyVault interface{} `yaml:"azure_keyvault"` // string or []string
VaultURI interface{} `yaml:"hc_vault_transit_uri"` // string or []string
TencentKMS interface{} `yaml:"tencent_kms"` // string or []string
KeyGroups []keyGroup `yaml:"key_groups"`
ShamirThreshold int `yaml:"shamir_threshold"`
UnencryptedSuffix string `yaml:"unencrypted_suffix"`
Expand All @@ -198,6 +205,10 @@ func (c *creationRule) GetAgeKeys() ([]string, error) {
return parseKeyField(c.Age, "age")
}

func (c *creationRule) GetTencentKMSKeys() ([]string, error) {
return parseKeyField(c.TencentKMS, "tencent_kms")
}

func (c *creationRule) GetPGPKeys() ([]string, error) {
return parseKeyField(c.PGP, "pgp")
}
Expand Down Expand Up @@ -343,6 +354,9 @@ func extractMasterKeys(group keyGroup) (sops.KeyGroup, error) {
return nil, err
}
}
for _, k := range group.TencentKMS {
keyGroup = append(keyGroup, tencentkms.NewMasterKeyFromKeyID(k.KeyID))
}
return deduplicateKeygroup(keyGroup), nil
}

Expand Down Expand Up @@ -424,6 +438,13 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
for _, k := range vaultKeys {
keyGroup = append(keyGroup, k)
}
tencentKMSKeys, err := getKeysWithValidation(cRule.GetTencentKMSKeys, "tencent_kms")
if err != nil {
return nil, err
}
for _, k := range tencentKMSKeys {
keyGroup = append(keyGroup, tencentkms.NewMasterKeyFromKeyID(k))
}
groups = append(groups, keyGroup)
}
return groups, nil
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ require (
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.11.1
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.46
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.1.3
github.com/urfave/cli v1.22.17
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/crypto v0.43.0
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.3/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.46 h1:wWcfc+d0BJSGvLtIdPSLuN//KCgIhuWbjao68roZrzw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.46/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.1.3 h1:HAGbYdcJcQtUQxU9Y7W/Rh0CwYAOKeZCeDeqtQXT16U=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.1.3/go.mod h1:Xko/+Z18akdtRaU9HXIyAn/Xatxywl7PNgW2iud1uvU=
github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ=
github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
Expand Down
9 changes: 9 additions & 0 deletions keyservice/keyservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/getsops/sops/v3/keys"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/tencentkms"
)

// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers
Expand Down Expand Up @@ -78,6 +79,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *tencentkms.MasterKey:
return Key{
KeyType: &Key_TencentKmsKey{
TencentKmsKey: &TencentKmsKey{
KeyId: mk.KeyID,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}
Expand Down
Loading