Skip to content

Commit 02a8304

Browse files
committed
Resolves #1864. Adds Native List as an option for configuring keys in addition to the trailing comma option already given.
Signed-off-by: Lucas Earl <[email protected]>
1 parent a4a1266 commit 02a8304

File tree

2 files changed

+115
-23
lines changed

2 files changed

+115
-23
lines changed

config/config.go

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -170,23 +170,78 @@ type destinationRule struct {
170170
}
171171

172172
type creationRule struct {
173-
PathRegex string `yaml:"path_regex"`
174-
KMS string
175-
AwsProfile string `yaml:"aws_profile"`
176-
Age string `yaml:"age"`
177-
PGP string
178-
GCPKMS string `yaml:"gcp_kms"`
179-
AzureKeyVault string `yaml:"azure_keyvault"`
180-
VaultURI string `yaml:"hc_vault_transit_uri"`
181-
KeyGroups []keyGroup `yaml:"key_groups"`
182-
ShamirThreshold int `yaml:"shamir_threshold"`
183-
UnencryptedSuffix string `yaml:"unencrypted_suffix"`
184-
EncryptedSuffix string `yaml:"encrypted_suffix"`
185-
UnencryptedRegex string `yaml:"unencrypted_regex"`
186-
EncryptedRegex string `yaml:"encrypted_regex"`
187-
UnencryptedCommentRegex string `yaml:"unencrypted_comment_regex"`
188-
EncryptedCommentRegex string `yaml:"encrypted_comment_regex"`
189-
MACOnlyEncrypted bool `yaml:"mac_only_encrypted"`
173+
PathRegex string `yaml:"path_regex"`
174+
KMS interface{} `yaml:"kms"` // string or []string
175+
AwsProfile string `yaml:"aws_profile"`
176+
Age interface{} `yaml:"age"` // string or []string
177+
PGP interface{} `yaml:"pgp"` // string or []string
178+
GCPKMS interface{} `yaml:"gcp_kms"` // string or []string
179+
AzureKeyVault interface{} `yaml:"azure_keyvault"` // string or []string
180+
VaultURI interface{} `yaml:"hc_vault_transit_uri"` // string or []string
181+
KeyGroups []keyGroup `yaml:"key_groups"`
182+
ShamirThreshold int `yaml:"shamir_threshold"`
183+
UnencryptedSuffix string `yaml:"unencrypted_suffix"`
184+
EncryptedSuffix string `yaml:"encrypted_suffix"`
185+
UnencryptedRegex string `yaml:"unencrypted_regex"`
186+
EncryptedRegex string `yaml:"encrypted_regex"`
187+
UnencryptedCommentRegex string `yaml:"unencrypted_comment_regex"`
188+
EncryptedCommentRegex string `yaml:"encrypted_comment_regex"`
189+
MACOnlyEncrypted bool `yaml:"mac_only_encrypted"`
190+
}
191+
192+
// Helper methods to safely extract keys as []string
193+
func (c *creationRule) GetKMSKeys() []string {
194+
return parseKeyField(c.KMS)
195+
}
196+
197+
func (c *creationRule) GetAgeKeys() []string {
198+
return parseKeyField(c.Age)
199+
}
200+
201+
func (c *creationRule) GetPGPKeys() []string {
202+
return parseKeyField(c.PGP)
203+
}
204+
205+
func (c *creationRule) GetGCPKMSKeys() []string {
206+
return parseKeyField(c.GCPKMS)
207+
}
208+
209+
func (c *creationRule) GetAzureKeyVaultKeys() []string {
210+
return parseKeyField(c.AzureKeyVault)
211+
}
212+
213+
func (c *creationRule) GetVaultURIs() []string {
214+
return parseKeyField(c.VaultURI)
215+
}
216+
217+
// Utility function to handle both string and []string
218+
func parseKeyField(field interface{}) []string {
219+
switch v := field.(type) {
220+
case string:
221+
if v == "" {
222+
return []string{}
223+
}
224+
// Existing CSV parsing logic
225+
keys := strings.Split(v, ",")
226+
result := make([]string, 0, len(keys))
227+
for _, key := range keys {
228+
trimmed := strings.TrimSpace(key)
229+
if trimmed != "" { // Skip empty strings (fixes trailing comma issue)
230+
result = append(result, trimmed)
231+
}
232+
}
233+
return result
234+
case []interface{}:
235+
result := make([]string, len(v))
236+
for i, item := range v {
237+
result[i] = fmt.Sprintf("%v", item)
238+
}
239+
return result
240+
case []string:
241+
return v
242+
default:
243+
return []string{}
244+
}
190245
}
191246

192247
func NewStoresConfig() *StoresConfig {
@@ -292,7 +347,7 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
292347
} else {
293348
var keyGroup sops.KeyGroup
294349
if cRule.Age != "" {
295-
ageKeys, err := age.MasterKeysFromRecipients(cRule.Age)
350+
ageKeys, err := age.MasterKeysFromRecipients(strings.Join(cRule.GetAgeKeys(), ","))
296351
if err != nil {
297352
return nil, err
298353
} else {
@@ -301,23 +356,23 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
301356
}
302357
}
303358
}
304-
for _, k := range pgp.MasterKeysFromFingerprintString(cRule.PGP) {
359+
for _, k := range pgp.MasterKeysFromFingerprintString(strings.Join(cRule.GetPGPKeys(), ",")) {
305360
keyGroup = append(keyGroup, k)
306361
}
307-
for _, k := range kms.MasterKeysFromArnString(cRule.KMS, kmsEncryptionContext, cRule.AwsProfile) {
362+
for _, k := range kms.MasterKeysFromArnString(strings.Join(cRule.GetKMSKeys(), ","), kmsEncryptionContext, cRule.AwsProfile) {
308363
keyGroup = append(keyGroup, k)
309364
}
310-
for _, k := range gcpkms.MasterKeysFromResourceIDString(cRule.GCPKMS) {
365+
for _, k := range gcpkms.MasterKeysFromResourceIDString(strings.Join(cRule.GetGCPKMSKeys(), ",")) {
311366
keyGroup = append(keyGroup, k)
312367
}
313-
azureKeys, err := azkv.MasterKeysFromURLs(cRule.AzureKeyVault)
368+
azureKeys, err := azkv.MasterKeysFromURLs(strings.Join(cRule.GetAzureKeyVaultKeys(), ","))
314369
if err != nil {
315370
return nil, err
316371
}
317372
for _, k := range azureKeys {
318373
keyGroup = append(keyGroup, k)
319374
}
320-
vaultKeys, err := hcvault.NewMasterKeysFromURIs(cRule.VaultURI)
375+
vaultKeys, err := hcvault.NewMasterKeysFromURIs(strings.Join(cRule.GetVaultURIs(), ","))
321376
if err != nil {
322377
return nil, err
323378
}

config/config_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,3 +718,40 @@ func TestLoadConfigFileWithVaultDestinationRules(t *testing.T) {
718718
assert.NotNil(t, conf.Destination)
719719
assert.Contains(t, conf.Destination.Path("barfoo"), "/v1/kv/barfoo/barfoo")
720720
}
721+
722+
func TestCreationRuleNativeKeyLists(t *testing.T) {
723+
var sampleConfigWithNativeKeyLists = []byte(`
724+
creation_rules:
725+
- path_regex: native_list*
726+
pgp:
727+
- "85D77543B3D624B63CEA9E6DBC17301B491B3F21" # [email protected]
728+
- "FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4" # server_XYZ
729+
kms:
730+
- "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
731+
age:
732+
- "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
733+
gcp_kms:
734+
- "projects/test-project/locations/global/keyRings/test-ring/cryptoKeys/test-key"
735+
hc_vault_transit_uri:
736+
- "https://vault.example.com:8200/v1/transit/keys/key1"
737+
`)
738+
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithNativeKeyLists, t), "/conf/path", "native_list_test", nil)
739+
assert.Nil(t, err)
740+
if conf == nil {
741+
t.Fatal("Expected configuration but got nil")
742+
}
743+
744+
assert.True(t, len(conf.KeyGroups) > 0)
745+
assert.True(t, len(conf.KeyGroups[0]) == 6)
746+
747+
keyTypeCounts := make(map[string]int)
748+
for _, key := range conf.KeyGroups[0] {
749+
keyTypeCounts[key.TypeToIdentifier()]++
750+
}
751+
752+
assert.Equal(t, 2, keyTypeCounts["pgp"])
753+
assert.Equal(t, 1, keyTypeCounts["kms"])
754+
assert.Equal(t, 1, keyTypeCounts["age"])
755+
assert.Equal(t, 1, keyTypeCounts["gcp_kms"])
756+
assert.Equal(t, 1, keyTypeCounts["hc_vault"])
757+
}

0 commit comments

Comments
 (0)