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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 81 additions & 12 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/logging"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/stackitkms"
"github.com/getsops/sops/v3/stores"
"github.com/getsops/sops/v3/stores/dotenv"
"github.com/getsops/sops/v3/stores/json"
Expand Down Expand Up @@ -91,14 +92,14 @@ func main() {
},
}
app.Name = "sops"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, HuaweiCloud KMS, Azure Key Vault, age, and GPG support"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, HuaweiCloud KMS, STACKIT KMS, Azure Key Vault, 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, HuaweiCloud KMS, AZKV,
PGP, and Age
app.UsageText = `sops is an editor of encrypted files that supports AWS KMS, GCP, HuaweiCloud KMS, STACKIT KMS,
AZKV, 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.
Expand All @@ -117,6 +118,12 @@ func main() {
HUAWEICLOUD_SDK_AK, HUAWEICLOUD_SDK_SK, HUAWEICLOUD_SDK_PROJECT_ID, or
use credentials file at ~/.huaweicloud/credentials)

To encrypt or decrypt a document with STACKIT KMS, specify the
STACKIT KMS resource ID in the --stackit-kms flag or in the
SOPS_STACKIT_KMS_IDS environment variable.
(Authentication is handled by the STACKIT SDK via environment variables,
service account key files, or credentials file at ~/.stackit/credentials.json)

To encrypt or decrypt a document with HashiCorp Vault's Transit Secret
Engine, specify the Vault key URI name in the --hc-vault-transit flag
or in the SOPS_VAULT_URIS environment variable (for example
Expand All @@ -142,12 +149,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, --hckms, --hc-vault-transit, and --azure-kv flags are only
The -p, -k, --gcp-kms, --hckms, --stackit-kms, --hc-vault-transit, 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,hckms,azure-kv,hc-vault-transit}"
and "rm-{kms,pgp,gcp-kms,hckms,azure-kv,hc-vault-transit}" flags with --rotate
keys in existing documents, use the "add-{kms,pgp,gcp-kms,hckms,stackit-kms,azure-kv,hc-vault-transit}"
and "rm-{kms,pgp,gcp-kms,hckms,stackit-kms,azure-kv,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.
Expand Down Expand Up @@ -582,6 +589,10 @@ func main() {
Name: "hckms",
Usage: "the HuaweiCloud KMS key ID (format: region:key-uuid) the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "stackit-kms",
Usage: "the STACKIT KMS resource ID the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "azure-kv",
Usage: "the Azure Key Vault key URL the new group should contain. Can be specified more than once",
Expand Down Expand Up @@ -635,6 +646,15 @@ func main() {
}
group = append(group, k)
}
stackitKmsIds := c.StringSlice("stackit-kms")
for _, resID := range stackitKmsIds {
k, err := stackitkms.NewMasterKey(resID)
if err != nil {
log.WithError(err).Error("Failed to add key")
continue
}
group = append(group, k)
}
for _, url := range azkvs {
k, err := azkv.NewMasterKeyFromURL(url)
if err != nil {
Expand Down Expand Up @@ -950,6 +970,11 @@ func main() {
Usage: "comma separated list of HuaweiCloud KMS key IDs (format: region:key-uuid)",
EnvVar: "SOPS_HUAWEICLOUD_KMS_IDS",
},
cli.StringFlag{
Name: "stackit-kms",
Usage: "comma separated list of STACKIT KMS resource IDs",
EnvVar: "SOPS_STACKIT_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
Expand Down Expand Up @@ -1143,6 +1168,14 @@ func main() {
Name: "rm-hckms",
Usage: "remove the provided comma-separated list of HuaweiCloud KMS key IDs (format: region:key-uuid) from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-stackit-kms",
Usage: "add the provided comma-separated list of STACKIT KMS resource IDs to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-stackit-kms",
Usage: "remove the provided comma-separated list of STACKIT KMS resource IDs from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-azure-kv",
Usage: "add the provided comma-separated list of Azure Key Vault key URLs to the list of master keys on the given file",
Expand Down Expand Up @@ -1209,8 +1242,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-hckms") != "" || 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-hckms") != "" || 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-hckms") != "" || c.String("add-stackit-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-hckms") != "" || c.String("rm-stackit-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
return common.NewExitError(fmt.Sprintf("Error: cannot add or remove keys on non-existent file %q, use the `edit` subcommand instead.", fileName), codes.CannotChangeKeysFromNonExistentFile)
}
}
Expand Down Expand Up @@ -1301,6 +1334,11 @@ func main() {
Usage: "comma separated list of HuaweiCloud KMS key IDs (format: region:key-uuid)",
EnvVar: "SOPS_HUAWEICLOUD_KMS_IDS",
},
cli.StringFlag{
Name: "stackit-kms",
Usage: "comma separated list of STACKIT KMS resource IDs",
EnvVar: "SOPS_STACKIT_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
Expand Down Expand Up @@ -1714,6 +1752,11 @@ func main() {
Usage: "comma separated list of HuaweiCloud KMS key IDs (format: region:key-uuid)",
EnvVar: "SOPS_HUAWEICLOUD_KMS_IDS",
},
cli.StringFlag{
Name: "stackit-kms",
Usage: "comma separated list of STACKIT KMS resource IDs",
EnvVar: "SOPS_STACKIT_KMS_IDS",
},
cli.StringFlag{
Name: "azure-kv",
Usage: "comma separated list of Azure Key Vault URLs",
Expand Down Expand Up @@ -1770,6 +1813,14 @@ func main() {
Name: "rm-hckms",
Usage: "remove the provided comma-separated list of HuaweiCloud KMS key IDs (format: region:key-uuid) from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-stackit-kms",
Usage: "add the provided comma-separated list of STACKIT KMS resource IDs to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-stackit-kms",
Usage: "remove the provided comma-separated list of STACKIT KMS resource IDs from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-azure-kv",
Usage: "add the provided comma-separated list of Azure Key Vault key URLs to the list of master keys on the given file",
Expand Down Expand Up @@ -2235,7 +2286,7 @@ func getEncryptConfig(c *cli.Context, fileName string, inputStore common.Store,
}, nil
}

func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, hckmsOptionName string, azureKvOptionName string, hcVaultTransitOptionName string, ageOptionName string) ([]keys.MasterKey, error) {
func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsOptionName string, pgpOptionName string, gcpKmsOptionName string, hckmsOptionName string, stackitKmsOptionName string, azureKvOptionName string, 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)
Expand All @@ -2253,6 +2304,13 @@ func getMasterKeys(c *cli.Context, kmsEncryptionContext map[string]*string, kmsO
for _, k := range hckmsKeys {
masterKeys = append(masterKeys, k)
}
stackitKmsKeys, err := stackitkms.NewMasterKeyFromResourceIDString(c.String(stackitKmsOptionName))
if err != nil {
return nil, err
}
for _, k := range stackitKmsKeys {
masterKeys = append(masterKeys, k)
}
azureKeys, err := azkv.MasterKeysFromURLs(c.String(azureKvOptionName))
if err != nil {
return nil, err
Expand All @@ -2279,11 +2337,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-hckms", "add-azure-kv", "add-hc-vault-transit", "add-age")
addMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "add-kms", "add-pgp", "add-gcp-kms", "add-hckms", "add-stackit-kms", "add-azure-kv", "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-hckms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age")
rmMasterKeys, err := getMasterKeys(c, kmsEncryptionContext, "rm-kms", "rm-pgp", "rm-gcp-kms", "rm-hckms", "rm-stackit-kms", "rm-azure-kv", "rm-hc-vault-transit", "rm-age")
if err != nil {
return rotateOpts{}, err
}
Expand Down Expand Up @@ -2432,6 +2490,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
var azkvKeys []keys.MasterKey
var hcVaultMkKeys []keys.MasterKey
var hckmsMkKeys []keys.MasterKey
var stackitKmsMkKeys []keys.MasterKey
var ageMasterKeys []keys.MasterKey
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
if c.String("encryption-context") != "" && kmsEncryptionContext == nil {
Expand All @@ -2456,6 +2515,15 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
hckmsMkKeys = append(hckmsMkKeys, k)
}
}
if c.String("stackit-kms") != "" {
stackitKmsKeys, err := stackitkms.NewMasterKeyFromResourceIDString(c.String("stackit-kms"))
if err != nil {
return nil, err
}
for _, k := range stackitKmsKeys {
stackitKmsMkKeys = append(stackitKmsMkKeys, k)
}
}
if c.String("azure-kv") != "" {
azureKeys, err := azkv.MasterKeysFromURLs(c.String("azure-kv"))
if err != nil {
Expand Down Expand Up @@ -2488,7 +2556,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
ageMasterKeys = append(ageMasterKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("hckms") == "" && 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("hckms") == "" && c.String("stackit-kms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" {
conf := optionalConfig
var err error
if conf == nil {
Expand All @@ -2508,6 +2576,7 @@ func keyGroups(c *cli.Context, file string, optionalConfig *config.Config) ([]so
group = append(group, kmsKeys...)
group = append(group, cloudKmsKeys...)
group = append(group, hckmsMkKeys...)
group = append(group, stackitKmsMkKeys...)
group = append(group, azkvKeys...)
group = append(group, pgpKeys...)
group = append(group, hcVaultMkKeys...)
Expand Down
45 changes: 37 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/publish"
"github.com/getsops/sops/v3/stackitkms"
"go.yaml.in/yaml/v3"
)

Expand Down Expand Up @@ -130,14 +131,15 @@ type configFile struct {
}

type keyGroup struct {
Merge []keyGroup `yaml:"merge"`
KMS []kmsKey `yaml:"kms"`
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
HCKms []hckmsKey `yaml:"hckms"`
AzureKV []azureKVKey `yaml:"azure_keyvault"`
Vault []string `yaml:"hc_vault"`
Age []string `yaml:"age"`
PGP []string `yaml:"pgp"`
Merge []keyGroup `yaml:"merge"`
KMS []kmsKey `yaml:"kms"`
GCPKMS []gcpKmsKey `yaml:"gcp_kms"`
HCKms []hckmsKey `yaml:"hckms"`
STACKITKms []stackitKmsKey `yaml:"stackit_kms"`
AzureKV []azureKVKey `yaml:"azure_keyvault"`
Vault []string `yaml:"hc_vault"`
Age []string `yaml:"age"`
PGP []string `yaml:"pgp"`
}

type gcpKmsKey struct {
Expand All @@ -161,6 +163,10 @@ type hckmsKey struct {
KeyID string `yaml:"key_id"`
}

type stackitKmsKey struct {
ResourceID string `yaml:"resource_id"`
}

type destinationRule struct {
PathRegex string `yaml:"path_regex"`
S3Bucket string `yaml:"s3_bucket"`
Expand All @@ -183,6 +189,7 @@ type creationRule struct {
PGP interface{} `yaml:"pgp"` // string or []string
GCPKMS interface{} `yaml:"gcp_kms"` // string or []string
HCKms []string `yaml:"hckms"`
STACKITKms interface{} `yaml:"stackit_kms"` // string or []string
AzureKeyVault interface{} `yaml:"azure_keyvault"` // string or []string
VaultURI interface{} `yaml:"hc_vault_transit_uri"` // string or []string
KeyGroups []keyGroup `yaml:"key_groups"`
Expand Down Expand Up @@ -213,6 +220,10 @@ func (c *creationRule) GetGCPKMSKeys() ([]string, error) {
return parseKeyField(c.GCPKMS, "gcp_kms")
}

func (c *creationRule) GetSTACKITKmsKeys() ([]string, error) {
return parseKeyField(c.STACKITKms, "stackit_kms")
}

func (c *creationRule) GetAzureKeyVaultKeys() ([]string, error) {
return parseKeyField(c.AzureKeyVault, "azure_keyvault")
}
Expand Down Expand Up @@ -343,6 +354,13 @@ func extractMasterKeys(group keyGroup) (sops.KeyGroup, error) {
}
keyGroup = append(keyGroup, key)
}
for _, k := range group.STACKITKms {
key, err := stackitkms.NewMasterKey(k.ResourceID)
if err != nil {
return nil, err
}
keyGroup = append(keyGroup, key)
}
for _, k := range group.AzureKV {
if key, err := azkv.NewMasterKeyWithOptionalVersion(k.VaultURL, k.Key, k.Version); err == nil {
keyGroup = append(keyGroup, key)
Expand Down Expand Up @@ -423,6 +441,17 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
for _, k := range hckmsMasterKeys {
keyGroup = append(keyGroup, k)
}
stackitKmsKeys, err := getKeysWithValidation(cRule.GetSTACKITKmsKeys, "stackit_kms")
if err != nil {
return nil, err
}
stackitKmsMasterKeys, err := stackitkms.NewMasterKeyFromResourceIDString(strings.Join(stackitKmsKeys, ","))
if err != nil {
return nil, err
}
for _, k := range stackitKmsMasterKeys {
keyGroup = append(keyGroup, k)
}
azKeys, err := getKeysWithValidation(cRule.GetAzureKeyVaultKeys, "azure_keyvault")
if err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ require (
github.com/ory/dockertest/v3 v3.12.0
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.4
github.com/stackitcloud/stackit-sdk-go/core v0.22.0
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2
github.com/stretchr/testify v1.11.1
github.com/urfave/cli v1.22.17
go.yaml.in/yaml/v3 v3.0.4
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/stackitcloud/stackit-sdk-go/core v0.22.0 h1:6rViz7GnNwXSh51Lur5xuDzO8EWSZfN9J0HvEkBKq6c=
github.com/stackitcloud/stackit-sdk-go/core v0.22.0/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2 h1:2ulSL2IkIAKND59eAjbEhVkOoBMyvm48ojwz1a3t0U0=
github.com/stackitcloud/stackit-sdk-go/services/kms v1.3.2/go.mod h1:cuIaMMiHeHQsbvy7BOFMutoV3QtN+ZBx7Tg3GmYUw7s=
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=
Expand Down
9 changes: 9 additions & 0 deletions keyservice/keyservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/getsops/sops/v3/keys"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/stackitkms"
)

// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers
Expand Down Expand Up @@ -87,6 +88,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *stackitkms.MasterKey:
return Key{
KeyType: &Key_STACKITKmsKey{
STACKITKmsKey: &STACKITKmsKey{
ResourceId: mk.ResourceID,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}
Expand Down
5 changes: 5 additions & 0 deletions keyservice/keyservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ message Key {
VaultKey vault_key = 5;
AgeKey age_key = 6;
HckmsKey hckms_key = 7;
STACKITKmsKey stackit_kms_key = 8;
}
}

Expand Down Expand Up @@ -49,6 +50,10 @@ message HckmsKey {
string key_id = 1;
}

message STACKITKmsKey {
string resource_id = 1;
}

message EncryptRequest {
Key key = 1;
bytes plaintext = 2;
Expand Down
Loading