diff --git a/CHANGELOG.md b/CHANGELOG.md index 033b2e402..93e86e9d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/README.rst b/README.rst index 866389dfd..e2e566e05 100644 --- a/README.rst +++ b/README.rst @@ -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. @@ -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. @@ -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. @@ -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 @@ -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. @@ -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: @@ -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. diff --git a/cmd/sops/main.go b/cmd/sops/main.go index fca10f303..11a91fb06 100644 --- a/cmd/sops/main.go +++ b/cmd/sops/main.go @@ -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" @@ -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{ @@ -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: @@ -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')", @@ -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", @@ -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')", @@ -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", @@ -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')", @@ -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", @@ -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", @@ -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) @@ -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 } @@ -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) @@ -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 { @@ -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 } diff --git a/config/config.go b/config/config.go index 511df1bc1..1a4f5edb7 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ package config //import "github.com/getsops/sops/v3/config" import ( "fmt" + "github.com/getsops/sops/v3/tencentkms" "os" "path" "path/filepath" @@ -130,14 +131,19 @@ type configFile struct { } type keyGroup struct { - Merge []keyGroup `yaml:"merge"` - KMS []kmsKey `yaml:"kms"` - GCPKMS []gcpKmsKey `yaml:"gcp_kms"` - HCKms []hckmsKey `yaml:"hckms"` - 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"` + HCKms []hckmsKey `yaml:"hckms"` + AzureKV []azureKVKey `yaml:"azure_keyvault"` + Vault []string `yaml:"hc_vault"` + Age []string `yaml:"age"` + PGP []string `yaml:"pgp"` + TencentKMS []tencentKMSKey `yaml:"tencent_kms"` +} + +type tencentKMSKey struct { + KeyID string `yaml:"key_id"` } type gcpKmsKey struct { @@ -185,6 +191,7 @@ type creationRule struct { HCKms []string `yaml:"hckms"` AzureKeyVault interface{} `yaml:"azure_keyvault"` // string or []string VaultURI interface{} `yaml:"hc_vault_transit_uri"` // string or []string + TencentKMS []string `yaml:"tencent_kms"` KeyGroups []keyGroup `yaml:"key_groups"` ShamirThreshold int `yaml:"shamir_threshold"` UnencryptedSuffix string `yaml:"unencrypted_suffix"` @@ -357,6 +364,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 } @@ -445,6 +455,11 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[ for _, k := range vaultKeys { keyGroup = append(keyGroup, k) } + // Tencent KMS + tencentkmsMasterKeys := tencentkms.MasterKeysFromKeyIDString(strings.Join(cRule.TencentKMS, ",")) + for _, k := range tencentkmsMasterKeys { + keyGroup = append(keyGroup, k) + } groups = append(groups, keyGroup) } return groups, nil diff --git a/go.mod b/go.mod index 0e2a0c534..d2ac119c2 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,8 @@ require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.3.7 github.com/urfave/cli v1.22.17 go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.47.0 diff --git a/go.sum b/go.sum index 3e1a3083a..7b73237e8 100644 --- a/go.sum +++ b/go.sum @@ -327,6 +327,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.3.7/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24 h1:A0FLutAc8Qvzb4Ulz7e0otGwksM7dR9no8/AiIZj9kM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.3.7 h1:xcpb2zxYNLoARq+hk91TWDtthIeuTWkhmRkZmSdbOOw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.3.7/go.mod h1:88xdoOQOMaevSlWGF5Ig7g6iNOSjTvAaUzAcOS8xnJc= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= diff --git a/keyservice/keyservice.go b/keyservice/keyservice.go index 04125f751..f5aedebeb 100644 --- a/keyservice/keyservice.go +++ b/keyservice/keyservice.go @@ -6,6 +6,7 @@ package keyservice import ( "fmt" + "github.com/getsops/sops/v3/tencentkms" "github.com/getsops/sops/v3/age" "github.com/getsops/sops/v3/azkv" @@ -87,6 +88,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { }, }, } + case *tencentkms.MasterKey: + return Key{ + KeyType: &Key_TencentKey{ + TencentKey: &TencentKey{ + KeyId: mk.KeyID, + }, + }, + } default: panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk)) } diff --git a/keyservice/keyservice.pb.go b/keyservice/keyservice.pb.go index 6314929c7..573e27fe6 100644 --- a/keyservice/keyservice.pb.go +++ b/keyservice/keyservice.pb.go @@ -1,17 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 -// protoc v5.28.3 -// source: keyservice/keyservice.proto +// protoc-gen-go v1.36.11 +// protoc v3.6.1 +// source: keyservice.proto package keyservice import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" ) const ( @@ -22,11 +22,8 @@ const ( ) type Key struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to KeyType: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to KeyType: // // *Key_KmsKey // *Key_PgpKey @@ -35,12 +32,15 @@ type Key struct { // *Key_VaultKey // *Key_AgeKey // *Key_HckmsKey - KeyType isKey_KeyType `protobuf_oneof:"key_type"` + // *Key_TencentKey + KeyType isKey_KeyType `protobuf_oneof:"key_type"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Key) Reset() { *x = Key{} - mi := &file_keyservice_keyservice_proto_msgTypes[0] + mi := &file_keyservice_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -52,7 +52,7 @@ func (x *Key) String() string { func (*Key) ProtoMessage() {} func (x *Key) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[0] + mi := &file_keyservice_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -65,61 +65,84 @@ func (x *Key) ProtoReflect() protoreflect.Message { // Deprecated: Use Key.ProtoReflect.Descriptor instead. func (*Key) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{0} + return file_keyservice_proto_rawDescGZIP(), []int{0} } -func (m *Key) GetKeyType() isKey_KeyType { - if m != nil { - return m.KeyType +func (x *Key) GetKeyType() isKey_KeyType { + if x != nil { + return x.KeyType } return nil } func (x *Key) GetKmsKey() *KmsKey { - if x, ok := x.GetKeyType().(*Key_KmsKey); ok { - return x.KmsKey + if x != nil { + if x, ok := x.KeyType.(*Key_KmsKey); ok { + return x.KmsKey + } } return nil } func (x *Key) GetPgpKey() *PgpKey { - if x, ok := x.GetKeyType().(*Key_PgpKey); ok { - return x.PgpKey + if x != nil { + if x, ok := x.KeyType.(*Key_PgpKey); ok { + return x.PgpKey + } } return nil } func (x *Key) GetGcpKmsKey() *GcpKmsKey { - if x, ok := x.GetKeyType().(*Key_GcpKmsKey); ok { - return x.GcpKmsKey + if x != nil { + if x, ok := x.KeyType.(*Key_GcpKmsKey); ok { + return x.GcpKmsKey + } } return nil } func (x *Key) GetAzureKeyvaultKey() *AzureKeyVaultKey { - if x, ok := x.GetKeyType().(*Key_AzureKeyvaultKey); ok { - return x.AzureKeyvaultKey + if x != nil { + if x, ok := x.KeyType.(*Key_AzureKeyvaultKey); ok { + return x.AzureKeyvaultKey + } } return nil } func (x *Key) GetVaultKey() *VaultKey { - if x, ok := x.GetKeyType().(*Key_VaultKey); ok { - return x.VaultKey + if x != nil { + if x, ok := x.KeyType.(*Key_VaultKey); ok { + return x.VaultKey + } } return nil } func (x *Key) GetAgeKey() *AgeKey { - if x, ok := x.GetKeyType().(*Key_AgeKey); ok { - return x.AgeKey + if x != nil { + if x, ok := x.KeyType.(*Key_AgeKey); ok { + return x.AgeKey + } } return nil } func (x *Key) GetHckmsKey() *HckmsKey { - if x, ok := x.GetKeyType().(*Key_HckmsKey); ok { - return x.HckmsKey + if x != nil { + if x, ok := x.KeyType.(*Key_HckmsKey); ok { + return x.HckmsKey + } + } + return nil +} + +func (x *Key) GetTencentKey() *TencentKey { + if x != nil { + if x, ok := x.KeyType.(*Key_TencentKey); ok { + return x.TencentKey + } } return nil } @@ -156,6 +179,10 @@ type Key_HckmsKey struct { HckmsKey *HckmsKey `protobuf:"bytes,7,opt,name=hckms_key,json=hckmsKey,proto3,oneof"` } +type Key_TencentKey struct { + TencentKey *TencentKey `protobuf:"bytes,8,opt,name=tencent_key,json=tencentKey,proto3,oneof"` +} + func (*Key_KmsKey) isKey_KeyType() {} func (*Key_PgpKey) isKey_KeyType() {} @@ -170,17 +197,62 @@ func (*Key_AgeKey) isKey_KeyType() {} func (*Key_HckmsKey) isKey_KeyType() {} -type PgpKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache +func (*Key_TencentKey) isKey_KeyType() {} + +type TencentKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TencentKey) Reset() { + *x = TencentKey{} + mi := &file_keyservice_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TencentKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TencentKey) ProtoMessage() {} + +func (x *TencentKey) ProtoReflect() protoreflect.Message { + mi := &file_keyservice_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} - Fingerprint string `protobuf:"bytes,1,opt,name=fingerprint,proto3" json:"fingerprint,omitempty"` +// Deprecated: Use TencentKey.ProtoReflect.Descriptor instead. +func (*TencentKey) Descriptor() ([]byte, []int) { + return file_keyservice_proto_rawDescGZIP(), []int{1} +} + +func (x *TencentKey) GetKeyId() string { + if x != nil { + return x.KeyId + } + return "" +} + +type PgpKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + Fingerprint string `protobuf:"bytes,1,opt,name=fingerprint,proto3" json:"fingerprint,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PgpKey) Reset() { *x = PgpKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[1] + mi := &file_keyservice_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -192,7 +264,7 @@ func (x *PgpKey) String() string { func (*PgpKey) ProtoMessage() {} func (x *PgpKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[1] + mi := &file_keyservice_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -205,7 +277,7 @@ func (x *PgpKey) ProtoReflect() protoreflect.Message { // Deprecated: Use PgpKey.ProtoReflect.Descriptor instead. func (*PgpKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{1} + return file_keyservice_proto_rawDescGZIP(), []int{2} } func (x *PgpKey) GetFingerprint() string { @@ -216,19 +288,18 @@ func (x *PgpKey) GetFingerprint() string { } type KmsKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Arn string `protobuf:"bytes,1,opt,name=arn,proto3" json:"arn,omitempty"` + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` + Context map[string]string `protobuf:"bytes,3,rep,name=context,proto3" json:"context,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + AwsProfile string `protobuf:"bytes,4,opt,name=aws_profile,json=awsProfile,proto3" json:"aws_profile,omitempty"` unknownFields protoimpl.UnknownFields - - Arn string `protobuf:"bytes,1,opt,name=arn,proto3" json:"arn,omitempty"` - Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` - Context map[string]string `protobuf:"bytes,3,rep,name=context,proto3" json:"context,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - AwsProfile string `protobuf:"bytes,4,opt,name=aws_profile,json=awsProfile,proto3" json:"aws_profile,omitempty"` + sizeCache protoimpl.SizeCache } func (x *KmsKey) Reset() { *x = KmsKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[2] + mi := &file_keyservice_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -240,7 +311,7 @@ func (x *KmsKey) String() string { func (*KmsKey) ProtoMessage() {} func (x *KmsKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[2] + mi := &file_keyservice_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -253,7 +324,7 @@ func (x *KmsKey) ProtoReflect() protoreflect.Message { // Deprecated: Use KmsKey.ProtoReflect.Descriptor instead. func (*KmsKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{2} + return file_keyservice_proto_rawDescGZIP(), []int{3} } func (x *KmsKey) GetArn() string { @@ -285,16 +356,15 @@ func (x *KmsKey) GetAwsProfile() string { } type GcpKmsKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ResourceId string `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` unknownFields protoimpl.UnknownFields - - ResourceId string `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GcpKmsKey) Reset() { *x = GcpKmsKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[3] + mi := &file_keyservice_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -306,7 +376,7 @@ func (x *GcpKmsKey) String() string { func (*GcpKmsKey) ProtoMessage() {} func (x *GcpKmsKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[3] + mi := &file_keyservice_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -319,7 +389,7 @@ func (x *GcpKmsKey) ProtoReflect() protoreflect.Message { // Deprecated: Use GcpKmsKey.ProtoReflect.Descriptor instead. func (*GcpKmsKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{3} + return file_keyservice_proto_rawDescGZIP(), []int{4} } func (x *GcpKmsKey) GetResourceId() string { @@ -330,18 +400,17 @@ func (x *GcpKmsKey) GetResourceId() string { } type VaultKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + VaultAddress string `protobuf:"bytes,1,opt,name=vault_address,json=vaultAddress,proto3" json:"vault_address,omitempty"` + EnginePath string `protobuf:"bytes,2,opt,name=engine_path,json=enginePath,proto3" json:"engine_path,omitempty"` + KeyName string `protobuf:"bytes,3,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"` unknownFields protoimpl.UnknownFields - - VaultAddress string `protobuf:"bytes,1,opt,name=vault_address,json=vaultAddress,proto3" json:"vault_address,omitempty"` - EnginePath string `protobuf:"bytes,2,opt,name=engine_path,json=enginePath,proto3" json:"engine_path,omitempty"` - KeyName string `protobuf:"bytes,3,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *VaultKey) Reset() { *x = VaultKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[4] + mi := &file_keyservice_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -353,7 +422,7 @@ func (x *VaultKey) String() string { func (*VaultKey) ProtoMessage() {} func (x *VaultKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[4] + mi := &file_keyservice_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -366,7 +435,7 @@ func (x *VaultKey) ProtoReflect() protoreflect.Message { // Deprecated: Use VaultKey.ProtoReflect.Descriptor instead. func (*VaultKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{4} + return file_keyservice_proto_rawDescGZIP(), []int{5} } func (x *VaultKey) GetVaultAddress() string { @@ -391,18 +460,17 @@ func (x *VaultKey) GetKeyName() string { } type AzureKeyVaultKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + VaultUrl string `protobuf:"bytes,1,opt,name=vault_url,json=vaultUrl,proto3" json:"vault_url,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` unknownFields protoimpl.UnknownFields - - VaultUrl string `protobuf:"bytes,1,opt,name=vault_url,json=vaultUrl,proto3" json:"vault_url,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AzureKeyVaultKey) Reset() { *x = AzureKeyVaultKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[5] + mi := &file_keyservice_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -414,7 +482,7 @@ func (x *AzureKeyVaultKey) String() string { func (*AzureKeyVaultKey) ProtoMessage() {} func (x *AzureKeyVaultKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[5] + mi := &file_keyservice_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -427,7 +495,7 @@ func (x *AzureKeyVaultKey) ProtoReflect() protoreflect.Message { // Deprecated: Use AzureKeyVaultKey.ProtoReflect.Descriptor instead. func (*AzureKeyVaultKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{5} + return file_keyservice_proto_rawDescGZIP(), []int{6} } func (x *AzureKeyVaultKey) GetVaultUrl() string { @@ -452,16 +520,15 @@ func (x *AzureKeyVaultKey) GetVersion() string { } type AgeKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Recipient string `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` unknownFields protoimpl.UnknownFields - - Recipient string `protobuf:"bytes,1,opt,name=recipient,proto3" json:"recipient,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AgeKey) Reset() { *x = AgeKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[6] + mi := &file_keyservice_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -473,7 +540,7 @@ func (x *AgeKey) String() string { func (*AgeKey) ProtoMessage() {} func (x *AgeKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[6] + mi := &file_keyservice_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -486,7 +553,7 @@ func (x *AgeKey) ProtoReflect() protoreflect.Message { // Deprecated: Use AgeKey.ProtoReflect.Descriptor instead. func (*AgeKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{6} + return file_keyservice_proto_rawDescGZIP(), []int{7} } func (x *AgeKey) GetRecipient() string { @@ -497,16 +564,15 @@ func (x *AgeKey) GetRecipient() string { } type HckmsKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"` unknownFields protoimpl.UnknownFields - - KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HckmsKey) Reset() { *x = HckmsKey{} - mi := &file_keyservice_keyservice_proto_msgTypes[7] + mi := &file_keyservice_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -518,7 +584,7 @@ func (x *HckmsKey) String() string { func (*HckmsKey) ProtoMessage() {} func (x *HckmsKey) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[7] + mi := &file_keyservice_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -531,7 +597,7 @@ func (x *HckmsKey) ProtoReflect() protoreflect.Message { // Deprecated: Use HckmsKey.ProtoReflect.Descriptor instead. func (*HckmsKey) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{7} + return file_keyservice_proto_rawDescGZIP(), []int{8} } func (x *HckmsKey) GetKeyId() string { @@ -542,17 +608,16 @@ func (x *HckmsKey) GetKeyId() string { } type EncryptRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Plaintext []byte `protobuf:"bytes,2,opt,name=plaintext,proto3" json:"plaintext,omitempty"` unknownFields protoimpl.UnknownFields - - Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Plaintext []byte `protobuf:"bytes,2,opt,name=plaintext,proto3" json:"plaintext,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EncryptRequest) Reset() { *x = EncryptRequest{} - mi := &file_keyservice_keyservice_proto_msgTypes[8] + mi := &file_keyservice_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -564,7 +629,7 @@ func (x *EncryptRequest) String() string { func (*EncryptRequest) ProtoMessage() {} func (x *EncryptRequest) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[8] + mi := &file_keyservice_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -577,7 +642,7 @@ func (x *EncryptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EncryptRequest.ProtoReflect.Descriptor instead. func (*EncryptRequest) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{8} + return file_keyservice_proto_rawDescGZIP(), []int{9} } func (x *EncryptRequest) GetKey() *Key { @@ -595,16 +660,15 @@ func (x *EncryptRequest) GetPlaintext() []byte { } type EncryptResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Ciphertext []byte `protobuf:"bytes,1,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` unknownFields protoimpl.UnknownFields - - Ciphertext []byte `protobuf:"bytes,1,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EncryptResponse) Reset() { *x = EncryptResponse{} - mi := &file_keyservice_keyservice_proto_msgTypes[9] + mi := &file_keyservice_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -616,7 +680,7 @@ func (x *EncryptResponse) String() string { func (*EncryptResponse) ProtoMessage() {} func (x *EncryptResponse) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[9] + mi := &file_keyservice_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -629,7 +693,7 @@ func (x *EncryptResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EncryptResponse.ProtoReflect.Descriptor instead. func (*EncryptResponse) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{9} + return file_keyservice_proto_rawDescGZIP(), []int{10} } func (x *EncryptResponse) GetCiphertext() []byte { @@ -640,17 +704,16 @@ func (x *EncryptResponse) GetCiphertext() []byte { } type DecryptRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Ciphertext []byte `protobuf:"bytes,2,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` unknownFields protoimpl.UnknownFields - - Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Ciphertext []byte `protobuf:"bytes,2,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DecryptRequest) Reset() { *x = DecryptRequest{} - mi := &file_keyservice_keyservice_proto_msgTypes[10] + mi := &file_keyservice_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -662,7 +725,7 @@ func (x *DecryptRequest) String() string { func (*DecryptRequest) ProtoMessage() {} func (x *DecryptRequest) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[10] + mi := &file_keyservice_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -675,7 +738,7 @@ func (x *DecryptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DecryptRequest.ProtoReflect.Descriptor instead. func (*DecryptRequest) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{10} + return file_keyservice_proto_rawDescGZIP(), []int{11} } func (x *DecryptRequest) GetKey() *Key { @@ -693,16 +756,15 @@ func (x *DecryptRequest) GetCiphertext() []byte { } type DecryptResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plaintext []byte `protobuf:"bytes,1,opt,name=plaintext,proto3" json:"plaintext,omitempty"` unknownFields protoimpl.UnknownFields - - Plaintext []byte `protobuf:"bytes,1,opt,name=plaintext,proto3" json:"plaintext,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DecryptResponse) Reset() { *x = DecryptResponse{} - mi := &file_keyservice_keyservice_proto_msgTypes[11] + mi := &file_keyservice_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -714,7 +776,7 @@ func (x *DecryptResponse) String() string { func (*DecryptResponse) ProtoMessage() {} func (x *DecryptResponse) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[11] + mi := &file_keyservice_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -727,7 +789,7 @@ func (x *DecryptResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DecryptResponse.ProtoReflect.Descriptor instead. func (*DecryptResponse) Descriptor() ([]byte, []int) { - return file_keyservice_keyservice_proto_rawDescGZIP(), []int{11} + return file_keyservice_proto_rawDescGZIP(), []int{12} } func (x *DecryptResponse) GetPlaintext() []byte { @@ -737,148 +799,131 @@ func (x *DecryptResponse) GetPlaintext() []byte { return nil } -var File_keyservice_keyservice_proto protoreflect.FileDescriptor - -var file_keyservice_keyservice_proto_rawDesc = []byte{ - 0x0a, 0x1b, 0x6b, 0x65, 0x79, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6b, 0x65, 0x79, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc2, 0x02, - 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x48, - 0x00, 0x52, 0x06, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x07, 0x70, 0x67, 0x70, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x50, 0x67, 0x70, - 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x06, 0x70, 0x67, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, - 0x0b, 0x67, 0x63, 0x70, 0x5f, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x47, 0x63, 0x70, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x48, 0x00, - 0x52, 0x09, 0x67, 0x63, 0x70, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x12, 0x61, - 0x7a, 0x75, 0x72, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4b, - 0x65, 0x79, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x10, 0x61, 0x7a, - 0x75, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x28, - 0x0a, 0x09, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x09, 0x2e, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x08, - 0x76, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x07, 0x61, 0x67, 0x65, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x41, 0x67, 0x65, 0x4b, - 0x65, 0x79, 0x48, 0x00, 0x52, 0x06, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x09, - 0x68, 0x63, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x09, 0x2e, 0x48, 0x63, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x08, 0x68, 0x63, - 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x2a, 0x0a, 0x06, 0x50, 0x67, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, - 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x22, 0xbb, - 0x01, 0x0a, 0x06, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x72, - 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, - 0x2e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, - 0x1f, 0x0a, 0x0b, 0x61, 0x77, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x77, 0x73, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x1a, 0x3a, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2c, 0x0a, 0x09, - 0x47, 0x63, 0x70, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x22, 0x6b, 0x0a, 0x08, 0x56, 0x61, - 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x76, - 0x61, 0x75, 0x6c, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, - 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, - 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x0a, 0x10, 0x41, 0x7a, 0x75, 0x72, 0x65, - 0x4b, 0x65, 0x79, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x76, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x76, 0x61, 0x75, 0x6c, 0x74, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x06, 0x41, 0x67, 0x65, 0x4b, 0x65, 0x79, - 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x21, - 0x0a, 0x08, 0x48, 0x63, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, - 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, - 0x64, 0x22, 0x46, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x04, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x70, - 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, - 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x31, 0x0a, 0x0f, 0x45, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x22, 0x48, 0x0a, 0x0e, - 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x4b, 0x65, - 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, - 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, - 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x22, 0x2f, 0x0a, 0x0f, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x6c, - 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x32, 0x6c, 0x0a, 0x0a, 0x4b, 0x65, 0x79, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x12, 0x0f, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x10, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x07, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x12, 0x0f, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x10, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +var File_keyservice_proto protoreflect.FileDescriptor + +const file_keyservice_proto_rawDesc = "" + + "\n" + + "\x10keyservice.proto\"\xf2\x02\n" + + "\x03Key\x12\"\n" + + "\akms_key\x18\x01 \x01(\v2\a.KmsKeyH\x00R\x06kmsKey\x12\"\n" + + "\apgp_key\x18\x02 \x01(\v2\a.PgpKeyH\x00R\x06pgpKey\x12,\n" + + "\vgcp_kms_key\x18\x03 \x01(\v2\n" + + ".GcpKmsKeyH\x00R\tgcpKmsKey\x12A\n" + + "\x12azure_keyvault_key\x18\x04 \x01(\v2\x11.AzureKeyVaultKeyH\x00R\x10azureKeyvaultKey\x12(\n" + + "\tvault_key\x18\x05 \x01(\v2\t.VaultKeyH\x00R\bvaultKey\x12\"\n" + + "\aage_key\x18\x06 \x01(\v2\a.AgeKeyH\x00R\x06ageKey\x12(\n" + + "\thckms_key\x18\a \x01(\v2\t.HckmsKeyH\x00R\bhckmsKey\x12.\n" + + "\vtencent_key\x18\b \x01(\v2\v.TencentKeyH\x00R\n" + + "tencentKeyB\n" + + "\n" + + "\bkey_type\"#\n" + + "\n" + + "TencentKey\x12\x15\n" + + "\x06key_id\x18\x01 \x01(\tR\x05keyId\"*\n" + + "\x06PgpKey\x12 \n" + + "\vfingerprint\x18\x01 \x01(\tR\vfingerprint\"\xbb\x01\n" + + "\x06KmsKey\x12\x10\n" + + "\x03arn\x18\x01 \x01(\tR\x03arn\x12\x12\n" + + "\x04role\x18\x02 \x01(\tR\x04role\x12.\n" + + "\acontext\x18\x03 \x03(\v2\x14.KmsKey.ContextEntryR\acontext\x12\x1f\n" + + "\vaws_profile\x18\x04 \x01(\tR\n" + + "awsProfile\x1a:\n" + + "\fContextEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\",\n" + + "\tGcpKmsKey\x12\x1f\n" + + "\vresource_id\x18\x01 \x01(\tR\n" + + "resourceId\"k\n" + + "\bVaultKey\x12#\n" + + "\rvault_address\x18\x01 \x01(\tR\fvaultAddress\x12\x1f\n" + + "\vengine_path\x18\x02 \x01(\tR\n" + + "enginePath\x12\x19\n" + + "\bkey_name\x18\x03 \x01(\tR\akeyName\"]\n" + + "\x10AzureKeyVaultKey\x12\x1b\n" + + "\tvault_url\x18\x01 \x01(\tR\bvaultUrl\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x03 \x01(\tR\aversion\"&\n" + + "\x06AgeKey\x12\x1c\n" + + "\trecipient\x18\x01 \x01(\tR\trecipient\"!\n" + + "\bHckmsKey\x12\x15\n" + + "\x06key_id\x18\x01 \x01(\tR\x05keyId\"F\n" + + "\x0eEncryptRequest\x12\x16\n" + + "\x03key\x18\x01 \x01(\v2\x04.KeyR\x03key\x12\x1c\n" + + "\tplaintext\x18\x02 \x01(\fR\tplaintext\"1\n" + + "\x0fEncryptResponse\x12\x1e\n" + + "\n" + + "ciphertext\x18\x01 \x01(\fR\n" + + "ciphertext\"H\n" + + "\x0eDecryptRequest\x12\x16\n" + + "\x03key\x18\x01 \x01(\v2\x04.KeyR\x03key\x12\x1e\n" + + "\n" + + "ciphertext\x18\x02 \x01(\fR\n" + + "ciphertext\"/\n" + + "\x0fDecryptResponse\x12\x1c\n" + + "\tplaintext\x18\x01 \x01(\fR\tplaintext2l\n" + + "\n" + + "KeyService\x12.\n" + + "\aEncrypt\x12\x0f.EncryptRequest\x1a\x10.EncryptResponse\"\x00\x12.\n" + + "\aDecrypt\x12\x0f.DecryptRequest\x1a\x10.DecryptResponse\"\x00B\x0eZ\f./keyserviceb\x06proto3" var ( - file_keyservice_keyservice_proto_rawDescOnce sync.Once - file_keyservice_keyservice_proto_rawDescData = file_keyservice_keyservice_proto_rawDesc + file_keyservice_proto_rawDescOnce sync.Once + file_keyservice_proto_rawDescData []byte ) -func file_keyservice_keyservice_proto_rawDescGZIP() []byte { - file_keyservice_keyservice_proto_rawDescOnce.Do(func() { - file_keyservice_keyservice_proto_rawDescData = protoimpl.X.CompressGZIP(file_keyservice_keyservice_proto_rawDescData) +func file_keyservice_proto_rawDescGZIP() []byte { + file_keyservice_proto_rawDescOnce.Do(func() { + file_keyservice_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_keyservice_proto_rawDesc), len(file_keyservice_proto_rawDesc))) }) - return file_keyservice_keyservice_proto_rawDescData + return file_keyservice_proto_rawDescData } -var file_keyservice_keyservice_proto_msgTypes = make([]protoimpl.MessageInfo, 13) -var file_keyservice_keyservice_proto_goTypes = []any{ +var file_keyservice_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_keyservice_proto_goTypes = []any{ (*Key)(nil), // 0: Key - (*PgpKey)(nil), // 1: PgpKey - (*KmsKey)(nil), // 2: KmsKey - (*GcpKmsKey)(nil), // 3: GcpKmsKey - (*VaultKey)(nil), // 4: VaultKey - (*AzureKeyVaultKey)(nil), // 5: AzureKeyVaultKey - (*AgeKey)(nil), // 6: AgeKey - (*HckmsKey)(nil), // 7: HckmsKey - (*EncryptRequest)(nil), // 8: EncryptRequest - (*EncryptResponse)(nil), // 9: EncryptResponse - (*DecryptRequest)(nil), // 10: DecryptRequest - (*DecryptResponse)(nil), // 11: DecryptResponse - nil, // 12: KmsKey.ContextEntry -} -var file_keyservice_keyservice_proto_depIdxs = []int32{ - 2, // 0: Key.kms_key:type_name -> KmsKey - 1, // 1: Key.pgp_key:type_name -> PgpKey - 3, // 2: Key.gcp_kms_key:type_name -> GcpKmsKey - 5, // 3: Key.azure_keyvault_key:type_name -> AzureKeyVaultKey - 4, // 4: Key.vault_key:type_name -> VaultKey - 6, // 5: Key.age_key:type_name -> AgeKey - 7, // 6: Key.hckms_key:type_name -> HckmsKey - 12, // 7: KmsKey.context:type_name -> KmsKey.ContextEntry - 0, // 8: EncryptRequest.key:type_name -> Key - 0, // 9: DecryptRequest.key:type_name -> Key - 8, // 10: KeyService.Encrypt:input_type -> EncryptRequest - 10, // 11: KeyService.Decrypt:input_type -> DecryptRequest - 9, // 12: KeyService.Encrypt:output_type -> EncryptResponse - 11, // 13: KeyService.Decrypt:output_type -> DecryptResponse - 12, // [12:14] is the sub-list for method output_type - 10, // [10:12] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name -} - -func init() { file_keyservice_keyservice_proto_init() } -func file_keyservice_keyservice_proto_init() { - if File_keyservice_keyservice_proto != nil { + (*TencentKey)(nil), // 1: TencentKey + (*PgpKey)(nil), // 2: PgpKey + (*KmsKey)(nil), // 3: KmsKey + (*GcpKmsKey)(nil), // 4: GcpKmsKey + (*VaultKey)(nil), // 5: VaultKey + (*AzureKeyVaultKey)(nil), // 6: AzureKeyVaultKey + (*AgeKey)(nil), // 7: AgeKey + (*HckmsKey)(nil), // 8: HckmsKey + (*EncryptRequest)(nil), // 9: EncryptRequest + (*EncryptResponse)(nil), // 10: EncryptResponse + (*DecryptRequest)(nil), // 11: DecryptRequest + (*DecryptResponse)(nil), // 12: DecryptResponse + nil, // 13: KmsKey.ContextEntry +} +var file_keyservice_proto_depIdxs = []int32{ + 3, // 0: Key.kms_key:type_name -> KmsKey + 2, // 1: Key.pgp_key:type_name -> PgpKey + 4, // 2: Key.gcp_kms_key:type_name -> GcpKmsKey + 6, // 3: Key.azure_keyvault_key:type_name -> AzureKeyVaultKey + 5, // 4: Key.vault_key:type_name -> VaultKey + 7, // 5: Key.age_key:type_name -> AgeKey + 8, // 6: Key.hckms_key:type_name -> HckmsKey + 1, // 7: Key.tencent_key:type_name -> TencentKey + 13, // 8: KmsKey.context:type_name -> KmsKey.ContextEntry + 0, // 9: EncryptRequest.key:type_name -> Key + 0, // 10: DecryptRequest.key:type_name -> Key + 9, // 11: KeyService.Encrypt:input_type -> EncryptRequest + 11, // 12: KeyService.Decrypt:input_type -> DecryptRequest + 10, // 13: KeyService.Encrypt:output_type -> EncryptResponse + 12, // 14: KeyService.Decrypt:output_type -> DecryptResponse + 13, // [13:15] is the sub-list for method output_type + 11, // [11:13] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name +} + +func init() { file_keyservice_proto_init() } +func file_keyservice_proto_init() { + if File_keyservice_proto != nil { return } - file_keyservice_keyservice_proto_msgTypes[0].OneofWrappers = []any{ + file_keyservice_proto_msgTypes[0].OneofWrappers = []any{ (*Key_KmsKey)(nil), (*Key_PgpKey)(nil), (*Key_GcpKmsKey)(nil), @@ -886,23 +931,23 @@ func file_keyservice_keyservice_proto_init() { (*Key_VaultKey)(nil), (*Key_AgeKey)(nil), (*Key_HckmsKey)(nil), + (*Key_TencentKey)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_keyservice_keyservice_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_keyservice_proto_rawDesc), len(file_keyservice_proto_rawDesc)), NumEnums: 0, - NumMessages: 13, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_keyservice_keyservice_proto_goTypes, - DependencyIndexes: file_keyservice_keyservice_proto_depIdxs, - MessageInfos: file_keyservice_keyservice_proto_msgTypes, + GoTypes: file_keyservice_proto_goTypes, + DependencyIndexes: file_keyservice_proto_depIdxs, + MessageInfos: file_keyservice_proto_msgTypes, }.Build() - File_keyservice_keyservice_proto = out.File - file_keyservice_keyservice_proto_rawDesc = nil - file_keyservice_keyservice_proto_goTypes = nil - file_keyservice_keyservice_proto_depIdxs = nil + File_keyservice_proto = out.File + file_keyservice_proto_goTypes = nil + file_keyservice_proto_depIdxs = nil } diff --git a/keyservice/keyservice.proto b/keyservice/keyservice.proto index 3a471a34f..080482f6b 100644 --- a/keyservice/keyservice.proto +++ b/keyservice/keyservice.proto @@ -11,6 +11,7 @@ message Key { VaultKey vault_key = 5; AgeKey age_key = 6; HckmsKey hckms_key = 7; + TencentKey tencent_key = 8; } } @@ -49,6 +50,10 @@ message HckmsKey { string key_id = 1; } +message TencentKey { + string key_id = 1; +} + message EncryptRequest { Key key = 1; bytes plaintext = 2; diff --git a/keyservice/keyservice_grpc.pb.go b/keyservice/keyservice_grpc.pb.go index d278b82d9..e24c79a6b 100644 --- a/keyservice/keyservice_grpc.pb.go +++ b/keyservice/keyservice_grpc.pb.go @@ -1,8 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v5.28.3 -// source: keyservice/keyservice.proto +// - protoc-gen-go-grpc v1.6.0 +// - protoc v3.6.1 +// source: keyservice.proto package keyservice @@ -60,14 +60,15 @@ func (c *keyServiceClient) Decrypt(ctx context.Context, in *DecryptRequest, opts } // KeyServiceServer is the server API for KeyService service. -// All implementations should embed UnimplementedKeyServiceServer +// All implementations must embed UnimplementedKeyServiceServer // for forward compatibility. type KeyServiceServer interface { Encrypt(context.Context, *EncryptRequest) (*EncryptResponse, error) Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) + mustEmbedUnimplementedKeyServiceServer() } -// UnimplementedKeyServiceServer should be embedded to have +// UnimplementedKeyServiceServer must be embedded to have // forward compatible implementations. // // NOTE: this should be embedded by value instead of pointer to avoid a nil @@ -75,12 +76,13 @@ type KeyServiceServer interface { type UnimplementedKeyServiceServer struct{} func (UnimplementedKeyServiceServer) Encrypt(context.Context, *EncryptRequest) (*EncryptResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Encrypt not implemented") + return nil, status.Error(codes.Unimplemented, "method Encrypt not implemented") } func (UnimplementedKeyServiceServer) Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Decrypt not implemented") + return nil, status.Error(codes.Unimplemented, "method Decrypt not implemented") } -func (UnimplementedKeyServiceServer) testEmbeddedByValue() {} +func (UnimplementedKeyServiceServer) mustEmbedUnimplementedKeyServiceServer() {} +func (UnimplementedKeyServiceServer) testEmbeddedByValue() {} // UnsafeKeyServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to KeyServiceServer will @@ -90,7 +92,7 @@ type UnsafeKeyServiceServer interface { } func RegisterKeyServiceServer(s grpc.ServiceRegistrar, srv KeyServiceServer) { - // If the following call pancis, it indicates UnimplementedKeyServiceServer was + // If the following call panics, it indicates UnimplementedKeyServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -153,5 +155,5 @@ var KeyService_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "keyservice/keyservice.proto", + Metadata: "keyservice.proto", } diff --git a/keyservice/server.go b/keyservice/server.go index c1f1e8ce8..d8f2946ca 100644 --- a/keyservice/server.go +++ b/keyservice/server.go @@ -2,6 +2,7 @@ package keyservice import ( "fmt" + "github.com/getsops/sops/v3/tencentkms" "github.com/getsops/sops/v3/age" "github.com/getsops/sops/v3/azkv" @@ -19,6 +20,7 @@ import ( type Server struct { // Prompt indicates whether the server should prompt before decrypting or encrypting data Prompt bool + UnimplementedKeyServiceServer } func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error) { @@ -100,6 +102,17 @@ func (ks *Server) encryptWithAge(key *AgeKey, plaintext []byte) ([]byte, error) return []byte(ageKey.EncryptedKey), nil } +func (ks *Server) encryptWithTencentKms(key *TencentKey, plaintext []byte) ([]byte, error) { + tencentKmsKey := tencentkms.MasterKey{ + KeyID: key.KeyId, + } + err := tencentKmsKey.Encrypt(plaintext) + if err != nil { + return nil, err + } + return []byte(tencentKmsKey.EncryptedKey), nil +} + func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error) { pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint) pgpKey.EncryptedKey = string(ciphertext) @@ -167,6 +180,15 @@ func (ks *Server) decryptWithAge(key *AgeKey, ciphertext []byte) ([]byte, error) return []byte(plaintext), err } +func (ks *Server) decryptWithTencentKms(key *TencentKey, ciphertext []byte) ([]byte, error) { + tencentKmsKey := tencentkms.MasterKey{ + KeyID: key.KeyId, + } + tencentKmsKey.EncryptedKey = string(ciphertext) + plaintext, err := tencentKmsKey.Decrypt() + return []byte(plaintext), err +} + // Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted // result func (ks Server) Encrypt(ctx context.Context, @@ -230,6 +252,14 @@ func (ks Server) Encrypt(ctx context.Context, response = &EncryptResponse{ Ciphertext: ciphertext, } + case *Key_TencentKey: + ciphertext, err := ks.encryptWithTencentKms(k.TencentKey, req.Plaintext) + if err != nil { + return nil, err + } + response = &EncryptResponse{ + Ciphertext: ciphertext, + } case nil: return nil, status.Errorf(codes.NotFound, "Must provide a key") default: @@ -258,6 +288,8 @@ func keyToString(key *Key) string { return fmt.Sprintf("Hashicorp Vault key with URI %s/v1/%s/keys/%s", k.VaultKey.VaultAddress, k.VaultKey.EnginePath, k.VaultKey.KeyName) case *Key_HckmsKey: return fmt.Sprintf("HuaweiCloud KMS key with ID %s", k.HckmsKey.KeyId) + case *Key_TencentKey: + return fmt.Sprintf("Tencent KMS key with ID %s", k.TencentKey.KeyId) default: return "Unknown key type" } @@ -342,6 +374,14 @@ func (ks Server) Decrypt(ctx context.Context, response = &DecryptResponse{ Plaintext: plaintext, } + case *Key_TencentKey: + plaintext, err := ks.decryptWithTencentKms(k.TencentKey, req.Ciphertext) + if err != nil { + return nil, err + } + response = &DecryptResponse{ + Plaintext: plaintext, + } case nil: return nil, status.Errorf(codes.NotFound, "Must provide a key") default: diff --git a/stores/stores.go b/stores/stores.go index 11e362a5d..0692f1071 100644 --- a/stores/stores.go +++ b/stores/stores.go @@ -23,6 +23,7 @@ import ( "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" "github.com/getsops/sops/v3/pgp" + "github.com/getsops/sops/v3/tencentkms" ) const ( @@ -44,37 +45,41 @@ type SopsFile struct { // in order to allow the binary format to stay backwards compatible over time, but at the same time allow the internal // representation SOPS uses to change over time. type Metadata struct { - ShamirThreshold int `yaml:"shamir_threshold,omitempty" json:"shamir_threshold,omitempty"` - KeyGroups []keygroup `yaml:"key_groups,omitempty" json:"key_groups,omitempty"` - KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` - GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` - HCKmsKeys []hckmskey `yaml:"hckms,omitempty" json:"hckms,omitempty"` - AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` - VaultKeys []vaultkey `yaml:"hc_vault,omitempty" json:"hc_vault,omitempty"` - AgeKeys []agekey `yaml:"age,omitempty" json:"age,omitempty"` - LastModified string `yaml:"lastmodified" json:"lastmodified"` - MessageAuthenticationCode string `yaml:"mac" json:"mac"` - PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"` - UnencryptedSuffix string `yaml:"unencrypted_suffix,omitempty" json:"unencrypted_suffix,omitempty"` - EncryptedSuffix string `yaml:"encrypted_suffix,omitempty" json:"encrypted_suffix,omitempty"` - UnencryptedRegex string `yaml:"unencrypted_regex,omitempty" json:"unencrypted_regex,omitempty"` - EncryptedRegex string `yaml:"encrypted_regex,omitempty" json:"encrypted_regex,omitempty"` - UnencryptedCommentRegex string `yaml:"unencrypted_comment_regex,omitempty" json:"unencrypted_comment_regex,omitempty"` - EncryptedCommentRegex string `yaml:"encrypted_comment_regex,omitempty" json:"encrypted_comment_regex,omitempty"` - MACOnlyEncrypted bool `yaml:"mac_only_encrypted,omitempty" json:"mac_only_encrypted,omitempty"` - Version string `yaml:"version" json:"version"` + ShamirThreshold int `yaml:"shamir_threshold,omitempty" json:"shamir_threshold,omitempty"` + KeyGroups []keygroup `yaml:"key_groups,omitempty" json:"key_groups,omitempty"` + KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` + GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` + HCKmsKeys []hckmskey `yaml:"hckms,omitempty" json:"hckms,omitempty"` + AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` + VaultKeys []vaultkey `yaml:"hc_vault,omitempty" json:"hc_vault,omitempty"` + AgeKeys []agekey `yaml:"age,omitempty" json:"age,omitempty"` + TencentKeys []tencentkey `yaml:"tencent_kms,omitempty" json:"tencent_kms,omitempty"` + LastModified string `yaml:"lastmodified" json:"lastmodified"` + MessageAuthenticationCode string `yaml:"mac" json:"mac"` + PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"` + UnencryptedSuffix string `yaml:"unencrypted_suffix,omitempty" json:"unencrypted_suffix,omitempty"` + EncryptedSuffix string `yaml:"encrypted_suffix,omitempty" json:"encrypted_suffix,omitempty"` + UnencryptedRegex string `yaml:"unencrypted_regex,omitempty" json:"unencrypted_regex,omitempty"` + EncryptedRegex string `yaml:"encrypted_regex,omitempty" json:"encrypted_regex,omitempty"` + UnencryptedCommentRegex string `yaml:"unencrypted_comment_regex,omitempty" json:"unencrypted_comment_regex,omitempty"` + EncryptedCommentRegex string `yaml:"encrypted_comment_regex,omitempty" json:"encrypted_comment_regex,omitempty"` + MACOnlyEncrypted bool `yaml:"mac_only_encrypted,omitempty" json:"mac_only_encrypted,omitempty"` + Version string `yaml:"version" json:"version"` } type keygroup struct { - PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"` - KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` - GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` - HCKmsKeys []hckmskey `yaml:"hckms,omitempty" json:"hckms,omitempty"` - AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` - VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"` - AgeKeys []agekey `yaml:"age" json:"age"` + PGPKeys []pgpkey `yaml:"pgp,omitempty" json:"pgp,omitempty"` + KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` + GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` + HCKmsKeys []hckmskey `yaml:"hckms,omitempty" json:"hckms,omitempty"` + AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` + VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"` + AgeKeys []agekey `yaml:"age" json:"age"` + TencentKeys []tencentkey `yaml:"tencent_kms" json:"tencent_kms"` } + + type pgpkey struct { CreatedAt string `yaml:"created_at" json:"created_at"` EncryptedDataKey string `yaml:"enc" json:"enc"` @@ -123,6 +128,14 @@ type hckmskey struct { EncryptedDataKey string `yaml:"enc" json:"enc"` } +type tencentkey struct { + KeyID string `yaml:"key_id" json:"key_id"` + CreatedAt string `yaml:"created_at" json:"created_at"` + EncryptedDataKey string `yaml:"enc" json:"enc"` +} + + + // MetadataFromInternal converts an internal SOPS metadata representation to a representation appropriate for storage func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { var m Metadata @@ -146,6 +159,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { m.VaultKeys = vaultKeysFromGroup(group) m.AzureKeyVaultKeys = azkvKeysFromGroup(group) m.AgeKeys = ageKeysFromGroup(group) + m.TencentKeys = tencentKeysFromGroup(group) } else { for _, group := range sopsMetadata.KeyGroups { m.KeyGroups = append(m.KeyGroups, keygroup{ @@ -156,6 +170,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { VaultKeys: vaultKeysFromGroup(group), AzureKeyVaultKeys: azkvKeysFromGroup(group), AgeKeys: ageKeysFromGroup(group), + TencentKeys: tencentKeysFromGroup(group), }) } } @@ -266,6 +281,20 @@ func hckmsKeysFromGroup(group sops.KeyGroup) (keys []hckmskey) { return } +func tencentKeysFromGroup(group sops.KeyGroup) (keys []tencentkey) { + for _, key := range group { + switch key := key.(type) { + case *tencentkms.MasterKey: + keys = append(keys, tencentkey{ + KeyID: key.KeyID, + CreatedAt: key.CreationDate.Format(time.RFC3339), + EncryptedDataKey: key.EncryptedKey, + }) + } + } + return +} + // ToInternal converts a storage-appropriate Metadata struct to a SOPS internal representation func (m *Metadata) ToInternal() (sops.Metadata, error) { lastModified, err := time.Parse(time.RFC3339, m.LastModified) @@ -320,7 +349,8 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) { }, nil } -func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, hckmsKeys []hckmskey, azkvKeys []azkvkey, vaultKeys []vaultkey, ageKeys []agekey) (sops.KeyGroup, error) { +func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, hckmsKeys []hckmskey, azkvKeys []azkvkey, + vaultKeys []vaultkey, ageKeys []agekey, tencentKeys []tencentkey) (sops.KeyGroup, error) { var internalGroup sops.KeyGroup for _, kmsKey := range kmsKeys { k, err := kmsKey.toInternal() @@ -371,13 +401,23 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske } internalGroup = append(internalGroup, k) } + + for _, tencentKey := range tencentKeys { + k, err := tencentKey.toInternal() + if err != nil { + return nil, err + } + internalGroup = append(internalGroup, k) + } return internalGroup, nil } func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) { var internalGroups []sops.KeyGroup - if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.HCKmsKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 { - internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.HCKmsKeys, m.AzureKeyVaultKeys, m.VaultKeys, m.AgeKeys) + if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.HCKmsKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 || len(m.TencentKeys) > 0 { + + internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.HCKmsKeys, m.AzureKeyVaultKeys, m.VaultKeys, m.AgeKeys, m.TencentKeys) + if err != nil { return nil, err } @@ -385,7 +425,8 @@ func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) { return internalGroups, nil } else if len(m.KeyGroups) > 0 { for _, group := range m.KeyGroups { - internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.HCKmsKeys, group.AzureKeyVaultKeys, group.VaultKeys, group.AgeKeys) + internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.HCKmsKeys, group.AzureKeyVaultKeys, group.VaultKeys, group.AgeKeys, group.TencentKeys) + if err != nil { return nil, err } @@ -485,6 +526,19 @@ func (hckmsKey *hckmskey) toInternal() (*hckms.MasterKey, error) { return key, nil } + +func (tencentkey *tencentkey) toInternal() (*tencentkms.MasterKey, error) { + creationDate, err := time.Parse(time.RFC3339, tencentkey.CreatedAt) + if err != nil { + return nil, err + } + return &tencentkms.MasterKey{ + KeyID: tencentkey.KeyID, + EncryptedKey: tencentkey.EncryptedDataKey, + CreationDate: creationDate, + }, nil +} + // ExampleComplexTree is an example sops.Tree object exhibiting complex relationships var ExampleComplexTree = sops.Tree{ Branches: sops.TreeBranches{ diff --git a/stores/stores_test.go b/stores/stores_test.go index 31ced210a..4f664b554 100644 --- a/stores/stores_test.go +++ b/stores/stores_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" ) - func TestValToString(t *testing.T) { assert.Equal(t, "1", ValToString(1)) assert.Equal(t, "1.0", ValToString(1.0)) diff --git a/tencentkms/keysource.go b/tencentkms/keysource.go new file mode 100644 index 000000000..d76853794 --- /dev/null +++ b/tencentkms/keysource.go @@ -0,0 +1,261 @@ +/* +Package tencentkms contains an implementation of the github.com/getsops/sops/v3/keys.MasterKey +interface that encrypts and decrypts the data key using Tencent Cloud KMS with the +Tencent Cloud SDK for Go. +*/ +package tencentkms // import "github.com/getsops/sops/v3/tencentkms" + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strings" + "time" + + "github.com/getsops/sops/v3/logging" + "github.com/sirupsen/logrus" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + kms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms/v20190118" +) + +const ( + // KeyTypeIdentifier is the string used to identify a Tencent Cloud KMS MasterKey. + KeyTypeIdentifier = "tencent_kms" + // TencentKmsEnvVar is the environment variable name for Tencent Cloud KMS key IDs. + TencentKmsEnvVar = "SOPS_TENCENT_KMS_IDS" + + // TencentSecretIdEnvVar is the environment variable name for Tencent Cloud SecretId. + TencentSecretIdEnvVar = "TENCENTCLOUD_SECRET_ID" + // TencentSecretKeyEnvVar is the environment variable name for Tencent Cloud SecretKey. + TencentSecretKeyEnvVar = "TENCENTCLOUD_SECRET_KEY" + // TencentTokenEnvVar is the environment variable name for Tencent Cloud Token (optional, for STS). + TencentTokenEnvVar = "TENCENTCLOUD_TOKEN" + // TencentRegionEnvVar is the environment variable name for Tencent Cloud region. + TencentRegionEnvVar = "TENCENTCLOUD_REGION" + // TencentKMSEndpointEnvVar is the environment variable name for Tencent Cloud kms service endpoint. + TencentKMSEndpointEnvVar = "TENCENTCLOUD_KMS_ENDPOINT" +) + +var ( + // log is the global logger for any Tencent Cloud KMS MasterKey. + log *logrus.Logger + // tencent kms TTL is the duration after which a MasterKey requires rotation. + tencentkmsTTL = time.Hour * 24 * 30 * 6 +) + +func init() { + log = logging.NewLogger("TENCENT_KMS") +} + +// MasterKey is a Tencent Cloud KMS Key used to Encrypt and Decrypt SOPS' data key. +type MasterKey struct { + // KeyID is the ID of the Tencent Cloud KMS key. + KeyID string + // Region is the region of the Tencent Cloud KMS key. + Region string + // EncryptedKey contains the SOPS data key encrypted with the Tencent Cloud KMS key. + EncryptedKey string + // CreationDate of the MasterKey, used to determine if the EncryptedKey needs rotation. + CreationDate time.Time + + // secretId is the Tencent Cloud SecretId used for authentication. + secretId string + // secretKey is the Tencent Cloud SecretKey used for authentication. + secretKey string + // token is the Tencent Cloud STS token used for authentication (optional). + token string +} + +// NewMasterKeyFromKeyID creates a new MasterKey with the provided Key ID. +func NewMasterKeyFromKeyID(keyID string) *MasterKey { + k := &MasterKey{} + keyID = strings.Replace(keyID, " ", "", -1) + k.KeyID = keyID + k.CreationDate = time.Now().UTC() + return k +} + +// MasterKeysFromKeyIDString takes a comma separated list of Tencent KMS +// KeyIDs and returns a slice of new MasterKeys for them. +func MasterKeysFromKeyIDString(keyID string) []*MasterKey { + var keys []*MasterKey + if keyID == "" { + return keys + } + for _, s := range strings.Split(keyID, ",") { + keys = append(keys, NewMasterKeyFromKeyID(s)) + } + return keys +} + +// Encrypt takes a SOPS data key, encrypts it with Tencent Cloud KMS, and stores the result in the EncryptedKey field. +// Consider using EncryptContext instead. +func (key *MasterKey) Encrypt(dataKey []byte) error { + return key.EncryptContext(context.Background(), dataKey) +} + +// EncryptContext takes a SOPS data key, encrypts it with Tencent Cloud KMS, and stores the result in the EncryptedKey field. +func (key *MasterKey) EncryptContext(ctx context.Context, dataKey []byte) error { + client, err := key.createClient() + if err != nil { + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(err).Error("Failed to create Tencent Cloud KMS client") + return fmt.Errorf("failed to create Tencent Cloud KMS client: %w", err) + } + + // Create encryption request + request := kms.NewEncryptRequest() + request.KeyId = common.StringPtr(key.KeyID) + request.Plaintext = common.StringPtr(base64.StdEncoding.EncodeToString(dataKey)) + + // Send encryption request + response, err := client.EncryptWithContext(ctx, request) + if err != nil { + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(err).Error("Failed to encrypt data key with Tencent Cloud KMS") + return fmt.Errorf("failed to encrypt data key with Tencent Cloud KMS: %w", err) + } + + // Store the encrypted key + key.EncryptedKey = *response.Response.CiphertextBlob + log.WithFields(logrus.Fields{"keyId": key.KeyID}).Info("Encryption successful") + return nil +} + +// EncryptIfNeeded encrypts the provided SOPS data key, if it has not been encrypted yet. +func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error { + if key.EncryptedKey == "" { + return key.Encrypt(dataKey) + } + return nil +} + +// EncryptedDataKey returns the encrypted data key this master key holds. +func (key *MasterKey) EncryptedDataKey() []byte { + return []byte(key.EncryptedKey) +} + +// SetEncryptedDataKey sets the encrypted data key for this master key. +func (key *MasterKey) SetEncryptedDataKey(encrypted []byte) { + key.EncryptedKey = string(encrypted) +} + +// Decrypt decrypts the EncryptedKey field with Tencent Cloud KMS and returns the result. +func (key *MasterKey) Decrypt() ([]byte, error) { + return key.DecryptContext(context.Background()) +} + +// DecryptContext decrypts the EncryptedKey field with Tencent Cloud KMS and returns the result. +func (key *MasterKey) DecryptContext(ctx context.Context) ([]byte, error) { + if key.EncryptedKey == "" { + return nil, fmt.Errorf("master key is empty") + } + + client, err := key.createClient() + if err != nil { + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(err).Error("Failed to create Tencent Cloud KMS client") + return nil, fmt.Errorf("failed to create Tencent Cloud KMS client: %w", err) + } + + // Create decryption request + request := kms.NewDecryptRequest() + request.CiphertextBlob = common.StringPtr(key.EncryptedKey) + + // Send decryption request + response, err := client.DecryptWithContext(ctx, request) + if err != nil { + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(err).Error("Failed to decrypt data key with Tencent Cloud KMS") + return nil, fmt.Errorf("failed to decrypt data key with Tencent Cloud KMS: %w", err) + } + + decodedCipher, err := base64.StdEncoding.DecodeString(*response.Response.Plaintext) + if err != nil { + log.WithField("keyId", key.KeyID).WithError(err).Error("Failed to decode decrypted plaintext") + return nil, err + } + + log.WithFields(logrus.Fields{"keyId": key.KeyID}).Info("Decryption successful") + return decodedCipher, nil +} + +// NeedsRotation returns whether the data key needs to be rotated or not. +func (key *MasterKey) NeedsRotation() bool { + return time.Since(key.CreationDate) > (tencentkmsTTL) +} + +// ToString converts the master key to a string representation. +func (key *MasterKey) ToString() string { + return key.KeyID +} + +// ToMap converts the master key to a map representation. +func (key *MasterKey) ToMap() map[string]interface{} { + return map[string]interface{}{ + "keyId": key.KeyID, + "created_at": key.CreationDate.UTC().Format(time.RFC3339), + "enc": key.EncryptedKey, + } +} + +// TypeToIdentifier returns the key type identifier. +func (key *MasterKey) TypeToIdentifier() string { + return KeyTypeIdentifier +} + +// createClient creates a new Tencent Cloud KMS client with support for multiple authentication methods. +func (key *MasterKey) createClient() (*kms.Client, error) { + credential, err := key.getCredential() + if err != nil { + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(err).Error("Failed to obtain Tencent Cloud credentials") + return nil, fmt.Errorf("failed to obtain Tencent Cloud credentials: %w", err) + } + + if credential == nil { + credErr := fmt.Errorf("no valid credentials found. Please set TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY environment variables") + log.WithFields(logrus.Fields{"keyId": key.KeyID}).WithError(credErr).Error("Failed to obtain Tencent Cloud credentials") + return nil, credErr + } + + region := os.Getenv(TencentRegionEnvVar) + if region == "" { + region = "ap-guangzhou" + } + + cpf := profile.NewClientProfile() + endpoint := os.Getenv(TencentKMSEndpointEnvVar) + if endpoint != "" { + cpf.HttpProfile.Endpoint = endpoint + } + + client, err := kms.NewClient(credential, region, cpf) + if err != nil { + return nil, fmt.Errorf("failed to create Tencent KMS client for region %s: %w", region, err) + } + + return client, nil +} + +// getCredential gets authentication credentials, supports multiple methods +func (key *MasterKey) getCredential() (common.CredentialIface, error) { + if secretId, ok := os.LookupEnv(TencentSecretIdEnvVar); ok && len(secretId) > 0 { + key.secretId = secretId + } + + if secretKey, ok := os.LookupEnv(TencentSecretKeyEnvVar); ok && len(secretKey) > 0 { + key.secretKey = secretKey + } + + if key.secretId == "" && key.secretKey == "" { + return nil, fmt.Errorf("environment variable TENCENTCLOUD_SECRET_ID or TENCENTCLOUD_SECRET_KEY is not set") + } + + if token, ok := os.LookupEnv(TencentTokenEnvVar); ok && len(token) > 0 { + key.token = token + } + + if key.token != "" { + return common.NewTokenCredential(key.secretId, key.secretKey, key.token), nil + } + + return common.NewCredential(key.secretId, key.secretKey), nil +} \ No newline at end of file diff --git a/tencentkms/keysource_integration_test.go b/tencentkms/keysource_integration_test.go new file mode 100644 index 000000000..533d58d6b --- /dev/null +++ b/tencentkms/keysource_integration_test.go @@ -0,0 +1,107 @@ +//go:build integration + +package tencentkms + +import ( + "os" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +const testTencentKMSKeyIDEnvVar = "SOPS_TENCENT_KMS_KEY_ID" + +// TestEncryptDecryptIntegration tests the full encrypt-decrypt cycle with real KMS operations +// This test requires valid Tencent KMS credentials to be set as environment variables +func TestEncryptDecryptIntegration(t *testing.T) { + keyID := requireTencentKMSEnv(t) + + // Test cases for encryption and decryption + testCases := []struct { + name string + plaintext string + expectError bool + }{{ + name: "Simple string encryption", + plaintext: "Hello, Tencent KMS!", + expectError: false, + }, { + name: "Empty string encryption", + plaintext: "", + expectError: true, + }, { + name: "Long string encryption", + plaintext: generateLongString(1000), // 1000 characters + expectError: false, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a new master key + masterKey := NewMasterKeyFromKeyID(keyID) + masterKey.CreationDate = time.Now().UTC() + + err := masterKey.Encrypt([]byte(tc.plaintext)) + if tc.expectError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.NotNil(t, masterKey.EncryptedKey) + + // Decrypt the data key + decryptedKey, err := masterKey.Decrypt() + assert.NoError(t, err) + assert.NotNil(t, decryptedKey) + assert.Equal(t, tc.plaintext, string(decryptedKey)) + + // Verify key rotation status (should not need rotation if recently created) + assert.False(t, masterKey.NeedsRotation(), "Newly created key should not need rotation") + }) + } +} + +// generateLongString creates a string of the specified length for testing +func generateLongString(length int) string { + result := make([]byte, length) + for i := 0; i < length; i++ { + result[i] = byte(65 + (i % 26)) // A-Z characters + } + return string(result) +} + +func requireTencentKMSEnv(t *testing.T) string { + t.Helper() + + requiredVars := []struct { + name string + value string + }{ + {name: TencentSecretIdEnvVar, value: os.Getenv(TencentSecretIdEnvVar)}, + {name: TencentSecretKeyEnvVar, value: os.Getenv(TencentSecretKeyEnvVar)}, + {name: TencentRegionEnvVar, value: os.Getenv(TencentRegionEnvVar)}, + {name: testTencentKMSKeyIDEnvVar, value: os.Getenv(testTencentKMSKeyIDEnvVar)}, + } + + missing := make([]string, 0) + var keyID string + + for _, envVar := range requiredVars { + if envVar.value == "" { + missing = append(missing, envVar.name) + continue + } + + if envVar.name == testTencentKMSKeyIDEnvVar { + keyID = envVar.value + } + } + + if len(missing) > 0 { + t.Skipf("skip: please configure %s before running integration tests", strings.Join(missing, ", ")) + } + + return keyID +} \ No newline at end of file diff --git a/tencentkms/keysource_test.go b/tencentkms/keysource_test.go new file mode 100644 index 000000000..355109e67 --- /dev/null +++ b/tencentkms/keysource_test.go @@ -0,0 +1,338 @@ +package tencentkms + +import ( + "context" + "encoding/base64" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var ( + // dummyKeyID + dummyKeyID = "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx" + // dummyRegion + dummyRegion = "ap-singapore" + // dummyEncryptedKey + dummyEncryptedKey = "dummy-encrypted-key" +) + +// TestNewMasterKeyFromKeyID tests creating MasterKey from key ID +func TestNewMasterKeyFromKeyID(t *testing.T) { + t.Run("normal creation", func(t *testing.T) { + key := NewMasterKeyFromKeyID(dummyKeyID) + assert.Equal(t, dummyKeyID, key.KeyID) + assert.NotNil(t, key.CreationDate) + assert.Empty(t, key.Region) + assert.Empty(t, key.EncryptedKey) + }) + + t.Run("remove spaces", func(t *testing.T) { + key := NewMasterKeyFromKeyID(" xxxxx-xxxxx-xxxxx-xxxxx-xxxxx ") + assert.Equal(t, dummyKeyID, key.KeyID) + }) + + t.Run("empty string", func(t *testing.T) { + key := NewMasterKeyFromKeyID("") + assert.Empty(t, key.KeyID) + assert.NotNil(t, key.CreationDate) + }) +} + +// TestMasterKeysFromKeyIDString tests creating multiple MasterKeys from comma-separated key ID string +func TestMasterKeysFromKeyIDString(t *testing.T) { + t.Run("single key", func(t *testing.T) { + keys := MasterKeysFromKeyIDString(dummyKeyID) + assert.Len(t, keys, 1) + assert.Equal(t, dummyKeyID, keys[0].KeyID) + }) + + t.Run("multiple keys", func(t *testing.T) { + keyID2 := "yyyyy-yyyyy-yyyyy-yyyyy-yyyyy" + keys := MasterKeysFromKeyIDString(dummyKeyID + "," + keyID2) + assert.Len(t, keys, 2) + assert.Equal(t, dummyKeyID, keys[0].KeyID) + assert.Equal(t, keyID2, keys[1].KeyID) + }) + + t.Run("empty string", func(t *testing.T) { + keys := MasterKeysFromKeyIDString("") + assert.Len(t, keys, 0) + }) + + t.Run("with spaces", func(t *testing.T) { + keyID2 := "yyyyy-yyyyy-yyyyy-yyyyy-yyyyy" + keys := MasterKeysFromKeyIDString(dummyKeyID + ", " + keyID2) + assert.Len(t, keys, 2) + assert.Equal(t, dummyKeyID, keys[0].KeyID) + assert.Equal(t, keyID2, keys[1].KeyID) + }) + + t.Run("empty elements", func(t *testing.T) { + keys := MasterKeysFromKeyIDString(dummyKeyID + ",,") + assert.Len(t, keys, 3) // Empty strings will still create MasterKey + assert.Equal(t, dummyKeyID, keys[0].KeyID) + assert.Empty(t, keys[1].KeyID) + assert.Empty(t, keys[2].KeyID) + }) +} + +// TestMasterKey_EncryptIfNeeded tests encryption when needed +func TestMasterKey_EncryptIfNeeded(t *testing.T) { + // Since actual encryption requires Tencent Cloud KMS service, we use mock data for testing + key := &MasterKey{ + KeyID: dummyKeyID, + secretId: "mock-secret-id", // Set mock credentials to avoid nil reference + secretKey: "mock-secret-key", + Region: dummyRegion, + } + + // We can't actually call Tencent Cloud KMS, so we verify the logic flow + // Actual encryption will return an error, but EncryptIfNeeded should call Encrypt + err := key.EncryptIfNeeded([]byte("test-data")) + assert.Error(t, err) // Expected to fail because we're using mock credentials + + // Manually set encrypted key, then test that it won't be re-encrypted + key.EncryptedKey = dummyEncryptedKey + err = key.EncryptIfNeeded([]byte("different-data")) + assert.NoError(t, err) + assert.Equal(t, dummyEncryptedKey, key.EncryptedKey) // Confirm key wasn't modified +} + +// TestMasterKey_EncryptedDataKey tests getting encrypted data key +func TestMasterKey_EncryptedDataKey(t *testing.T) { + key := &MasterKey{EncryptedKey: dummyEncryptedKey} + assert.EqualValues(t, []byte(dummyEncryptedKey), key.EncryptedDataKey()) + + key = &MasterKey{EncryptedKey: ""} + assert.EqualValues(t, []byte(""), key.EncryptedDataKey()) +} + +// TestMasterKey_SetEncryptedDataKey tests setting encrypted data key +func TestMasterKey_SetEncryptedDataKey(t *testing.T) { + key := &MasterKey{} + data := []byte("test-encrypted-data") + key.SetEncryptedDataKey(data) + assert.Equal(t, string(data), key.EncryptedKey) + + // Test empty data + key.SetEncryptedDataKey([]byte{}) + assert.Equal(t, "", key.EncryptedKey) +} + +// TestMasterKey_NeedsRotation tests if key rotation is needed +func TestMasterKey_NeedsRotation(t *testing.T) { + key := NewMasterKeyFromKeyID(dummyKeyID) + assert.False(t, key.NeedsRotation()) // Newly created key doesn't need rotation + + // Set an expired creation time (significantly greater than TTL) + key.CreationDate = time.Now().UTC().Add(-(tencentkmsTTL + 24*time.Hour)) + assert.True(t, key.NeedsRotation()) + + // Set time significantly less than TTL to avoid precision issues + // We'll use a 1 hour difference to ensure it's clearly less than TTL + key.CreationDate = time.Now().UTC().Add(-(tencentkmsTTL - time.Hour)) + assert.False(t, key.NeedsRotation()) + + // We'll skip the exact TTL test due to time precision issues + // The implementation clearly uses '>' which means only strictly greater than TTL returns true +} + +// TestMasterKey_ToString tests conversion to string +func TestMasterKey_ToString(t *testing.T) { + key := NewMasterKeyFromKeyID(dummyKeyID) + assert.Equal(t, dummyKeyID, key.ToString()) + + key = NewMasterKeyFromKeyID("") + assert.Equal(t, "", key.ToString()) +} + +// TestMasterKey_ToMap tests conversion to map +func TestMasterKey_ToMap(t *testing.T) { + fixedTime := time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC) + key := &MasterKey{ + KeyID: dummyKeyID, + CreationDate: fixedTime, + EncryptedKey: dummyEncryptedKey, + } + + expectedMap := map[string]interface{}{ + "keyId": dummyKeyID, + "created_at": fixedTime.UTC().Format(time.RFC3339), + "enc": dummyEncryptedKey, + } + + resultMap := key.ToMap() + assert.Equal(t, expectedMap, resultMap) + + // Test empty value case + key = &MasterKey{ + KeyID: "", + CreationDate: fixedTime, + EncryptedKey: "", + } + + emptyExpectedMap := map[string]interface{}{ + "keyId": "", + "created_at": fixedTime.UTC().Format(time.RFC3339), + "enc": "", + } + + assert.Equal(t, emptyExpectedMap, key.ToMap()) +} + +// TestMasterKey_TypeToIdentifier tests type identifier +func TestMasterKey_TypeToIdentifier(t *testing.T) { + key := NewMasterKeyFromKeyID(dummyKeyID) + assert.Equal(t, KeyTypeIdentifier, key.TypeToIdentifier()) +} + +// TestMasterKey_createClient tests client creation logic +func TestMasterKey_createClient(t *testing.T) { + // Save original environment variables + originalSecretId := os.Getenv(TencentSecretIdEnvVar) + originalSecretKey := os.Getenv(TencentSecretKeyEnvVar) + originalRegion := os.Getenv(TencentRegionEnvVar) + defer func() { + // Restore original environment variables + os.Unsetenv(TencentSecretIdEnvVar) + os.Unsetenv(TencentSecretKeyEnvVar) + os.Unsetenv(TencentRegionEnvVar) + if originalSecretId != "" { + os.Setenv(TencentSecretIdEnvVar, originalSecretId) + } + if originalSecretKey != "" { + os.Setenv(TencentSecretKeyEnvVar, originalSecretKey) + } + if originalRegion != "" { + os.Setenv(TencentRegionEnvVar, originalRegion) + } + }() + + t.Run("use credentials from environment", func(t *testing.T) { + os.Setenv(TencentSecretIdEnvVar, "env-secret-id") + os.Setenv(TencentSecretKeyEnvVar, "env-secret-key") + os.Setenv(TencentRegionEnvVar, "env-region") + + key := &MasterKey{ + KeyID: dummyKeyID, + } + + client, err := key.createClient() + assert.NotNil(t, client, "should create client object from environment variables") + _ = err // Avoid unused variable warning + }) + + t.Run("prioritize credentials in key", func(t *testing.T) { + os.Setenv(TencentSecretIdEnvVar, "env-secret-id") + os.Setenv(TencentSecretKeyEnvVar, "env-secret-key") + os.Setenv(TencentRegionEnvVar, "env-region") + + key := &MasterKey{ + KeyID: dummyKeyID, + Region: "key-region", + secretId: "key-secret-id", + secretKey: "key-secret-key", + } + + // Check if function runs without crashing + client, err := key.createClient() + assert.NotNil(t, client, "should create client object") + _ = err // Avoid unused variable warning + }) + + t.Run("empty credentials", func(t *testing.T) { + key := &MasterKey{ + KeyID: dummyKeyID, + } + + // Check if client can be created with empty credentials (may return error or default client) + client, err := key.createClient() + // Don't make strict assertions, just ensure test doesn't crash + if err != nil { + assert.Error(t, err, "empty credentials may return error") + } else { + assert.NotNil(t, client, "empty credentials may return default client") + } + }) +} + +// TestEncryptDecryptMock tests encryption and decryption process (using mock data) +func TestEncryptDecryptMock(t *testing.T) { + // Create a key + key := &MasterKey{ + KeyID: dummyKeyID, + Region: dummyRegion, + secretId: "mock-secret-id", + secretKey: "mock-secret-key", + } + + // Test encryption (will fail but test the flow) + dataKey := []byte("test-data-key") + err := key.Encrypt(dataKey) + assert.Error(t, err) // Expected to fail because we're using mock credentials + + // Manually set encrypted key + key.EncryptedKey = base64.StdEncoding.EncodeToString(dataKey) + + // Test decryption (will fail but test the flow) + _, err = key.Decrypt() + assert.Error(t, err) // Expected to fail because we're using mock credentials +} + +// TestEncryptContextDecryptContextMock tests context-aware encryption and decryption process (using mock data) +func TestEncryptContextDecryptContextMock(t *testing.T) { + // Create a key + key := &MasterKey{ + KeyID: dummyKeyID, + Region: dummyRegion, + secretId: "mock-secret-id", + secretKey: "mock-secret-key", + } + + // Create a context + ctx := context.Background() + + // Test context-aware encryption (will fail but test the flow) + dataKey := []byte("test-data-key") + err := key.EncryptContext(ctx, dataKey) + assert.Error(t, err) // Expected to fail because we're using mock credentials + + // Manually set encrypted key + key.EncryptedKey = base64.StdEncoding.EncodeToString(dataKey) + + // Test context-aware decryption (will fail but test the flow) + _, err = key.DecryptContext(ctx) + assert.Error(t, err) // Expected to fail because we're using mock credentials + + // Test decryption with empty encrypted key + key.EncryptedKey = "" + _, err = key.DecryptContext(ctx) + assert.Error(t, err) + assert.Equal(t, "master key is empty", err.Error()) +} + +// TestTimeCalculations tests time calculation related functionality +func TestTimeCalculations(t *testing.T) { + // Verify TTL value + expectedTTL := time.Hour * 24 * 30 * 6 // 6 months + assert.Equal(t, expectedTTL, tencentkmsTTL) + + // Test time comparison logic + key := NewMasterKeyFromKeyID(dummyKeyID) + now := time.Now().UTC() + + // Newly created key doesn't need rotation + key.CreationDate = now + assert.False(t, key.NeedsRotation()) + + // Key close to but not exceeding TTL doesn't need rotation + key.CreationDate = now.Add(-(tencentkmsTTL - 24*time.Hour)) + assert.False(t, key.NeedsRotation()) + + // Key exceeding TTL needs rotation + key.CreationDate = now.Add(-(tencentkmsTTL + 24*time.Hour)) + assert.True(t, key.NeedsRotation()) +}