Skip to content

Commit f1999b5

Browse files
committed
Add Azure Key Vault publish destination
1 parent 0597040 commit f1999b5

File tree

5 files changed

+100
-19
lines changed

5 files changed

+100
-19
lines changed

cmd/sops/subcommand/publish/publish.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func Run(opts Opts) error {
135135
return fmt.Errorf("could not read file: %s", err)
136136
}
137137
}
138-
case *publish.VaultDestination:
138+
case *publish.VaultDestination, *publish.AzureKeyVaultDestination:
139139
_, err = common.DecryptTree(common.DecryptTreeOpts{
140140
Cipher: opts.Cipher,
141141
IgnoreMac: false,
@@ -174,7 +174,7 @@ func Run(opts Opts) error {
174174
switch dest := conf.Destination.(type) {
175175
case *publish.S3Destination, *publish.GCSDestination:
176176
err = dest.Upload(fileContents, destinationPath)
177-
case *publish.VaultDestination:
177+
case *publish.VaultDestination, *publish.AzureKeyVaultDestination:
178178
err = dest.UploadUnencrypted(data, destinationPath)
179179
}
180180

config/config.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,19 @@ type azureKVKey struct {
9696
}
9797

9898
type destinationRule struct {
99-
PathRegex string `yaml:"path_regex"`
100-
S3Bucket string `yaml:"s3_bucket"`
101-
S3Prefix string `yaml:"s3_prefix"`
102-
GCSBucket string `yaml:"gcs_bucket"`
103-
GCSPrefix string `yaml:"gcs_prefix"`
104-
VaultPath string `yaml:"vault_path"`
105-
VaultAddress string `yaml:"vault_address"`
106-
VaultKVMountName string `yaml:"vault_kv_mount_name"`
107-
VaultKVVersion int `yaml:"vault_kv_version"`
108-
RecreationRule creationRule `yaml:"recreation_rule,omitempty"`
109-
OmitExtensions bool `yaml:"omit_extensions"`
99+
PathRegex string `yaml:"path_regex"`
100+
S3Bucket string `yaml:"s3_bucket"`
101+
S3Prefix string `yaml:"s3_prefix"`
102+
GCSBucket string `yaml:"gcs_bucket"`
103+
GCSPrefix string `yaml:"gcs_prefix"`
104+
VaultPath string `yaml:"vault_path"`
105+
VaultAddress string `yaml:"vault_address"`
106+
VaultKVMountName string `yaml:"vault_kv_mount_name"`
107+
VaultKVVersion int `yaml:"vault_kv_version"`
108+
RecreationRule creationRule `yaml:"recreation_rule,omitempty"`
109+
OmitExtensions bool `yaml:"omit_extensions"`
110+
AzureKeyVaultURL string `yaml:"azure_keyvault_url"`
111+
AzurePublishSuffix string `yaml:"azure_publish_suffix"`
110112
}
111113

112114
type creationRule struct {
@@ -305,6 +307,9 @@ func parseDestinationRuleForFile(conf *configFile, filePath string, kmsEncryptio
305307
if dRule.VaultPath != "" {
306308
dest = publish.NewVaultDestination(dRule.VaultAddress, dRule.VaultPath, dRule.VaultKVMountName, dRule.VaultKVVersion)
307309
}
310+
if dRule.AzureKeyVaultURL != "" {
311+
dest = publish.NewAzureKeyVaultDestination(dRule.AzureKeyVaultURL, dRule.AzurePublishSuffix)
312+
}
308313
}
309314

310315
config, err := configFromRule(rule, kmsEncryptionContext)

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1
1010
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
1111
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0
12+
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
1213
github.com/ProtonMail/go-crypto v0.0.0-20230626094100-7e9e0395ebec
1314
github.com/aws/aws-sdk-go-v2 v1.18.1
1415
github.com/aws/aws-sdk-go-v2/config v1.18.27
@@ -35,7 +36,7 @@ require (
3536
go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a
3637
golang.org/x/crypto v0.10.0
3738
golang.org/x/net v0.11.0
38-
golang.org/x/sys v0.9.0
39+
golang.org/x/sys v0.10.0
3940
golang.org/x/term v0.9.0
4041
google.golang.org/api v0.129.0
4142
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529
@@ -119,7 +120,7 @@ require (
119120
go.opencensus.io v0.24.0 // indirect
120121
golang.org/x/mod v0.9.0 // indirect
121122
golang.org/x/oauth2 v0.9.0 // indirect
122-
golang.org/x/text v0.10.0 // indirect
123+
golang.org/x/text v0.11.0 // indirect
123124
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
124125
golang.org/x/tools v0.7.0 // indirect
125126
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInm
2222
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
2323
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM=
2424
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE=
25+
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 h1:xnO4sFyG8UH2fElBkcqLTOZsAajvKfnSlgBBW8dXYjw=
26+
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0/go.mod h1:XD3DIOOVgBCO03OleB1fHjgktVRFxlT++KwKgIOewdM=
2527
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
2628
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
2729
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
@@ -411,8 +413,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
411413
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
412414
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
413415
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
414-
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
415-
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
416+
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
417+
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
416418
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
417419
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
418420
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -429,8 +431,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
429431
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
430432
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
431433
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
432-
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
433-
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
434+
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
435+
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
434436
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
435437
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
436438
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

publish/azkv.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package publish
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"go.mozilla.org/sops/v3/logging"
9+
10+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
11+
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
12+
"github.com/sirupsen/logrus"
13+
)
14+
15+
var azkvLog *logrus.Logger
16+
17+
func init() {
18+
azkvLog = logging.NewLogger("AZKVPublish")
19+
}
20+
21+
type AzureKeyVaultDestination struct {
22+
azureKeyVaultURL string
23+
publishSuffix string
24+
}
25+
26+
func NewAzureKeyVaultDestination(azureKeyVaultURL string, publishSuffix string) *AzureKeyVaultDestination {
27+
return &AzureKeyVaultDestination{azureKeyVaultURL, publishSuffix}
28+
}
29+
30+
func (azkvd *AzureKeyVaultDestination) Path(fileName string) string {
31+
return fmt.Sprintf("%s", azkvd.azureKeyVaultURL)
32+
}
33+
34+
// Returns NotImplementedError
35+
func (azkvd *AzureKeyVaultDestination) Upload(fileContents []byte, fileName string) error {
36+
return &NotImplementedError{"Azure Key Vault does not support uploading encrypted sops files directly."}
37+
}
38+
39+
func (azkvd *AzureKeyVaultDestination) UploadUnencrypted(data map[string]interface{}, fileName string) error {
40+
credential, err := azidentity.NewDefaultAzureCredential(nil)
41+
if err != nil {
42+
log.Fatalf("failed to retrieve Azure credential %v", err)
43+
return err
44+
}
45+
46+
client, err := azsecrets.NewClient(azkvd.azureKeyVaultURL, credential, nil)
47+
if err != nil {
48+
log.Fatalf("failed to create azsecrets client %v", err)
49+
return err
50+
}
51+
52+
for secretName, secretElement := range data {
53+
54+
if !strings.HasSuffix(secretName, azkvd.publishSuffix) {
55+
continue
56+
}
57+
58+
secretValue := fmt.Sprintf("%v", secretElement)
59+
60+
sanitizedSecretName := strings.ReplaceAll(secretName, "_", "-")
61+
62+
azkvLog.Infof("Uploading Secret Name: %v, Sanitized: %v", secretName, sanitizedSecretName)
63+
64+
// Create a secret
65+
params := azsecrets.SetSecretParameters{Value: &secretValue}
66+
_, err = client.SetSecret(context.TODO(), sanitizedSecretName, params, nil)
67+
if err != nil {
68+
log.Fatalf("failed to create a secret %v: %v", secretName, err)
69+
}
70+
}
71+
72+
return nil
73+
}

0 commit comments

Comments
 (0)