Skip to content

Commit cb7448c

Browse files
Merge pull request #30 from vimeo/gsm-default-latest
Google Secret Manager: Default to Latest Version
2 parents cb5e603 + 7cfb330 commit cb7448c

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ mappings:
3030
- sourceType: gsm
3131
path: projects/my-project/secrets/my-secret/versions/latest
3232
secretName: my-secret
33+
- sourceType: gsm
34+
path: projects/my-project/secrets/my-other-secret
35+
secretName: defaults-to-latest-version
3336
```
3437
3538
### Labels and Reconciliation
@@ -87,6 +90,8 @@ Google Secret Manager's API simply returns arbitrary bytes as the value of a sec
8790

8891
In cases where `gsmEncoding` is not set to json, the key's value will default to the name of the secret (`secretName` in the mapping). If you would like to override this, set `gsmSecretKeyValue` to your preferred key.
8992

93+
Also, Google Secret Manager Secrets have versions which can be specified in the configuration mapping's `Path`. If you do not specify a specific version (with the `/versions/...` suffix), `/versions/latest` will automatically be appended to the path.
94+
9095
## Return Values
9196
The application will return 0 on success (when all keys were copied/updated successfully). A complete list of all possible return values follows:
9297

config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package pentagon
33
import (
44
"fmt"
55
"log"
6+
"path"
7+
"regexp"
68

79
"github.com/hashicorp/vault/api"
810
"github.com/vimeo/pentagon/vault"
@@ -29,8 +31,15 @@ const (
2931

3032
// GSM encoded as json
3133
GSMEncodingTypeJSON = "json"
34+
35+
// when a version isn't specified, just default to the latest
36+
gsmLatestSuffix = "/versions/latest"
3237
)
3338

39+
// regex to match the version suffix at the end of a GSM secret path. Note that
40+
// this can be a version number, or a version alias.
41+
var gsmVersionSuffix = regexp.MustCompile(`/versions/[\w-]+$`)
42+
3443
// Config describes the configuration for Pentagon.
3544
type Config struct {
3645
// Vault is the configuration used to connect to vault.
@@ -88,6 +97,10 @@ func (c *Config) SetDefaults() {
8897
if m.SecretType == "" {
8998
c.Mappings[i].SecretType = corev1.SecretTypeOpaque
9099
}
100+
101+
if m.SourceType == GSMSourceType && !gsmVersionSuffix.MatchString(m.Path) {
102+
c.Mappings[i].Path = path.Join(m.Path, gsmLatestSuffix)
103+
}
91104
}
92105
}
93106

config_test.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ func TestSetDefaults(t *testing.T) {
2020
VaultPath: "path",
2121
SecretName: "theSecret",
2222
},
23+
{
24+
SourceType: GSMSourceType,
25+
Path: "projects/my-project/secrets/my-secret/versions/latest",
26+
SecretName: "latestSecret",
27+
},
28+
{
29+
SourceType: GSMSourceType,
30+
Path: "projects/my-project/secrets/my-secret/versions/3",
31+
SecretName: "3secret",
32+
},
33+
{
34+
SourceType: GSMSourceType,
35+
Path: "projects/my-project/secrets/my-secret/versions/prod-alias",
36+
SecretName: "prodAliasSecret",
37+
},
38+
{
39+
SourceType: GSMSourceType,
40+
Path: "projects/my-project/secrets/my-secret",
41+
SecretName: "noVersionSecret",
42+
},
43+
{
44+
SourceType: GSMSourceType,
45+
Path: "projects/my-project/secrets/my-secret/",
46+
SecretName: "noVersionSecretWithTrailingSlash",
47+
},
2348
},
2449
}
2550

@@ -36,10 +61,19 @@ func TestSetDefaults(t *testing.T) {
3661
t.Fatalf("unexpected default engine type: %s", c.Vault.DefaultEngineType)
3762
}
3863

64+
if c.Mappings[0].SourceType != VaultSourceType {
65+
t.Fatalf("source type should have defaulted to vault: %+v", c.Mappings[0].SourceType)
66+
}
67+
68+
if c.Mappings[1].SourceType != VaultSourceType {
69+
t.Fatalf("source type should have defaulted to vault: %+v", c.Mappings[1].SourceType)
70+
}
71+
72+
if c.Mappings[0].Path != "path" {
73+
t.Fatalf("path should be unchanged, is %s", c.Mappings[0].Path)
74+
}
75+
3976
for _, m := range c.Mappings {
40-
if m.SourceType != VaultSourceType {
41-
t.Fatalf("source type should have defaulted to vault: %+v", m)
42-
}
4377
if m.Path == "" {
4478
t.Fatalf("empty path for vault secret: %+v", m)
4579
}
@@ -50,6 +84,26 @@ func TestSetDefaults(t *testing.T) {
5084
t.Fatalf("empty Kubernetes secret type for mapping: %+v", m)
5185
}
5286
}
87+
88+
if c.Mappings[2].Path != "projects/my-project/secrets/my-secret/versions/latest" {
89+
t.Fatalf("latest GSM path should be unchanged, is %s", c.Mappings[2].Path)
90+
}
91+
92+
if c.Mappings[3].Path != "projects/my-project/secrets/my-secret/versions/3" {
93+
t.Fatalf("versioned GSM path should be unchanged, is %s", c.Mappings[3].Path)
94+
}
95+
96+
if c.Mappings[4].Path != "projects/my-project/secrets/my-secret/versions/prod-alias" {
97+
t.Fatalf("aliased GSM path should be unchanged, is %s", c.Mappings[4].Path)
98+
}
99+
100+
if c.Mappings[5].Path != "projects/my-project/secrets/my-secret/versions/latest" {
101+
t.Fatalf("GSM path without version should have latest suffix, is %s", c.Mappings[5].Path)
102+
}
103+
104+
if c.Mappings[6].Path != "projects/my-project/secrets/my-secret/versions/latest" {
105+
t.Fatalf("GSM path without version (but with trailing slash) should have latest suffix, is %s", c.Mappings[6].Path)
106+
}
53107
}
54108

55109
func TestNoClobber(t *testing.T) {

0 commit comments

Comments
 (0)