Skip to content

Commit

Permalink
This fixes a bug with age encryption when specifying multiple age rec…
Browse files Browse the repository at this point in the history
…ipients

I encountered an issue when I tried so specify multiple age recipients
in the .sops.yaml config file of my repository.

I tried running `sops --age 'agePubKey1,agePubKey2' -e -i values.secret.yaml`
which produced an appropriate file with two entries in the `/sops/age/-`
part of the encrypted yaml file.

However, I then continued to set multiple recipients in my .sops.yaml
file to simplify handling:

```yaml
creation_rules:
  - encrypted_regex: '^(data|stringData|spec)$'
    age: 'agePubKey1,agePubKey2'
```

However, this resulted in encryption only being done for the first
specified agePubKey, not the second or third one.

After digging a bit trough the code, I think this should fix it.

I verified the fix locally on my machine and got it working. Also adding
some unit tests and extending the repository examples so they can be
decrypted using the age keys provided in `age/keys.txt`

Signed-off-by: Cedric Kienzler <github@cedric-kienzler.de>
  • Loading branch information
cedi committed Mar 20, 2022
1 parent 86f500d commit 7ebee3d
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 14 deletions.
3 changes: 3 additions & 0 deletions age/keys.txt
@@ -1,3 +1,6 @@
# created: 2020-07-18T03:16:47-07:00
# public key: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw
AGE-SECRET-KEY-1NJT5YCS2LWU4V4QAJQ6R4JNU7LXPDX602DZ9NUFANVU5GDTGUWCQ5T59M6
# created: 2021-12-12T01:39:30+01:00
# public key: age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep
AGE-SECRET-KEY-1T0Z66WSXS6RMNCPSL7P2E8N4Q7SUD8VMG9ND27S08JL7Y2XAU9EQECHDS7
37 changes: 27 additions & 10 deletions age/keysource_test.go
Expand Up @@ -31,26 +31,43 @@ func TestMasterKeyFromRecipientWithLeadingAndTrailingSpaces(t *testing.T) {
assert.Equal(key.Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
}

func TestMasterKeysFromRecipientsWithMultiple(t *testing.T) {
assert := assert.New(t)

keys, err := MasterKeysFromRecipients("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

assert.NoError(err)

assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")
}

func TestAge(t *testing.T) {
assert := assert.New(t)

key, err := MasterKeyFromRecipient("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
keys, err := MasterKeysFromRecipients("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw,age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

assert.NoError(err)
assert.Equal("age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw", key.ToString())
assert.Equal(len(keys), 2)
assert.Equal(keys[0].Recipient, "age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw")
assert.Equal(keys[1].Recipient, "age1tmaae3ld5vpevmsh5yacsauzx8jetg300mpvc4ugp5zr5l6ssq9sla97ep")

dataKey := []byte("abcdefghijklmnopqrstuvwxyz123456")

err = key.Encrypt(dataKey)
assert.NoError(err)
for _, key := range keys {
err = key.Encrypt(dataKey)
assert.NoError(err)

_, filename, _, _ := runtime.Caller(0)
err = os.Setenv(SopsAgeKeyFileEnv, path.Join(path.Dir(filename), "keys.txt"))
assert.NoError(err)
_, filename, _, _ := runtime.Caller(0)
err = os.Setenv("SOPS_AGE_KEY_FILE", path.Join(path.Dir(filename), "keys.txt"))
assert.NoError(err)

decryptedKey, err := key.Decrypt()
assert.NoError(err)
assert.Equal(dataKey, decryptedKey)
}

decryptedKey, err := key.Decrypt()
assert.NoError(err)
assert.Equal(dataKey, decryptedKey)
}

func TestAgeDotEnv(t *testing.T) {
Expand Down
6 changes: 4 additions & 2 deletions cmd/sops/main.go
Expand Up @@ -442,12 +442,14 @@ func main() {
group = append(group, k)
}
for _, recipient := range ageRecipients {
k, err := age.MasterKeyFromRecipient(recipient)
keys, err := age.MasterKeysFromRecipients(recipient)
if err != nil {
log.WithError(err).Error("Failed to add key")
continue
}
group = append(group, k)
for _, key := range keys {
group = append(group, key)
}
}
return groups.Add(groups.AddOpts{
InputPath: c.String("file"),
Expand Down
6 changes: 4 additions & 2 deletions config/config.go
Expand Up @@ -153,11 +153,13 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
for _, group := range cRule.KeyGroups {
var keyGroup sops.KeyGroup
for _, k := range group.Age {
key, err := age.MasterKeyFromRecipient(k)
keys, err := age.MasterKeysFromRecipients(k)
if err != nil {
return nil, err
}
keyGroup = append(keyGroup, key)
for _, key := range keys {
keyGroup = append(keyGroup, key)
}
}
for _, k := range group.PGP {
keyGroup = append(keyGroup, pgp.NewMasterKeyFromFingerprint(k))
Expand Down

0 comments on commit 7ebee3d

Please sign in to comment.