decryptor: detect format of Secret data field

This checks the base64 decoded bytes from a Secret field for any of the
marker bytes, thereby allowing data to be encrypted into any format.
Instead of the previous behavior which assumed it to either be YAML or
JSON.

Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
Hidde Beydals 2022-04-29 11:26:34 +02:00
parent a7639c68d3
commit 36df540a5d
2 changed files with 45 additions and 6 deletions

View File

@ -67,12 +67,16 @@ const (
// DecryptionAzureAuthFile is the name of the file containing the Azure
// credentials.
DecryptionAzureAuthFile = "sops.azure-kv"
)
var (
// maxEncryptedFileSize is the max allowed file size in bytes of an encrypted
// file.
maxEncryptedFileSize int64 = 5 << 20
// unsupportedFormat is used to signal no sopsFormatToMarkerBytes format was
// detected by detectFormatFromMarkerBytes.
unsupportedFormat = formats.Format(-1)
)
var (
// sopsFormatToString is the counterpart to
// https://github.com/mozilla/sops/blob/v3.7.2/cmd/sops/formats/formats.go#L16
sopsFormatToString = map[formats.Format]string{
@ -334,9 +338,9 @@ func (d *KustomizeDecryptor) DecryptResource(res *resource.Resource) (*resource.
continue
}
if bytes.Contains(data, sopsFormatToMarkerBytes[formats.Yaml]) || bytes.Contains(data, sopsFormatToMarkerBytes[formats.Json]) {
if inF := detectFormatFromMarkerBytes(data); inF != unsupportedFormat {
outF := formatForPath(key)
out, err := d.SopsDecryptWithFormat(data, formats.Yaml, outF)
out, err := d.SopsDecryptWithFormat(data, inF, outF)
if err != nil {
return nil, fmt.Errorf("failed to decrypt and format '%s/%s' Secret field '%s': %w",
res.GetNamespace(), res.GetName(), key, err)
@ -412,7 +416,7 @@ func (d *KustomizeDecryptor) decryptKustomizationEnvSources(visited map[string]s
}
for _, envFile := range gen.EnvSources {
format := formatForPath(envFile)
if formatForPath(envFile) == formats.Binary {
if format == formats.Binary {
// Default to dotenv
format = formats.Dotenv
}
@ -740,3 +744,12 @@ func formatForPath(path string) formats.Format {
return formats.FormatForPath(path)
}
}
func detectFormatFromMarkerBytes(b []byte) formats.Format {
for k, v := range sopsFormatToMarkerBytes {
if bytes.Contains(b, v) {
return k
}
}
return unsupportedFormat
}

View File

@ -846,7 +846,7 @@ func TestKustomizeDecryptor_DecryptResource(t *testing.T) {
"name": "secret",
"namespace": "test",
},
"type": corev1.SecretTypeDockercfg,
"type": corev1.SecretTypeDockerConfigJson,
"data": map[string]interface{}{
corev1.DockerConfigJsonKey: base64.StdEncoding.EncodeToString(encData),
},
@ -1725,3 +1725,29 @@ func Test_formatForPath(t *testing.T) {
})
}
}
func Test_detectFormatFromMarkerBytes(t *testing.T) {
tests := []struct {
name string
b []byte
want formats.Format
}{
{
name: "detects format",
b: bytes.Join([][]byte{[]byte("random other bytes"), sopsFormatToMarkerBytes[formats.Yaml], []byte("more random bytes")}, []byte(" ")),
want: formats.Yaml,
},
{
name: "returns unsupported format",
b: []byte("no marker bytes present"),
want: unsupportedFormat,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := detectFormatFromMarkerBytes(tt.b); got != tt.want {
t.Errorf("detectFormatFromMarkerBytes() = %v, want %v", got, tt.want)
}
})
}
}