diff --git a/cloudru/client.go b/cloudru/client.go new file mode 100644 index 000000000..01ee8f79c --- /dev/null +++ b/cloudru/client.go @@ -0,0 +1,174 @@ +package cloudru + +import ( + "context" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "time" + + iamAuthV1 "github.com/cloudru-tech/iam-sdk/api/auth/v1" + kmsV1 "github.com/cloudru-tech/key-manager-sdk/api/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/metadata" +) + +// EndpointsResponse is a response from the Cloud.ru API. +type EndpointsResponse struct { + // Endpoints contains the list of actual API addresses of Cloud.ru products. + Endpoints []Endpoint `json:"endpoints"` +} + +// Endpoint is a product API address. +type Endpoint struct { + ID string `json:"id"` + Address string `json:"address"` +} + +type Client struct { + KMS kmsV1.KeyManagerServiceClient + kmsConn *grpc.ClientConn +} + +func provideClient() (*Client, error) { + discoveryURL := DiscoveryURL + + if du, ok := os.LookupEnv(EnvDiscoveryURL); ok { + u, err := url.Parse(discoveryURL) + if err != nil { + return nil, fmt.Errorf("invalid %s param: %w", EnvDiscoveryURL, err) + } + + switch { + case u.Host == "": + return nil, fmt.Errorf("invalid %s param: missing host", EnvDiscoveryURL) + case u.Scheme != "http", u.Scheme != "https": + return nil, fmt.Errorf("invalid %s param: scheme must be http or https", EnvDiscoveryURL) + } + + discoveryURL = du + } + + var ok bool + var akID, akSecret string + if akID, ok = os.LookupEnv(EnvAccessKeyID); !ok { + return nil, fmt.Errorf("missing %s env param", EnvAccessKeyID) + } + if akSecret, ok = os.LookupEnv(EnvAccessKeySecret); !ok { + return nil, fmt.Errorf("missing %s env param", EnvAccessKeySecret) + } + + endpoints, err := getEndpoints(discoveryURL) + if err != nil { + return nil, err + } + + kmsEndpoint := endpoints.Get("key-manager") + if kmsEndpoint == nil { + return nil, errors.New("key-manager API is not available") + } + + iamEndpoint := endpoints.Get("iam") + if iamEndpoint == nil { + return nil, errors.New("iam API is not available") + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + iamConn, err := grpc.NewClient(iamEndpoint.Address, + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS13})), + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: time.Second * 30, + Timeout: time.Second * 5, + PermitWithoutStream: false, + }), + grpc.WithUserAgent("sops"), + ) + if err != nil { + return nil, fmt.Errorf("initiate IAM gRPC connection: %w", err) + } + defer iamConn.Close() + + iam := iamAuthV1.NewAuthServiceClient(iamConn) + token, err := iam.GetToken(ctx, &iamAuthV1.GetTokenRequest{ + KeyId: akID, + Secret: akSecret, + }) + if err != nil { + return nil, fmt.Errorf("get token: %w", err) + } + + kmsConn, err := grpc.NewClient(kmsEndpoint.Address, + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS13})), + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: time.Second * 30, + Timeout: time.Second * 5, + PermitWithoutStream: false, + }), + grpc.WithUserAgent("sops"), + grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = metadata.New(map[string]string{}) + } + md.Set("authorization", "Bearer "+token.AccessToken) + + return invoker(metadata.NewOutgoingContext(ctx, md), method, req, reply, cc, opts...) + }), + ) + if err != nil { + return nil, fmt.Errorf("initiate KMS gRPC connection: %w", err) + } + + return &Client{ + KMS: kmsV1.NewKeyManagerServiceClient(kmsConn), + kmsConn: kmsConn, + }, nil +} + +// getEndpoints returns the actual Cloud.ru API endpoints. +func getEndpoints(url string) (*EndpointsResponse, error) { + req, err := http.NewRequest(http.MethodGet, url, http.NoBody) + if err != nil { + return nil, fmt.Errorf("construct HTTP request for cloud.ru endpoints: %w", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("get cloud.ru endpoints: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("get cloud.ru endpoints: unexpected status code %d", resp.StatusCode) + } + + var endpoints EndpointsResponse + if err = json.NewDecoder(resp.Body).Decode(&endpoints); err != nil { + return nil, fmt.Errorf("decode cloud.ru endpoints: %w", err) + } + + return &endpoints, nil +} + +// Get returns the API address of the product by its ID. +// If the product is not found, the function returns nil. +func (er *EndpointsResponse) Get(id string) *Endpoint { + for i := range er.Endpoints { + if er.Endpoints[i].ID == id { + return &er.Endpoints[i] + } + } + + return nil +} + +// Close closes the KMS gRPC client connection. +func (c *Client) Close() error { return c.kmsConn.Close() } diff --git a/cloudru/keysource.go b/cloudru/keysource.go new file mode 100644 index 000000000..476774369 --- /dev/null +++ b/cloudru/keysource.go @@ -0,0 +1,227 @@ +package cloudru + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + "time" + + kmsV1 "github.com/cloudru-tech/key-manager-sdk/api/v1" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/getsops/sops/v3/logging" +) + +const ( + // EnvDiscoveryURL is the environment variable used to set the Cloudru. + EnvDiscoveryURL = "CLOUDRU_DISCOVERY_URL" + // EnvAccessKeyID is the environment variable used to set the Cloudru API access key ID. + EnvAccessKeyID = "CLOUDRU_ACCESS_KEY_ID" + // EnvAccessKeySecret is the environment variable used to set the Cloudru API access key secret. + EnvAccessKeySecret = "CLOUDRU_ACCESS_KEY_SECRET" + + // KeyTypeIdentifier is the string used to identify a Cloudru KMS MasterKey. + KeyTypeIdentifier = "cloudru_kms" + + // DiscoveryURL is the default Cloudru API discovery URL, which is used to + // retrieve the actual API addresses of Cloudru products. + DiscoveryURL = "https://api.cloud.ru/endpoints" +) + +var ( + // ErrInvalidKeyID is returned when the key ID format is invalid. + ErrInvalidKeyID = errors.New("key id is invalid: it should be a UUID with an optional version number separated by a colon, e.g.: 123e4567-e89b-12d3-a456-426614174000:1") +) + +func init() { + logger = logging.NewLogger("CLOUDRU_KMS") +} + +var ( + // log is the global logger for any Vault Transit MasterKey. + logger *logrus.Logger +) + +// AccessKey is used to retrieve the cloudru API access token. +type AccessKey struct { + KeyID string + Secret string +} + +// MasterKey is a Cloudru KMS backend path, which is used to Encrypt and Decrypt SOPS data key. +type MasterKey struct { + // KeyID is the identifier is used to refer to the cloudru kms key. + KeyID string + // Cipher is the value returned after encrypting with Cloudru KMS. + Cipher []byte + // CreatedAt is the date and time when the MasterKey was created. + // Used for NeedsRotation. + CreatedAt time.Time + + // credentials is the AccessKey used for authenticating towards the Cloudru. + credentials AccessKey + // conn is the gRPC connection to the Cloudru KMS server. + conn *grpc.ClientConn +} + +// NewMasterKeyFromKeyID creates a new MasterKey with the provided KMS key ID. +func NewMasterKeyFromKeyID(kid string) (*MasterKey, error) { + parts := strings.SplitN(kid, ":", 2) + if len(parts) == 2 { + _, err := strconv.Atoi(parts[1]) + if err != nil { + return nil, ErrInvalidKeyID + } + } + + parsed, err := uuid.Parse(strings.TrimSpace(parts[0])) + if err != nil { + return nil, fmt.Errorf("invalid KMS key id: %s", err) + } + if parsed == uuid.Nil { + return nil, errors.New("invalid KMS key id: key id should be a valid and non-zero UUID") + } + + return &MasterKey{ + KeyID: kid, + CreatedAt: time.Now().UTC(), + }, nil +} + +// NewMasterKeysFromKeyIDs creates a new MasterKey with the provided KMS key IDs. +func NewMasterKeysFromKeyIDs(kids string) ([]*MasterKey, error) { + if kids == "" { + return nil, nil + } + + var keys []*MasterKey + for _, kid := range strings.Split(kids, ",") { + key, err := NewMasterKeyFromKeyID(kid) + if err != nil { + return nil, fmt.Errorf("parse key '%s': %s", kid, err) + } + keys = append(keys, key) + } + + return keys, nil +} + +// Encrypt takes a SOPS data key, encrypts it with Vault Transit, and stores +// the result in the EncryptedKey field. +func (key *MasterKey) Encrypt(dataKey []byte) error { + c, err := provideClient() + if err != nil { + return fmt.Errorf("initialize cloud.ru API: %w", err) + } + defer func() { + if closeErr := c.Close(); closeErr != nil { + logger.Errorf("failed to close cloud.ru KMS client connection: %s", closeErr) + } + }() + + kid, version, err := parseKeyID(key.KeyID) + if err != nil { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + req := &kmsV1.EncryptRequest{ + KeyId: kid, + KeyVersionId: int32(version), + Plaintext: wrapperspb.Bytes(dataKey), + } + resp, err := c.KMS.Encrypt(ctx, req) + if err != nil { + return fmt.Errorf("encrypt data with key_id '%s': %s", key.KeyID, err) + } + + key.Cipher = resp.Ciphertext.GetValue() + logger.WithField("key_id", 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 len(key.Cipher) == 0 { + return key.Encrypt(dataKey) + } + return nil +} + +// EncryptedDataKey returns the encrypted data key this master key holds. +func (key *MasterKey) EncryptedDataKey() []byte { return key.Cipher } + +// SetEncryptedDataKey sets the encrypted data key for this master key. +func (key *MasterKey) SetEncryptedDataKey(enc []byte) { key.Cipher = enc } + +// Decrypt decrypts the EncryptedKey field with Vault Transit and returns the result. +func (key *MasterKey) Decrypt() ([]byte, error) { + c, err := provideClient() + if err != nil { + return nil, fmt.Errorf("initialize cloud.ru API: %w", err) + } + defer func() { + if closeErr := c.Close(); closeErr != nil { + logger.Errorf("failed to close cloud.ru KMS client connection: %s", closeErr) + } + }() + + kid, _, err := parseKeyID(key.KeyID) + if err != nil { + return nil, err + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + req := &kmsV1.DecryptRequest{ + KeyId: kid, + Ciphertext: wrapperspb.Bytes(key.Cipher), + } + resp, err := c.KMS.Decrypt(ctx, req) + if err != nil { + return nil, fmt.Errorf("decrypt data with key_id '%s': %s", key.KeyID, err) + } + + logger.WithField("key_id", key.KeyID).Info("Decryption successful") + return resp.Plaintext.GetValue(), nil +} + +// NeedsRotation returns whether the data key needs to be rotated or not. +func (key *MasterKey) NeedsRotation() bool { + // TODO: research this value + return time.Since(key.CreatedAt) > (time.Hour * 24 * 30 * 6) +} + +// ToString converts the key to a string representation. +func (key *MasterKey) ToString() string { return key.KeyID } + +// ToMap converts the MasterKey to a map for serialization purposes. +func (key *MasterKey) ToMap() map[string]interface{} { + out := make(map[string]interface{}) + out["key_id"] = key.KeyID + out["created_at"] = key.CreatedAt.UTC().Format(time.RFC3339) + out["enc"] = string(key.Cipher) + return out +} + +// TypeToIdentifier returns the string identifier for the MasterKey type. +func (key *MasterKey) TypeToIdentifier() string { return KeyTypeIdentifier } + +func parseKeyID(kid string) (key string, version int, err error) { + parts := strings.SplitN(kid, ":", 2) + key = parts[0] + if len(parts) == 2 { + version, err = strconv.Atoi(parts[1]) + if err != nil { + return "", 0, ErrInvalidKeyID + } + } + return key, version, nil +} diff --git a/cmd/sops/main.go b/cmd/sops/main.go index 42883ff37..c2ed187cd 100644 --- a/cmd/sops/main.go +++ b/cmd/sops/main.go @@ -23,6 +23,7 @@ import ( "github.com/getsops/sops/v3/age" _ "github.com/getsops/sops/v3/audit" "github.com/getsops/sops/v3/azkv" + "github.com/getsops/sops/v3/cloudru" "github.com/getsops/sops/v3/cmd/sops/codes" "github.com/getsops/sops/v3/cmd/sops/common" "github.com/getsops/sops/v3/cmd/sops/subcommand/exec" @@ -80,7 +81,7 @@ 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, Cloudru KMS, age, and GPG support" app.ArgsUsage = "sops [options] file" app.Version = version.Version app.Authors = []cli.Author{ @@ -89,7 +90,7 @@ func main() { {Name: "Julien Vehent", Email: "jvehent@mozilla.com"}, } app.UsageText = `sops is an editor of encrypted files that supports AWS KMS, GCP, AZKV, - PGP, and Age + CKMS, 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. @@ -118,6 +119,17 @@ func main() { https://docs.microsoft.com/en-us/go/azure/azure-sdk-go-authorization#use-environment-based-authentication. The user/sp needs the key/encrypt and key/decrypt permissions.) + To encrypt or decrypt a document with Cloudru KMS, specify the + Azure Key Vault key URL in the --cloudru-kms flag or in the + CLOUDRU_KMS_KEY_ID environment variable in format "key_id:version" or "key_id". + If the version is not specified, the latest version will be used. + Authentication is based on environment variables, these variables are required: + - CLOUDRU_ACCESS_KEY_ID: Cloudru API access key identifier. + - CLOUDRU_ACCESS_KEY_SECRET: Cloudru API access key secret. + See the Authentication guide for more information: + https://cloud.ru/docs/console_api/ug/topics/guides__auth_api.html + The subject of the key must have the "encrypt" and "decrypt" permissions. + To encrypt or decrypt using age, specify the recipient in the -a flag, or in the SOPS_AGE_RECIPIENTS environment variable. @@ -513,6 +525,10 @@ func main() { 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", }, + cli.StringSliceFlag{ + Name: "cloudru-kms", + Usage: "the Cloudru KMS key ID the new group should contain. Can be specified more than once", + }, cli.StringSliceFlag{ Name: "age", Usage: "the age recipient the new group should contain. Can be specified more than once", @@ -536,6 +552,7 @@ func main() { gcpKmses := c.StringSlice("gcp-kms") vaultURIs := c.StringSlice("hc-vault-transit") azkvs := c.StringSlice("azure-kv") + ckms := c.StringSlice("cloudru-kms") ageRecipients := c.StringSlice("age") if c.NArg() != 0 { return common.NewExitError(fmt.Errorf("error: no positional arguments allowed"), codes.ErrorGeneric) @@ -566,6 +583,15 @@ func main() { } group = append(group, k) } + for _, kid := range ckms { + k, err := cloudru.NewMasterKeyFromKeyID(kid) + 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 { @@ -872,6 +898,11 @@ func main() { Usage: "comma separated list of PGP fingerprints", EnvVar: "SOPS_PGP_FP", }, + cli.StringFlag{ + Name: "cloudru-kms", + Usage: "comma separated list of Cloudru KMS key IDs", + EnvVar: "CLOUDRU_KMS_KEY_ID", + }, cli.StringFlag{ Name: "age, a", Usage: "comma separated list of age recipients", @@ -1050,6 +1081,14 @@ func main() { Name: "rm-hc-vault-transit", Usage: "remove the provided comma-separated list of Vault's URI key from the list of master keys on the given file ( eg. https://vault.example.org:8200/v1/transit/keys/dev)", }, + cli.StringFlag{ + Name: "add-cloudru-kms", + Usage: "add the provided comma-separated list of Cloudru KMS key resource IDs to the list of master keys on the given file", + }, + cli.StringFlag{ + Name: "rm-cloudru-kms", + Usage: "remove the provided comma-separated list of Cloudru KMS key resource IDs from the list of master keys on the given file", + }, cli.StringFlag{ Name: "add-age", Usage: "add the provided comma-separated list of age recipients fingerprints to the list of master keys on the given file", @@ -1092,8 +1131,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-cloudru-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-cloudru-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) } } @@ -1184,6 +1223,11 @@ func main() { Usage: "comma separated list of vault's key URI (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev')", EnvVar: "SOPS_VAULT_URIS", }, + cli.StringFlag{ + Name: "cloudru-kms", + Usage: "comma separated list of Cloudru KMS key IDs", + EnvVar: "SOPS_CLOUDRU_KMS_IDS", + }, cli.StringFlag{ Name: "pgp, p", Usage: "comma separated list of PGP fingerprints", @@ -1544,6 +1588,11 @@ func main() { Usage: "comma separated list of vault's key URI (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev')", EnvVar: "SOPS_VAULT_URIS", }, + cli.StringFlag{ + Name: "cloudru-kms", + Usage: "comma separated list of Cloudru KMS resource IDs", + EnvVar: "SOPS_CLOUDRU_KMS_IDS", + }, cli.StringFlag{ Name: "pgp, p", Usage: "comma separated list of PGP fingerprints", @@ -1606,6 +1655,14 @@ func main() { Name: "rm-hc-vault-transit", Usage: "remove the provided comma-separated list of Vault's URI key from the list of master keys on the given file ( eg. https://vault.example.org:8200/v1/transit/keys/dev)", }, + cli.StringFlag{ + Name: "add-cloudru-kms", + Usage: "add the provided comma-separated list of Cloudru KMS key IDs to the list of master keys on the given file", + }, + cli.StringFlag{ + Name: "rm-cloudru-kms", + Usage: "remove the provided comma-separated list of Cloudru KMS key IDs from the list of master keys on the given file", + }, cli.StringFlag{ Name: "add-age", Usage: "add the provided comma-separated list of age recipients fingerprints to the list of master keys on the given file", @@ -1715,8 +1772,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-cloudru-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-cloudru-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 { @@ -2004,7 +2061,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, hcVaultTransitOptionName string, ckmsOptionName 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) @@ -2029,6 +2086,13 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO for _, k := range hcVaultKeys { masterKeys = append(masterKeys, k) } + ckmsKeys, err := cloudru.NewMasterKeysFromKeyIDs(c.String(ckmsOptionName)) + if err != nil { + return nil, err + } + for _, k := range ckmsKeys { + masterKeys = append(masterKeys, k) + } ageKeys, err := age.MasterKeysFromRecipients(c.String(ageOptionName)) if err != nil { return nil, err @@ -2041,11 +2105,11 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO func getRotateOpts(c *cli.Context, fileName string, inputStore common.Store, outputStore common.Store, svcs []keyservice.KeyServiceClient, decryptionOrder []string) (rotateOpts, error) { kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context")) - addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-azure-kv", "add-hc-vault-transit", "add-age") + addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-azure-kv", "add-hc-vault-transit", "add-cloudru-kms", "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-hc-vault-transit", "rm-cloudru-kms", "rm-age") if err != nil { return rotateOpts{}, err } @@ -2179,6 +2243,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { var cloudKmsKeys []keys.MasterKey var azkvKeys []keys.MasterKey var hcVaultMkKeys []keys.MasterKey + var ckmsKeys []keys.MasterKey var ageMasterKeys []keys.MasterKey kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context")) if c.String("encryption-context") != "" && kmsEncryptionContext == nil { @@ -2212,6 +2277,16 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { hcVaultMkKeys = append(hcVaultMkKeys, k) } } + if c.String("cloudru-kms") != "" { + mk, err := cloudru.NewMasterKeysFromKeyIDs(c.String("cloudru-kms")) + if err != nil { + return nil, err + } + + for _, k := range mk { + ckmsKeys = append(ckmsKeys, k) + } + } if c.String("pgp") != "" { for _, k := range pgp.MasterKeysFromFingerprintString(c.String("pgp")) { pgpKeys = append(pgpKeys, k) @@ -2226,7 +2301,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("hc-vault-transit") == "" && c.String("cloudru-kms") == "" && c.String("age") == "" { conf, err := loadConfig(c, file, kmsEncryptionContext) // config file might just not be supplied, without any error if conf == nil { @@ -2244,6 +2319,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { group = append(group, azkvKeys...) group = append(group, pgpKeys...) group = append(group, hcVaultMkKeys...) + group = append(group, ckmsKeys...) group = append(group, ageMasterKeys...) log.Debugf("Master keys available: %+v", group) return []sops.KeyGroup{group}, nil diff --git a/config/config.go b/config/config.go index 8d3dc4dd1..46a711145 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ import ( "github.com/getsops/sops/v3" "github.com/getsops/sops/v3/age" "github.com/getsops/sops/v3/azkv" + "github.com/getsops/sops/v3/cloudru" "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" @@ -86,13 +87,14 @@ type configFile struct { } type keyGroup struct { - Merge []keyGroup - KMS []kmsKey - GCPKMS []gcpKmsKey `yaml:"gcp_kms"` - AzureKV []azureKVKey `yaml:"azure_keyvault"` - Vault []string `yaml:"hc_vault"` - Age []string `yaml:"age"` - PGP []string + Merge []keyGroup + KMS []kmsKey + GCPKMS []gcpKmsKey `yaml:"gcp_kms"` + AzureKV []azureKVKey `yaml:"azure_keyvault"` + Vault []string `yaml:"hc_vault"` + CloudruKMS []string `yaml:"cloudru_kms"` + Age []string `yaml:"age"` + PGP []string } type gcpKmsKey struct { @@ -136,6 +138,7 @@ type creationRule struct { AzureKeyVault string `yaml:"azure_keyvault"` VaultURI string `yaml:"hc_vault_transit_uri"` KeyGroups []keyGroup `yaml:"key_groups"` + CloudruKMS string `yaml:"cloudru_kms"` ShamirThreshold int `yaml:"shamir_threshold"` UnencryptedSuffix string `yaml:"unencrypted_suffix"` EncryptedSuffix string `yaml:"encrypted_suffix"` @@ -244,6 +247,13 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[ if err != nil { return nil, err } + for _, k := range group.CloudruKMS { + mk, err := cloudru.NewMasterKeyFromKeyID(k) + if err != nil { + return nil, err + } + keyGroup = append(keyGroup, mk) + } groups = append(groups, keyGroup) } } else { @@ -281,6 +291,14 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[ for _, k := range vaultKeys { keyGroup = append(keyGroup, k) } + ckmsKeys, err := cloudru.NewMasterKeysFromKeyIDs(cRule.CloudruKMS) + if err != nil { + return nil, err + } + for _, k := range ckmsKeys { + keyGroup = append(keyGroup, k) + } + groups = append(groups, keyGroup) } return groups, nil diff --git a/go.mod b/go.mod index 7015d2cd1..573bb0583 100644 --- a/go.mod +++ b/go.mod @@ -20,10 +20,13 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 github.com/blang/semver v3.5.1+incompatible + github.com/cloudru-tech/iam-sdk v1.0.4 + github.com/cloudru-tech/key-manager-sdk v1.0.1 github.com/fatih/color v1.18.0 github.com/getsops/gopgagent v0.0.0-20240527072608-0c14999532fe github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 + github.com/google/uuid v1.6.0 github.com/goware/prefixer v0.0.0-20160118172347-395022866408 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/vault/api v1.15.0 @@ -101,7 +104,6 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/s2a-go v0.1.8 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 6c83801a4..2c651417a 100644 --- a/go.sum +++ b/go.sum @@ -117,6 +117,10 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY= github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/cloudru-tech/iam-sdk v1.0.4 h1:qnGMhft3FnknCj6F+vTSbwznqJDDCAG6hWRe6IcCyVM= +github.com/cloudru-tech/iam-sdk v1.0.4/go.mod h1:V7O/EJJrIAHk1WEXclh7A/p0yQiaFIoPeIfJoc0O61w= +github.com/cloudru-tech/key-manager-sdk v1.0.1 h1:tHRR0pzDKUFBs9tRpXshUFfP2ec8w7IWBz/BbsrY02s= +github.com/cloudru-tech/key-manager-sdk v1.0.1/go.mod h1:r1QVrGhi9iKCetMX3i/2KShvDQojRlMo59Z/qwCOE54= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= diff --git a/keyservice/keyservice.go b/keyservice/keyservice.go index 321af7942..03a5e416a 100644 --- a/keyservice/keyservice.go +++ b/keyservice/keyservice.go @@ -9,6 +9,7 @@ import ( "github.com/getsops/sops/v3/age" "github.com/getsops/sops/v3/azkv" + "github.com/getsops/sops/v3/cloudru" "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/keys" @@ -78,6 +79,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key { }, }, } + case *cloudru.MasterKey: + return Key{ + KeyType: &Key_CloudruKmsKey{ + CloudruKmsKey: &CloudruKmsKey{ + 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 a810b2805..a4ed10a1a 100644 --- a/keyservice/keyservice.pb.go +++ b/keyservice/keyservice.pb.go @@ -33,6 +33,7 @@ type Key struct { // *Key_AzureKeyvaultKey // *Key_VaultKey // *Key_AgeKey + // *Key_CloudruKmsKey KeyType isKey_KeyType `protobuf_oneof:"key_type"` } @@ -115,6 +116,13 @@ func (x *Key) GetAgeKey() *AgeKey { return nil } +func (x *Key) GetCloudruKmsKey() *CloudruKmsKey { + if x, ok := x.GetKeyType().(*Key_CloudruKmsKey); ok { + return x.CloudruKmsKey + } + 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_CloudruKmsKey struct { + CloudruKmsKey *CloudruKmsKey `protobuf:"bytes,7,opt,name=cloudru_kms_key,json=cloudruKmsKey,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_CloudruKmsKey) isKey_KeyType() {} + type PgpKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -481,6 +495,51 @@ func (x *AgeKey) GetRecipient() string { return "" } +type CloudruKmsKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"` +} + +func (x *CloudruKmsKey) Reset() { + *x = CloudruKmsKey{} + mi := &file_keyservice_keyservice_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CloudruKmsKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloudruKmsKey) ProtoMessage() {} + +func (x *CloudruKmsKey) 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 CloudruKmsKey.ProtoReflect.Descriptor instead. +func (*CloudruKmsKey) Descriptor() ([]byte, []int) { + return file_keyservice_keyservice_proto_rawDescGZIP(), []int{7} +} + +func (x *CloudruKmsKey) GetKeyId() string { + if x != nil { + return x.KeyId + } + return "" +} + type EncryptRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -492,7 +551,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 +563,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 +576,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 +603,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 +615,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 +628,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 +649,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 +661,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 +674,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 +701,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 +713,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 +726,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 +740,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, 0xd2, 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 +757,71 @@ 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, 0x38, 0x0a, 0x0f, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x75, 0x5f, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x75, 0x4b, + 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x75, + 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, 0x26, + 0x0a, 0x0d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x75, 0x4b, 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 ( @@ -770,7 +836,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 +845,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 + (*CloudruKmsKey)(nil), // 7: CloudruKmsKey + (*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 +859,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.cloudru_kms_key:type_name -> CloudruKmsKey + 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 +886,7 @@ func file_keyservice_keyservice_proto_init() { (*Key_AzureKeyvaultKey)(nil), (*Key_VaultKey)(nil), (*Key_AgeKey)(nil), + (*Key_CloudruKmsKey)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -825,7 +894,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..84e521194 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; + CloudruKmsKey cloudru_kms_key = 7; } } @@ -44,6 +45,10 @@ message AgeKey { string recipient = 1; } +message CloudruKmsKey { + string key_id = 1; +} + message EncryptRequest { Key key = 1; bytes plaintext = 2; diff --git a/keyservice/server.go b/keyservice/server.go index 9f2b486a6..e9a857247 100644 --- a/keyservice/server.go +++ b/keyservice/server.go @@ -3,15 +3,17 @@ package keyservice import ( "fmt" + "golang.org/x/net/context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/getsops/sops/v3/age" "github.com/getsops/sops/v3/azkv" + "github.com/getsops/sops/v3/cloudru" "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" "github.com/getsops/sops/v3/pgp" - "golang.org/x/net/context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // Server is a key service server that uses SOPS MasterKeys to fulfill requests @@ -87,6 +89,28 @@ func (ks *Server) encryptWithAge(key *AgeKey, plaintext []byte) ([]byte, error) return []byte(ageKey.EncryptedKey), nil } +func (ks *Server) encryptWithCloudruKMS(key *CloudruKmsKey, plaintext []byte) ([]byte, error) { + mk := cloudru.MasterKey{ + KeyID: key.KeyId, + } + + if err := mk.Encrypt(plaintext); err != nil { + return nil, err + } + + return mk.Cipher, nil +} + +func (km *Server) decryptWithCloudruKMS(key *CloudruKmsKey, ciphertext []byte) ([]byte, error) { + mk := cloudru.MasterKey{ + KeyID: key.KeyId, + Cipher: ciphertext, + } + + plaintext, err := mk.Decrypt() + return plaintext, err +} + func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error) { pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint) pgpKey.EncryptedKey = string(ciphertext) @@ -196,6 +220,14 @@ func (ks Server) Encrypt(ctx context.Context, response = &EncryptResponse{ Ciphertext: ciphertext, } + case *Key_CloudruKmsKey: + ciphertext, err := ks.encryptWithCloudruKMS(k.CloudruKmsKey, 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: @@ -298,6 +330,14 @@ func (ks Server) Decrypt(ctx context.Context, response = &DecryptResponse{ Plaintext: plaintext, } + case *Key_CloudruKmsKey: + plaintext, err := ks.decryptWithCloudruKMS(k.CloudruKmsKey, 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 169e8dbb5..ac0df7375 100644 --- a/stores/stores.go +++ b/stores/stores.go @@ -10,13 +10,13 @@ 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" "github.com/getsops/sops/v3/azkv" + "github.com/getsops/sops/v3/cloudru" "github.com/getsops/sops/v3/gcpkms" "github.com/getsops/sops/v3/hcvault" "github.com/getsops/sops/v3/kms" @@ -48,6 +48,7 @@ type Metadata struct { GCPKMSKeys []gcpkmskey `yaml:"gcp_kms" json:"gcp_kms"` AzureKeyVaultKeys []azkvkey `yaml:"azure_kv" json:"azure_kv"` VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"` + CloudruKMSKeys []ckmskey `yaml:"cloudru_kms,omitempty" json:"cloudru_kms,omitempty"` AgeKeys []agekey `yaml:"age" json:"age"` LastModified string `yaml:"lastmodified" json:"lastmodified"` MessageAuthenticationCode string `yaml:"mac" json:"mac"` @@ -66,6 +67,7 @@ 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"` + CloudruKMSKeys []ckmskey `yaml:"cloudru_kms,omitempty" json:"cloudru_kms,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"` @@ -92,6 +94,12 @@ type gcpkmskey struct { EncryptedDataKey string `yaml:"enc" json:"enc"` } +type ckmskey struct { + KeyID string `yaml:"key_id" json:"key_id"` + CreatedAt string `yaml:"created_at" json:"created_at"` + EncryptionData string `yaml:"enc" json:"enc"` +} + type vaultkey struct { VaultAddress string `yaml:"vault_address" json:"vault_address"` EnginePath string `yaml:"engine_path" json:"engine_path"` @@ -135,6 +143,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { m.VaultKeys = vaultKeysFromGroup(group) m.AzureKeyVaultKeys = azkvKeysFromGroup(group) m.AgeKeys = ageKeysFromGroup(group) + m.CloudruKMSKeys = ckmsKeysFromGroup(group) } else { for _, group := range sopsMetadata.KeyGroups { m.KeyGroups = append(m.KeyGroups, keygroup{ @@ -144,6 +153,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { VaultKeys: vaultKeysFromGroup(group), AzureKeyVaultKeys: azkvKeysFromGroup(group), AgeKeys: ageKeysFromGroup(group), + CloudruKMSKeys: ckmsKeysFromGroup(group), }) } } @@ -211,6 +221,21 @@ func vaultKeysFromGroup(group sops.KeyGroup) (keys []vaultkey) { return } +func ckmsKeysFromGroup(group sops.KeyGroup) (keys []ckmskey) { + for _, key := range group { + switch k := key.(type) { + case *cloudru.MasterKey: + keys = append(keys, ckmskey{ + KeyID: k.KeyID, + CreatedAt: k.CreatedAt.Format(time.RFC3339), + EncryptionData: string(k.Cipher), + }) + } + } + return + +} + func azkvKeysFromGroup(group sops.KeyGroup) (keys []azkvkey) { for _, key := range group { switch key := key.(type) { @@ -294,7 +319,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, vaultKeys []vaultkey, ageKeys []agekey, ckmsKeys []ckmskey) (sops.KeyGroup, error) { var internalGroup sops.KeyGroup for _, kmsKey := range kmsKeys { k, err := kmsKey.toInternal() @@ -338,13 +363,20 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske } internalGroup = append(internalGroup, k) } + for _, ckmsKey := range ckmsKeys { + k, err := ckmsKey.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.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.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 || len(m.CloudruKMSKeys) > 0 { + internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys, m.VaultKeys, m.AgeKeys, m.CloudruKMSKeys) if err != nil { return nil, err } @@ -352,7 +384,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.VaultKeys, group.AgeKeys, group.CloudruKMSKeys) if err != nil { return nil, err } @@ -405,6 +437,18 @@ func (azkvKey *azkvkey) toInternal() (*azkv.MasterKey, error) { }, nil } +func (ckmsKey *ckmskey) toInternal() (*cloudru.MasterKey, error) { + creationDate, err := time.Parse(time.RFC3339, ckmsKey.CreatedAt) + if err != nil { + return nil, err + } + return &cloudru.MasterKey{ + KeyID: ckmsKey.KeyID, + Cipher: []byte(ckmsKey.EncryptionData), + CreatedAt: creationDate, + }, nil +} + func (vaultKey *vaultkey) toInternal() (*hcvault.MasterKey, error) { creationDate, err := time.Parse(time.RFC3339, vaultKey.CreatedAt) if err != nil {