diff --git a/README.rst b/README.rst index 1f73860d3..881ab7648 100644 --- a/README.rst +++ b/README.rst @@ -514,6 +514,22 @@ To easily deploy Vault locally: (DO NOT DO THIS FOR PRODUCTION!!!) $ sops encrypt --verbose prod/raw.yaml > prod/encrypted.yaml +Encrypting using OCI KMS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We assume you are already have authentication profile set-up, ~/.oci/config exists and DEFAULT profile will be used to access OCI KMS. For details follow official OCI documentation. + +.. code:: sh + + $ # CRYPTO_ENDPOINT is diffrenet for different types of KMS and Regions, correct endpoint can be found in OCI console + $ export CRYPTO_ENDPOINT=https://crypto.kms.eu-frankfurt-1.oraclecloud.com + + $ export KEY_OCID=ocid1.key.xxxx + $ export KEY_VERSION=ocid1.keyversion.xxxx + + $ sops encrypt --oci-kms $CRYPTO_ENDPOINT/$KEY_OCID/$KEY_VERSION example.yaml + + Adding and removing keys ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cmd/sops/main.go b/cmd/sops/main.go index bdbd5eab1..f274463d4 100644 --- a/cmd/sops/main.go +++ b/cmd/sops/main.go @@ -38,6 +38,7 @@ import ( "github.com/getsops/sops/v3/keyservice" "github.com/getsops/sops/v3/kms" "github.com/getsops/sops/v3/logging" + "github.com/getsops/sops/v3/ocikms" "github.com/getsops/sops/v3/pgp" "github.com/getsops/sops/v3/stores/dotenv" "github.com/getsops/sops/v3/stores/json" @@ -86,14 +87,14 @@ func main() { }, } app.Name = "sops" - app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Azure Key Vault, age, and GPG support" + app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Azure Key Vault, OCI KMS, age, and GPG support" app.ArgsUsage = "sops [options] file" app.Version = version.Version app.Authors = []cli.Author{ {Name: "CNCF Maintainers"}, } app.UsageText = `sops is an editor of encrypted files that supports AWS KMS, GCP, AZKV, - PGP, and Age + OCI KMS, PGP, and Age To encrypt or decrypt a document with AWS KMS, specify the KMS ARN in the -k flag or in the SOPS_KMS_ARN environment variable. @@ -131,12 +132,12 @@ func main() { To use multiple KMS or PGP keys, separate them by commas. For example: $ sops -p "10F2...0A, 85D...B3F21" file.yaml - The -p, -k, --gcp-kms, --hc-vault-transit, and --azure-kv flags are only + The -p, -k, --gcp-kms, --hc-vault-transit, --oci-kms, and --azure-kv flags are only used to encrypt new documents. Editing or decrypting existing documents can be done with "sops file" or "sops decrypt file" respectively. The KMS and PGP keys listed in the encrypted documents are used then. To manage master - keys in existing documents, use the "add-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit}" - and "rm-{kms,pgp,gcp-kms,azure-kv,hc-vault-transit}" flags with --rotate + keys in existing documents, use the "add-{kms,pgp,gcp-kms,azure-kv,oci-kms,hc-vault-transit}" + and "rm-{kms,pgp,gcp-kms,azure-kv,oci-kms,hc-vault-transit}" flags with --rotate or the updatekeys command. To use a different GPG binary than the one in your PATH, set SOPS_GPG_EXEC. @@ -534,6 +535,10 @@ func main() { Name: "azure-kv", Usage: "the Azure Key Vault key URL the new group should contain. Can be specified more than once", }, + cli.StringSliceFlag{ + Name: "oci-kms", + Usage: "the OCI KMS URL the new group should contain. Can be specified more than once", + }, cli.StringSliceFlag{ Name: "hc-vault-transit", Usage: "the full vault path to the key used to encrypt/decrypt. Make you choose and configure a key with encryption/decryption enabled (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev'). Can be specified more than once", @@ -561,6 +566,7 @@ func main() { gcpKmses := c.StringSlice("gcp-kms") vaultURIs := c.StringSlice("hc-vault-transit") azkvs := c.StringSlice("azure-kv") + ociKmses := c.StringSlice("oci-kms") ageRecipients := c.StringSlice("age") if c.NArg() != 0 { return common.NewExitError(fmt.Errorf("error: no positional arguments allowed"), codes.ErrorGeneric) @@ -591,6 +597,14 @@ func main() { } group = append(group, k) } + for _, uri := range ociKmses { + k, err := azkv.NewMasterKeyFromURL(uri) + if err != nil { + log.WithError(err).Error("Failed to add key") + continue + } + group = append(group, k) + } for _, recipient := range ageRecipients { keys, err := age.MasterKeysFromRecipients(recipient) if err != nil { @@ -898,6 +912,11 @@ func main() { Usage: "comma separated list of Azure Key Vault URLs", EnvVar: "SOPS_AZURE_KEYVAULT_URLS", }, + cli.StringFlag{ + Name: "oci-kms", + Usage: "comma separated list of OCI KMS URLs", + EnvVar: "SOPS_OCI_KMS_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')", @@ -1011,7 +1030,6 @@ func main() { KeyServices: svcs, encryptConfig: encConfig, }) - if err != nil { return toExitError(err) } @@ -1086,6 +1104,14 @@ func main() { Name: "rm-azure-kv", Usage: "remove the provided comma-separated list of Azure Key Vault key URLs from the list of master keys on the given file", }, + cli.StringFlag{ + Name: "add-oci-kms", + Usage: "add the provided comma-separated list of OCI KMS URL to the list of master keys on the given file", + }, + cli.StringFlag{ + Name: "rm-oci-kms", + Usage: "remove the provided comma-separated list of OCI KMS URL from the list of master keys on the given file", + }, cli.StringFlag{ Name: "add-kms", Usage: "add the provided comma-separated list of KMS ARNs to the list of master keys on the given file", @@ -1144,8 +1170,8 @@ func main() { return toExitError(err) } if _, err := os.Stat(fileName); os.IsNotExist(err) { - if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" || - c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" { + if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-oci-kms") != "" || c.String("add-age") != "" || + c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-oci-kms") != "" || c.String("rm-age") != "" { return common.NewExitError(fmt.Sprintf("Error: cannot add or remove keys on non-existent file %q, use the `edit` subcommand instead.", fileName), codes.CannotChangeKeysFromNonExistentFile) } } @@ -1236,6 +1262,11 @@ func main() { Usage: "comma separated list of Azure Key Vault URLs", EnvVar: "SOPS_AZURE_KEYVAULT_URLS", }, + cli.StringFlag{ + Name: "oci-kms", + Usage: "comma separated list of OCI KMS URLs", + EnvVar: "SOPS_OCI_KMS_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')", @@ -1610,6 +1641,11 @@ func main() { Usage: "comma separated list of Azure Key Vault URLs", EnvVar: "SOPS_AZURE_KEYVAULT_URLS", }, + cli.StringFlag{ + Name: "oci-kms", + Usage: "comma separated list of OCI KMS resource OCIDs", + EnvVar: "SOPS_OCI_KMS_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')", @@ -1661,6 +1697,14 @@ func main() { Name: "rm-azure-kv", Usage: "remove the provided comma-separated list of Azure Key Vault key URLs from the list of master keys on the given file", }, + cli.StringFlag{ + Name: "add-oci-kms", + Usage: "add the provided comma-separated list of OCI KMS URL to the list of master keys on the given file", + }, + cli.StringFlag{ + Name: "rm-oci-kms", + Usage: "remove the provided comma-separated list of OCI KMS URL from the list of master keys on the given file", + }, cli.StringFlag{ Name: "add-kms", Usage: "add the provided comma-separated list of KMS ARNs to the list of master keys on the given file", @@ -1787,8 +1831,8 @@ func main() { return toExitError(err) } if _, err := os.Stat(fileName); os.IsNotExist(err) { - if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" || - c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" { + if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-oci-kms") != "" || c.String("add-age") != "" || + c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-oci-kms") != "" || c.String("rm-age") != "" { return common.NewExitError(fmt.Sprintf("Error: cannot add or remove keys on non-existent file %q, use `--kms` and `--pgp` instead.", fileName), codes.CannotChangeKeysFromNonExistentFile) } if isEncryptMode || isDecryptMode || isRotateMode { @@ -2081,7 +2125,7 @@ func getEncryptConfig(c *cli.Context, fileName string) (encryptConfig, error) { }, nil } -func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, azureKvOptionName string, hcVaultTransitOptionName string, ageOptionName string) ([]keys.MasterKey, error) { +func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, azureKvOptionName string, ociKmsOptionName, hcVaultTransitOptionName string, ageOptionName 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) @@ -2092,6 +2136,13 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO for _, k := range gcpkms.MasterKeysFromResourceIDString(c.String(gcpKmsOptionName)) { masterKeys = append(masterKeys, k) } + ociKeys, err := ocikms.MasterKeysFromURLs(c.String(azureKvOptionName)) + if err != nil { + return nil, err + } + for _, k := range ociKeys { + masterKeys = append(masterKeys, k) + } azureKeys, err := azkv.MasterKeysFromURLs(c.String(azureKvOptionName)) if err != nil { return nil, err @@ -2118,11 +2169,11 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO func getRotateOpts(c *cli.Context, fileName string, inputStore common.Store, outputStore common.Store, svcs []keyservice.KeyServiceClient, decryptionOrder []string) (rotateOpts, error) { kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context")) - addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-azure-kv", "add-hc-vault-transit", "add-age") + addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-azure-kv", "add-oci-kms", "add-hc-vault-transit", "add-age") if err != nil { return rotateOpts{}, err } - rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age") + rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-azure-kv", "rm-oci-kms", "rm-hc-vault-transit", "rm-age") if err != nil { return rotateOpts{}, err } @@ -2265,6 +2316,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { var pgpKeys []keys.MasterKey var cloudKmsKeys []keys.MasterKey var azkvKeys []keys.MasterKey + var ociKmsKeys []keys.MasterKey var hcVaultMkKeys []keys.MasterKey var ageMasterKeys []keys.MasterKey kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context")) @@ -2290,6 +2342,16 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { azkvKeys = append(azkvKeys, k) } } + if c.String("oci-kms") != "" { + ociKeys, err := ocikms.MasterKeysFromURLs(c.String("oci-kms")) + if err != nil { + return nil, err + } + for _, k := range ociKeys { + ociKmsKeys = append(ociKmsKeys, k) + } + + } if c.String("hc-vault-transit") != "" { hcVaultKeys, err := hcvault.NewMasterKeysFromURIs(c.String("hc-vault-transit")) if err != nil { @@ -2313,7 +2375,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { ageMasterKeys = append(ageMasterKeys, k) } } - if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" { + if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" && c.String("oci-kms") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" { conf, err := loadConfig(c, file, kmsEncryptionContext) // config file might just not be supplied, without any error if conf == nil { @@ -2329,6 +2391,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { group = append(group, kmsKeys...) group = append(group, cloudKmsKeys...) group = append(group, azkvKeys...) + group = append(group, ociKmsKeys...) group = append(group, pgpKeys...) group = append(group, hcVaultMkKeys...) group = append(group, ageMasterKeys...) diff --git a/go.mod b/go.mod index ab09e5c5b..673bfa6ec 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/lib/pq v1.10.9 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-wordwrap v1.0.1 + github.com/oracle/oci-go-sdk/v65 v65.92.0 github.com/ory/dockertest/v3 v3.12.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 @@ -97,6 +98,7 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/google/s2a-go v0.1.9 // indirect @@ -126,10 +128,12 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/sony/gobreaker v0.5.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/zeebo/errs v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect diff --git a/go.sum b/go.sum index 72bab8796..3111e5a73 100644 --- a/go.sum +++ b/go.sum @@ -160,6 +160,8 @@ github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= @@ -239,6 +241,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runc v1.2.6 h1:P7Hqg40bsMvQGCS4S7DJYhUZOISMLJOB2iGX5COWiPk= github.com/opencontainers/runc v1.2.6/go.mod h1:dOQeFo29xZKBNeRBI0B19mJtfHv68YgCTh1X+YphA+4= +github.com/oracle/oci-go-sdk/v65 v65.92.0 h1:qLy3VH3aEO1c4RdKu58cmNrITtRbrgpRGOsYxgP2eXU= +github.com/oracle/oci-go-sdk/v65 v65.92.0/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA= github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -259,11 +263,14 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -282,8 +289,11 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= @@ -309,14 +319,24 @@ go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= @@ -324,21 +344,41 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= @@ -347,6 +387,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/keyservice/keyservice.go b/keyservice/keyservice.go index 321af7942..f2d58fd2a 100644 --- a/keyservice/keyservice.go +++ b/keyservice/keyservice.go @@ -13,6 +13,7 @@ import ( "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/keys" "github.com/getsops/sops/v3/kms" + "github.com/getsops/sops/v3/ocikms" "github.com/getsops/sops/v3/pgp" ) @@ -78,6 +79,16 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { }, }, } + case *ocikms.MasterKey: + return Key{ + KeyType: &Key_OciKmsKey{ + &OciKmsKey{ + Ocid: mk.Id, + CryptoEndpoint: mk.CryptoEndpoint, + Version: mk.KeyVersionId, + }, + }, + } 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 a810b2805..1babb44f9 100644 --- a/keyservice/keyservice.pb.go +++ b/keyservice/keyservice.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.35.2 -// protoc v5.28.3 +// protoc v6.30.2 // source: keyservice/keyservice.proto package keyservice @@ -33,6 +33,7 @@ type Key struct { // *Key_AzureKeyvaultKey // *Key_VaultKey // *Key_AgeKey + // *Key_OciKmsKey KeyType isKey_KeyType `protobuf_oneof:"key_type"` } @@ -115,6 +116,13 @@ func (x *Key) GetAgeKey() *AgeKey { return nil } +func (x *Key) GetOciKmsKey() *OciKmsKey { + if x, ok := x.GetKeyType().(*Key_OciKmsKey); ok { + return x.OciKmsKey + } + return nil +} + type isKey_KeyType interface { isKey_KeyType() } @@ -143,6 +151,10 @@ type Key_AgeKey struct { AgeKey *AgeKey `protobuf:"bytes,6,opt,name=age_key,json=ageKey,proto3,oneof"` } +type Key_OciKmsKey struct { + OciKmsKey *OciKmsKey `protobuf:"bytes,7,opt,name=oci_kms_key,json=ociKmsKey,proto3,oneof"` +} + func (*Key_KmsKey) isKey_KeyType() {} func (*Key_PgpKey) isKey_KeyType() {} @@ -155,6 +167,8 @@ func (*Key_VaultKey) isKey_KeyType() {} func (*Key_AgeKey) isKey_KeyType() {} +func (*Key_OciKmsKey) isKey_KeyType() {} + type PgpKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -481,6 +495,67 @@ func (x *AgeKey) GetRecipient() string { return "" } +type OciKmsKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ocid string `protobuf:"bytes,1,opt,name=ocid,proto3" json:"ocid,omitempty"` + CryptoEndpoint string `protobuf:"bytes,2,opt,name=crypto_endpoint,json=cryptoEndpoint,proto3" json:"crypto_endpoint,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *OciKmsKey) Reset() { + *x = OciKmsKey{} + mi := &file_keyservice_keyservice_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OciKmsKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OciKmsKey) ProtoMessage() {} + +func (x *OciKmsKey) ProtoReflect() protoreflect.Message { + mi := &file_keyservice_keyservice_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OciKmsKey.ProtoReflect.Descriptor instead. +func (*OciKmsKey) Descriptor() ([]byte, []int) { + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{7} +} + +func (x *OciKmsKey) GetOcid() string { + if x != nil { + return x.Ocid + } + return "" +} + +func (x *OciKmsKey) GetCryptoEndpoint() string { + if x != nil { + return x.CryptoEndpoint + } + return "" +} + +func (x *OciKmsKey) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + type EncryptRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -492,7 +567,7 @@ type EncryptRequest struct { func (x *EncryptRequest) Reset() { *x = EncryptRequest{} - mi := &file_keyservice_keyservice_proto_msgTypes[7] + mi := &file_keyservice_keyservice_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -504,7 +579,7 @@ func (x *EncryptRequest) String() string { func (*EncryptRequest) ProtoMessage() {} func (x *EncryptRequest) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[7] + mi := &file_keyservice_keyservice_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -517,7 +592,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{7} + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{8} } func (x *EncryptRequest) GetKey() *Key { @@ -544,7 +619,7 @@ type EncryptResponse struct { func (x *EncryptResponse) Reset() { *x = EncryptResponse{} - mi := &file_keyservice_keyservice_proto_msgTypes[8] + mi := &file_keyservice_keyservice_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -556,7 +631,7 @@ func (x *EncryptResponse) String() string { func (*EncryptResponse) ProtoMessage() {} func (x *EncryptResponse) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[8] + mi := &file_keyservice_keyservice_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -569,7 +644,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{8} + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{9} } func (x *EncryptResponse) GetCiphertext() []byte { @@ -590,7 +665,7 @@ type DecryptRequest struct { func (x *DecryptRequest) Reset() { *x = DecryptRequest{} - mi := &file_keyservice_keyservice_proto_msgTypes[9] + mi := &file_keyservice_keyservice_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -602,7 +677,7 @@ func (x *DecryptRequest) String() string { func (*DecryptRequest) ProtoMessage() {} func (x *DecryptRequest) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[9] + mi := &file_keyservice_keyservice_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -615,7 +690,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{9} + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{10} } func (x *DecryptRequest) GetKey() *Key { @@ -642,7 +717,7 @@ type DecryptResponse struct { func (x *DecryptResponse) Reset() { *x = DecryptResponse{} - mi := &file_keyservice_keyservice_proto_msgTypes[10] + mi := &file_keyservice_keyservice_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -654,7 +729,7 @@ func (x *DecryptResponse) String() string { func (*DecryptResponse) ProtoMessage() {} func (x *DecryptResponse) ProtoReflect() protoreflect.Message { - mi := &file_keyservice_keyservice_proto_msgTypes[10] + mi := &file_keyservice_keyservice_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -667,7 +742,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{10} + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{11} } func (x *DecryptResponse) GetPlaintext() []byte { @@ -681,7 +756,7 @@ 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, 0x98, 0x02, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc6, 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, @@ -698,64 +773,74 @@ var file_keyservice_keyservice_proto_rawDesc = []byte{ 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, 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, 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, + 0x65, 0x79, 0x48, 0x00, 0x52, 0x06, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x0b, + 0x6f, 0x63, 0x69, 0x5f, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0a, 0x2e, 0x4f, 0x63, 0x69, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, + 0x09, 0x6f, 0x63, 0x69, 0x4b, 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, 0x62, 0x0a, 0x09, 0x4f, 0x63, 0x69, 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, + 0x12, 0x0a, 0x04, 0x6f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, + 0x63, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x5f, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 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, 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 ( @@ -770,7 +855,7 @@ func file_keyservice_keyservice_proto_rawDescGZIP() []byte { return file_keyservice_keyservice_proto_rawDescData } -var file_keyservice_keyservice_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_keyservice_keyservice_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_keyservice_keyservice_proto_goTypes = []any{ (*Key)(nil), // 0: Key (*PgpKey)(nil), // 1: PgpKey @@ -779,11 +864,12 @@ var file_keyservice_keyservice_proto_goTypes = []any{ (*VaultKey)(nil), // 4: VaultKey (*AzureKeyVaultKey)(nil), // 5: AzureKeyVaultKey (*AgeKey)(nil), // 6: AgeKey - (*EncryptRequest)(nil), // 7: EncryptRequest - (*EncryptResponse)(nil), // 8: EncryptResponse - (*DecryptRequest)(nil), // 9: DecryptRequest - (*DecryptResponse)(nil), // 10: DecryptResponse - nil, // 11: KmsKey.ContextEntry + (*OciKmsKey)(nil), // 7: OciKmsKey + (*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 @@ -792,18 +878,19 @@ var file_keyservice_keyservice_proto_depIdxs = []int32{ 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 - 11, // 6: KmsKey.context:type_name -> KmsKey.ContextEntry - 0, // 7: EncryptRequest.key:type_name -> Key - 0, // 8: DecryptRequest.key:type_name -> Key - 7, // 9: KeyService.Encrypt:input_type -> EncryptRequest - 9, // 10: KeyService.Decrypt:input_type -> DecryptRequest - 8, // 11: KeyService.Encrypt:output_type -> EncryptResponse - 10, // 12: KeyService.Decrypt:output_type -> DecryptResponse - 11, // [11:13] is the sub-list for method output_type - 9, // [9:11] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 7, // 6: Key.oci_kms_key:type_name -> OciKmsKey + 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() } @@ -818,6 +905,7 @@ func file_keyservice_keyservice_proto_init() { (*Key_AzureKeyvaultKey)(nil), (*Key_VaultKey)(nil), (*Key_AgeKey)(nil), + (*Key_OciKmsKey)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -825,7 +913,7 @@ func file_keyservice_keyservice_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_keyservice_keyservice_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, diff --git a/keyservice/keyservice.proto b/keyservice/keyservice.proto index 8bf62f89b..9dbed8f0d 100644 --- a/keyservice/keyservice.proto +++ b/keyservice/keyservice.proto @@ -10,6 +10,7 @@ message Key { AzureKeyVaultKey azure_keyvault_key = 4; VaultKey vault_key = 5; AgeKey age_key = 6; + OciKmsKey oci_kms_key = 7; } } @@ -44,6 +45,12 @@ message AgeKey { string recipient = 1; } +message OciKmsKey { + string ocid = 1; + string crypto_endpoint = 2; + string version = 3; +} + message EncryptRequest { Key key = 1; bytes plaintext = 2; diff --git a/keyservice/keyservice_grpc.pb.go b/keyservice/keyservice_grpc.pb.go index d278b82d9..b30b85908 100644 --- a/keyservice/keyservice_grpc.pb.go +++ b/keyservice/keyservice_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v5.28.3 +// - protoc v6.30.2 // source: keyservice/keyservice.proto package keyservice diff --git a/keyservice/server.go b/keyservice/server.go index 9f2b486a6..307740c15 100644 --- a/keyservice/server.go +++ b/keyservice/server.go @@ -8,6 +8,7 @@ import ( "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" + "github.com/getsops/sops/v3/ocikms" "github.com/getsops/sops/v3/pgp" "golang.org/x/net/context" "google.golang.org/grpc/codes" @@ -62,6 +63,19 @@ func (ks *Server) encryptWithAzureKeyVault(key *AzureKeyVaultKey, plaintext []by return []byte(azkvKey.EncryptedKey), nil } +func (ks *Server) encryptWithOciKms(key *OciKmsKey, plaintext []byte) ([]byte, error) { + ociKmsKey := ocikms.MasterKey{ + CryptoEndpoint: key.CryptoEndpoint, + Id: key.Ocid, + KeyVersionId: key.Version, + } + err := ociKmsKey.Encrypt(plaintext) + if err != nil { + return nil, err + } + return []byte(ociKmsKey.EncryptedKey), nil +} + func (ks *Server) encryptWithVault(key *VaultKey, plaintext []byte) ([]byte, error) { vaultKey := hcvault.MasterKey{ VaultAddress: key.VaultAddress, @@ -121,6 +135,17 @@ func (ks *Server) decryptWithAzureKeyVault(key *AzureKeyVaultKey, ciphertext []b return []byte(plaintext), err } +func (ks *Server) decryptWithOciKms(key *OciKmsKey, ciphertext []byte) ([]byte, error) { + ociKmsKey := ocikms.MasterKey{ + Id: key.Ocid, + KeyVersionId: key.Version, + CryptoEndpoint: key.CryptoEndpoint, + } + ociKmsKey.EncryptedKey = string(ciphertext) + plaintext, err := ociKmsKey.Decrypt() + return []byte(plaintext), err +} + func (ks *Server) decryptWithVault(key *VaultKey, ciphertext []byte) ([]byte, error) { vaultKey := hcvault.MasterKey{ VaultAddress: key.VaultAddress, @@ -144,7 +169,8 @@ func (ks *Server) decryptWithAge(key *AgeKey, ciphertext []byte) ([]byte, error) // 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, - req *EncryptRequest) (*EncryptResponse, error) { + req *EncryptRequest, +) (*EncryptResponse, error) { key := req.Key var response *EncryptResponse switch k := key.KeyType.(type) { @@ -180,6 +206,14 @@ func (ks Server) Encrypt(ctx context.Context, response = &EncryptResponse{ Ciphertext: ciphertext, } + case *Key_OciKmsKey: + ciphertext, err := ks.encryptWithOciKms(k.OciKmsKey, req.Plaintext) + if err != nil { + return nil, err + } + response = &EncryptResponse{ + Ciphertext: ciphertext, + } case *Key_VaultKey: ciphertext, err := ks.encryptWithVault(k.VaultKey, req.Plaintext) if err != nil { @@ -246,7 +280,8 @@ func (ks Server) prompt(key *Key, requestType string) error { // Decrypt takes a decrypt request and decrypts the provided ciphertext with the provided key, returning the decrypted // result func (ks Server) Decrypt(ctx context.Context, - req *DecryptRequest) (*DecryptResponse, error) { + req *DecryptRequest, +) (*DecryptResponse, error) { key := req.Key var response *DecryptResponse switch k := key.KeyType.(type) { @@ -290,6 +325,14 @@ func (ks Server) Decrypt(ctx context.Context, response = &DecryptResponse{ Plaintext: plaintext, } + case *Key_OciKmsKey: + plaintext, err := ks.decryptWithOciKms(k.OciKmsKey, req.Ciphertext) + if err != nil { + return nil, err + } + response = &DecryptResponse{ + Plaintext: plaintext, + } case *Key_AgeKey: plaintext, err := ks.decryptWithAge(k.AgeKey, req.Ciphertext) if err != nil { diff --git a/ocikms/keysource.go b/ocikms/keysource.go new file mode 100644 index 000000000..483f82b1c --- /dev/null +++ b/ocikms/keysource.go @@ -0,0 +1,217 @@ +package ocikms + +import ( + "context" + "encoding/base64" + "fmt" + "regexp" + "strings" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" + kms "github.com/oracle/oci-go-sdk/v65/keymanagement" + "github.com/sirupsen/logrus" + + "github.com/getsops/sops/v3/logging" +) + +const ( + // KeyTypeIdentifier is the string used to identify a OCI KMS MasterKey. + KeyTypeIdentifier = "oci_kms" +) + +var ( + // ocikmsTTL is the duration after which a MasterKey requires rotation. + ocikmsTTL = time.Hour * 24 * 30 * 6 + // log is the global logger for any OCI KMS MasterKey. + log *logrus.Logger +) + +func init() { + log = logging.NewLogger("OCIKMS") +} + +// MasterKey is a OCI KMS key used to encrypt and decrypt the SOPS +// data key. +type MasterKey struct { + // KeyVersionId is OCID of key version used in combination of Key ID + KeyVersionId string + // Id is OCID of Master Ecnryption Key stored in OCI Vault + Id string + // CryptoEndpoint is URL of Crypto Endpoint, url can differ between regions and types of key storage + CryptoEndpoint string + // CreationDate is time of creation + CreationDate time.Time + // EncryptedKey is the string returned after encrypting with OCI KMS. + EncryptedKey string +} + +// NewMasterKeyFromResourceID creates a new MasterKey with the provided ocid +func NewMasterKey(cryptoEndpoint string, ocid string, version string) *MasterKey { + return &MasterKey{ + Id: ocid, + CreationDate: time.Now().UTC(), + KeyVersionId: version, + CryptoEndpoint: cryptoEndpoint, + } +} + +// MasterKeysFromResourceIDString takes a comma separated list of OCI KMS +// resource IDs and returns a slice of new MasterKeys for them. +func NewMasterKeyFromURL(url string) (*MasterKey, error) { + url = strings.TrimSpace(url) + re := regexp.MustCompile(`^(https://[^/]+)/(ocid1\.key\.[^/]+)/(ocid1\.keyversion\.[^/]+)/?$`) + parts := re.FindStringSubmatch(url) + if len(parts) != 4 { + return nil, fmt.Errorf("could not parse %q into a valid OCI Key Vault Master Encryption Key", url) + } + return NewMasterKey(parts[1], parts[2], parts[3]), nil +} + +func MasterKeysFromURLs(urls string) ([]*MasterKey, error) { + var keys []*MasterKey + if urls == "" { + return keys, nil + } + for _, s := range strings.Split(urls, ",") { + k, err := NewMasterKeyFromURL(s) + if err != nil { + return nil, err + } + keys = append(keys, k) + } + return keys, nil +} + +// Encrypt takes a SOPS data key, encrypts it with OCI 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 OCI KMS, and stores the +// result in the EncryptedKey field. +func (key *MasterKey) EncryptContext(ctx context.Context, dataKey []byte) error { + service, err := key.newKMSClient() + if err != nil { + log.WithField("ocid", key.Id).Info("Encryption failed") + return fmt.Errorf("cannot create OCI KMS service: %w", err) + } + + // OCI KMS reguires Plaintext is base64 encoded + plainText := base64.StdEncoding.EncodeToString(dataKey) + req := kms.EncryptRequest{ + EncryptDataDetails: kms.EncryptDataDetails{ + KeyId: &key.Id, + Plaintext: &plainText, + KeyVersionId: &key.KeyVersionId, + }, + } + resp, err := service.Encrypt(ctx, req) + if err != nil { + log.WithField("ocid", key.Id).Info("Encryption failed") + return fmt.Errorf("failed to encrypt sops data key with OCI KMS key: %w", err) + } + + key.EncryptedKey = *resp.Ciphertext + log.WithField("ocid", key.Id).Info("Encryption succeeded") + return nil +} + +// SetEncryptedDataKey sets the encrypted data key for this master key. +func (key *MasterKey) SetEncryptedDataKey(enc []byte) { + key.EncryptedKey = string(enc) +} + +// EncryptedDataKey returns the encrypted data key this master key holds. +func (key *MasterKey) EncryptedDataKey() []byte { + return []byte(key.EncryptedKey) +} + +// 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 +} + +// Decrypt decrypts the EncryptedKey field with OCI KMS and returns +// the result. +// +// Consider using DecryptContext instead. +func (key *MasterKey) Decrypt() ([]byte, error) { + return key.DecryptContext(context.Background()) +} + +// DecryptContext decrypts the EncryptedKey field with OCI KMS and returns +// the result. +func (key *MasterKey) DecryptContext(ctx context.Context) ([]byte, error) { + service, err := key.newKMSClient() + if err != nil { + log.WithField("ocid", key.Id).Info("Decryption failed") + return nil, fmt.Errorf("cannot create OCI KMS service: %w", err) + } + + cipher := string(key.EncryptedDataKey()) + + req := kms.DecryptRequest{ + DecryptDataDetails: kms.DecryptDataDetails{ + KeyId: &key.Id, + Ciphertext: &cipher, + KeyVersionId: &key.KeyVersionId, + }, + } + resp, err := service.Decrypt(ctx, req) + if err != nil { + log.WithField("ocid", key.Id).Info("Decryption failed") + return nil, fmt.Errorf("failed to decrypt sops data key with OCI KMS key: %w", err) + } + decodedPlainText, err := base64.StdEncoding.DecodeString(string(*resp.Plaintext)) + if err != nil { + log.WithField("ocid", key.Id).Info("Decryption failed") + return nil, err + } + log.WithField("ocid", key.Id).Info("Decryption succeeded") + return []byte(decodedPlainText), nil +} + +// NeedsRotation returns whether the data key needs to be rotated or not. +func (key *MasterKey) NeedsRotation() bool { + return time.Since(key.CreationDate) > (ocikmsTTL) +} + +// ToString converts the key to a string representation. +func (key *MasterKey) ToString() string { + return fmt.Sprintf("%s/%s/%s", key.CryptoEndpoint, key.Id, key.KeyVersionId) +} + +// ToMap converts the MasterKey to a map for serialization purposes. +func (key MasterKey) ToMap() map[string]interface{} { + out := make(map[string]interface{}) + out["id"] = key.Id + out["crypto_endpoint"] = key.CryptoEndpoint + out["key_version"] = key.KeyVersionId + out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339) + out["enc"] = key.EncryptedKey + return out +} + +// TypeToIdentifier returns the string identifier for the MasterKey type. +func (key *MasterKey) TypeToIdentifier() string { + return KeyTypeIdentifier +} + +func (key *MasterKey) newKMSClient() (*kms.KmsCryptoClient, error) { + // Right now only implements authentication using default profile + configProvider := common.DefaultConfigProvider() + client, err := kms.NewKmsCryptoClientWithConfigurationProvider(configProvider, key.CryptoEndpoint) + if err != nil { + return nil, err + } + + return &client, nil +} diff --git a/ocikms/keysource_test.go b/ocikms/keysource_test.go new file mode 100644 index 000000000..43062de5f --- /dev/null +++ b/ocikms/keysource_test.go @@ -0,0 +1,219 @@ +package ocikms + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +const ( + mockOciURL = "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xxxxx/ocid1.keyversion.xxxxxx" +) + +func TestNewMasterKeyFromURL(t *testing.T) { + tests := []struct { + name string + url string + expectErr bool + expectKey MasterKey + }{ + { + name: "URL with slash", + url: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xxxxx/ocid1.keyversion.xxxxxx/", + expectKey: MasterKey{ + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xxxxx", + KeyVersionId: "ocid1.keyversion.xxxxxx", + }, + }, + { + name: "URL", + url: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xxxxx/ocid1.keyversion.xxxxxx", + expectKey: MasterKey{ + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xxxxx", + KeyVersionId: "ocid1.keyversion.xxxxxx", + }, + }, + { + name: "wrong keyversion URL", + url: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xxxxx/ocid1.key.xxxxx", + expectErr: true, + }, + { + name: "missing keyversion URL", + url: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xxxxx", + expectErr: true, + }, + { + name: "missing keyid URL", + url: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/", + expectErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + key, err := NewMasterKeyFromURL(tt.url) + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, key) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.expectKey.CryptoEndpoint, key.CryptoEndpoint) + assert.Equal(t, tt.expectKey.Id, key.Id) + assert.Equal(t, tt.expectKey.KeyVersionId, key.KeyVersionId) + assert.NotNil(t, key.CreationDate) + }) + } +} + +func TestMasterKeysFromURLs(t *testing.T) { + tests := []struct { + name string + urls string + expectErr bool + expectKeyCount int + expectKeys []MasterKey + }{ + { + name: "URL", + urls: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xx/ocid1.keyversion.xx", + expectKeyCount: 1, + expectKeys: []MasterKey{ + { + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xx", + KeyVersionId: "ocid1.keyversion.xx", + }, + }, + }, + { + name: "multiple URLs", + urls: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xx/ocid1.keyversion.xx,https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.yy/ocid1.keyversion.yy", + expectKeyCount: 2, + expectKeys: []MasterKey{ + { + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xx", + KeyVersionId: "ocid1.keyversion.xx", + }, + { + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.yy", + KeyVersionId: "ocid1.keyversion.yy", + }, + }, + }, + { + name: "multiple URLs with leading and trailing spaces", + urls: " https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xx/ocid1.keyversion.xx,https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.yy/ocid1.keyversion.yy ", + expectKeyCount: 2, + expectKeys: []MasterKey{ + { + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xx", + KeyVersionId: "ocid1.keyversion.xx", + }, + { + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.yy", + KeyVersionId: "ocid1.keyversion.yy", + }, + }, + }, + { + name: "multiple URLs, one malformed", + urls: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xx/ocid1.test.xx,https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.yy/ocid1.keyversion.yy", + expectErr: true, + }, + { + name: "empty", + urls: "", + expectErr: false, + expectKeyCount: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + keys, err := MasterKeysFromURLs(tt.urls) + if tt.expectErr { + assert.Error(t, err) + assert.Nil(t, keys) + return + } + assert.NoError(t, err) + assert.Len(t, keys, tt.expectKeyCount) + for idx := range keys { + assert.Equal(t, tt.expectKeys[idx].CryptoEndpoint, keys[idx].CryptoEndpoint) + assert.Equal(t, tt.expectKeys[idx].Id, keys[idx].Id) + assert.Equal(t, tt.expectKeys[idx].KeyVersionId, keys[idx].KeyVersionId) + assert.NotNil(t, keys[idx].CreationDate) + } + }) + } +} + +func TestMasterKey_EncryptedDataKey(t *testing.T) { + key := &MasterKey{EncryptedKey: "some key"} + assert.EqualValues(t, key.EncryptedKey, key.EncryptedDataKey()) +} + +func TestMasterKey_SetEncryptedDataKey(t *testing.T) { + encryptedKey := []byte("encrypted") + key := &MasterKey{} + key.SetEncryptedDataKey(encryptedKey) + assert.EqualValues(t, encryptedKey, key.EncryptedKey) +} + +func TestMasterKey_EncryptIfNeeded(t *testing.T) { + t.Run("not encrypted", func(t *testing.T) { + key, err := NewMasterKeyFromURL(mockOciURL) + assert.NoError(t, err) + + err = key.Encrypt([]byte("some data")) + assert.Error(t, err) + assert.ErrorContains(t, err, "failed to encrypt sops data key with OCI KMS key") + }) + + t.Run("already encrypted", func(t *testing.T) { + encryptedKey := "encrypted" + key, err := NewMasterKeyFromURL(mockOciURL) + assert.NoError(t, err) + key.EncryptedKey = encryptedKey + + assert.NoError(t, key.EncryptIfNeeded([]byte("other data"))) + assert.Equal(t, encryptedKey, key.EncryptedKey) + }) +} + +func TestMasterKey_NeedsRotation(t *testing.T) { + key := NewMasterKey("", "", "") + assert.False(t, key.NeedsRotation()) + + key.CreationDate = key.CreationDate.Add(-(ocikmsTTL + time.Second)) + assert.True(t, key.NeedsRotation()) +} + +func TestMasterKey_ToString(t *testing.T) { + key := NewMasterKey("https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", "ocid1.key.xx", "ocid1.keyversion.xx") + assert.Equal(t, "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com/ocid1.key.xx/ocid1.keyversion.xx", key.ToString()) +} + +func TestMasterKey_ToMap(t *testing.T) { + key := MasterKey{ + CreationDate: time.Date(2016, time.October, 31, 10, 0, 0, 0, time.UTC), + CryptoEndpoint: "https://test-crypto.kms.eu-frankfurt-1.oraclecloud.com", + Id: "ocid1.key.xx", + KeyVersionId: "ocid1.keyversion.xx", + EncryptedKey: "this is encrypted", + } + assert.Equal(t, map[string]interface{}{ + "crypto_endpoint": key.CryptoEndpoint, + "id": key.Id, + "key_version": key.KeyVersionId, + "enc": "this is encrypted", + "created_at": "2016-10-31T10:00:00Z", + }, key.ToMap()) +} diff --git a/stores/stores.go b/stores/stores.go index bdc026a00..4a2250ba0 100644 --- a/stores/stores.go +++ b/stores/stores.go @@ -10,9 +10,8 @@ of the purpose of this package is to make it easy to change the SOPS file format package stores import ( - "time" - "fmt" + "time" "github.com/getsops/sops/v3" "github.com/getsops/sops/v3/age" @@ -20,6 +19,7 @@ import ( "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" + "github.com/getsops/sops/v3/ocikms" "github.com/getsops/sops/v3/pgp" ) @@ -47,6 +47,7 @@ type Metadata struct { KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` + OCIKMSKeys []ocikmskey `yaml:"oci_kms,omitempty" json:"oci_kms,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"` @@ -67,6 +68,7 @@ type keygroup struct { KMSKeys []kmskey `yaml:"kms,omitempty" json:"kms,omitempty"` GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"` AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"` + OCIKMSKeys []ocikmskey `yaml:"oci_kms,omitempty" json:"oci_kms,omitempty"` VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"` AgeKeys []agekey `yaml:"age" json:"age"` } @@ -108,6 +110,14 @@ type azkvkey struct { EncryptedDataKey string `yaml:"enc" json:"enc"` } +type ocikmskey struct { + Id string `yaml:"id" json:"id"` + CrpytoEndpoint string `yaml:"crypto_endpoint" json:"crypto_endpoint"` + KeyVersion string `yaml:"key_version" json:"key_version"` + CreatedAt string `yaml:"created_at" json:"created_at"` + EncryptedDataKey string `yaml:"enc" json:"enc"` +} + type agekey struct { Recipient string `yaml:"recipient" json:"recipient"` EncryptedDataKey string `yaml:"enc" json:"enc"` @@ -132,6 +142,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { m.PGPKeys = pgpKeysFromGroup(group) m.KMSKeys = kmsKeysFromGroup(group) m.GCPKMSKeys = gcpkmsKeysFromGroup(group) + m.OCIKMSKeys = ocikmsKeysFromGroup(group) m.VaultKeys = vaultKeysFromGroup(group) m.AzureKeyVaultKeys = azkvKeysFromGroup(group) m.AgeKeys = ageKeysFromGroup(group) @@ -141,6 +152,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { KMSKeys: kmsKeysFromGroup(group), PGPKeys: pgpKeysFromGroup(group), GCPKMSKeys: gcpkmsKeysFromGroup(group), + OCIKMSKeys: ocikmsKeysFromGroup(group), VaultKeys: vaultKeysFromGroup(group), AzureKeyVaultKeys: azkvKeysFromGroup(group), AgeKeys: ageKeysFromGroup(group), @@ -195,6 +207,22 @@ func gcpkmsKeysFromGroup(group sops.KeyGroup) (keys []gcpkmskey) { return } +func ocikmsKeysFromGroup(group sops.KeyGroup) (keys []ocikmskey) { + for _, key := range group { + switch key := key.(type) { + case *ocikms.MasterKey: + keys = append(keys, ocikmskey{ + Id: key.Id, + CreatedAt: key.CreationDate.Format(time.RFC3339), + EncryptedDataKey: key.EncryptedKey, + CrpytoEndpoint: key.CryptoEndpoint, + KeyVersion: key.KeyVersionId, + }) + } + } + return +} + func vaultKeysFromGroup(group sops.KeyGroup) (keys []vaultkey) { for _, key := range group { switch key := key.(type) { @@ -294,7 +322,7 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) { }, nil } -func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, azkvKeys []azkvkey, vaultKeys []vaultkey, ageKeys []agekey) (sops.KeyGroup, error) { +func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, azkvKeys []azkvkey, ociKmsKeys []ocikmskey, vaultKeys []vaultkey, ageKeys []agekey) (sops.KeyGroup, error) { var internalGroup sops.KeyGroup for _, kmsKey := range kmsKeys { k, err := kmsKey.toInternal() @@ -317,6 +345,13 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske } internalGroup = append(internalGroup, k) } + for _, ociKmsKey := range ociKmsKeys { + k, err := ociKmsKey.toInternal() + if err != nil { + return nil, err + } + internalGroup = append(internalGroup, k) + } for _, vaultKey := range vaultKeys { k, err := vaultKey.toInternal() if err != nil { @@ -343,8 +378,8 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske 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.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 { - internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys, m.VaultKeys, m.AgeKeys) + if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.OCIKMSKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 { + internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys, m.OCIKMSKeys, m.VaultKeys, m.AgeKeys) if err != nil { return nil, err } @@ -352,7 +387,7 @@ 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.AzureKeyVaultKeys, group.VaultKeys, group.AgeKeys) + internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.AzureKeyVaultKeys, group.OCIKMSKeys, group.VaultKeys, group.AgeKeys) if err != nil { return nil, err } @@ -405,6 +440,20 @@ func (azkvKey *azkvkey) toInternal() (*azkv.MasterKey, error) { }, nil } +func (ociKmsKey *ocikmskey) toInternal() (*ocikms.MasterKey, error) { + creationDate, err := time.Parse(time.RFC3339, ociKmsKey.CreatedAt) + if err != nil { + return nil, err + } + return &ocikms.MasterKey{ + EncryptedKey: ociKmsKey.EncryptedDataKey, + CreationDate: creationDate, + Id: ociKmsKey.Id, + CryptoEndpoint: ociKmsKey.CrpytoEndpoint, + KeyVersionId: ociKmsKey.KeyVersion, + }, nil +} + func (vaultKey *vaultkey) toInternal() (*hcvault.MasterKey, error) { creationDate, err := time.Parse(time.RFC3339, vaultKey.CreatedAt) if err != nil {