Skip to content
This repository was archived by the owner on Nov 1, 2022. It is now read-only.

Sops support #2580

Merged
merged 4 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add unit tests of sops decryption
add tests, that verify that a set of pre-encrypted files can be imported
and automatically decrypted with sops

Signed-off-by: Paul Farver <[email protected]>
  • Loading branch information
PaulFarver committed Dec 11, 2019
commit 25ab417f7baf80031f482f2949d139ccde6f9aa2
37 changes: 37 additions & 0 deletions pkg/cluster/kubernetes/resource/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package resource

import (
"bytes"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/stretchr/testify/assert"

"github.com/fluxcd/flux/pkg/cluster/kubernetes/testfiles"
"github.com/fluxcd/flux/pkg/gpg/gpgtest"
"github.com/fluxcd/flux/pkg/resource"
)

Expand Down Expand Up @@ -325,3 +327,38 @@ func TestChartTracker(t *testing.T) {
}

}

func TestLoadSomeWithSopsNoneEncrypted(t *testing.T) {
dir, cleanup := testfiles.TempDir(t)
defer cleanup()
if err := testfiles.WriteTestFiles(dir); err != nil {
t.Fatal(err)
}
objs, err := Load(dir, []string{dir}, true)
if err != nil {
t.Error(err)
}
if len(objs) != len(testfiles.ResourceMap) {
t.Errorf("expected %d objects from %d files, got result:\n%#v", len(testfiles.ResourceMap), len(testfiles.Files), objs)
}
}

func TestLoadSomeWithSopsAllEncrypted(t *testing.T) {
gpgHome, gpgCleanup := gpgtest.ImportGPGKey(t, testfiles.TestPrivateKey)
defer gpgCleanup()
os.Setenv("GNUPGHOME", gpgHome)
defer os.Unsetenv("GNUPGHOME")

dir, cleanup := testfiles.TempDir(t)
defer cleanup()
if err := testfiles.WriteSopsEncryptedTestFiles(dir); err != nil {
t.Fatal(err)
}
objs, err := Load(dir, []string{dir}, true)
if err != nil {
t.Error(err)
}
for expected := range testfiles.EncryptedResourceMap {
assert.NotNil(t, objs[expected.String()], "expected to find %s in manifest map after decryption", expected)
}
}
163 changes: 162 additions & 1 deletion pkg/cluster/kubernetes/testfiles/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ func TempDir(t *testing.T) (string, func()) {

// WriteTestFiles ... given a directory, create files in it, based on predetermined file content
func WriteTestFiles(dir string) error {
for name, content := range Files {
return writeFiles(dir, Files)
}

// WriteSopsEncryptedTestFiles ... given a directory, create files in it, based on predetermined file content.
// These files are encrypted with sops using TestPrivateKey
func WriteSopsEncryptedTestFiles(dir string) error {
return writeFiles(dir, SopsEncryptedFiles)
}

func writeFiles(dir string, files map[string]string) error {
for name, content := range files {
path := filepath.Join(dir, name)
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
return err
Expand Down Expand Up @@ -347,3 +357,154 @@ spec:
- containerPort: 8080
`,
}

var SopsEncryptedFiles = map[string]string{
"garbage": "This should just be ignored, since it is not YAML",
"helloworld-deploy.yaml": `apiVersion: ENC[AES256_GCM,data:N/68Js00AtWIvks/pt+be5AW,iv:9Ke36D3faRNrMzm82Z9ETl3lOMhhWy8fh907K5e2Ar4=,tag:EfAzs1AQvLRH/tIQ+iZttw==,type:str]
kind: ENC[AES256_GCM,data:nLQbX7tJ0toD8A==,iv:0YTwaHF/2ltg+0ZBJnVVwGpqC3hwetUEp7VqsTmG/dc=,tag:UwzBg+T6341hwFNE72rY1w==,type:str]
metadata:
name: ENC[AES256_GCM,data:1crujILtUO9ytA==,iv:M/ITcPrW08mPnAdhMR1lkHe+MV43nGmB7VZbg7ATE/8=,tag:wMgBuHXhsLyoiFjzuNyD5A==,type:str]
spec:
minReadySeconds: ENC[AES256_GCM,data:Gw==,iv:wpm9BoT6zoJK1D7FfAOUZRqqSt0vuRVZkKYTUFUwuGs=,tag:u1m4qb7KImqotaXqaJsc6g==,type:int]
replicas: ENC[AES256_GCM,data:5Q==,iv:1SgpuA3jpf/Zw7+ITPww0sSi0LDYI/b+MGvdfshFwQk=,tag:94tHbVYNISMd4V9+VJCQ1A==,type:int]
template:
metadata:
labels:
name: ENC[AES256_GCM,data:so45IhmDRm+Fig==,iv:10uaiK6rpy+vcrSC7gtuI92l3D/Zihsh1gUHPNaVxok=,tag:Ebg7aGnYo10gST02+uKOuQ==,type:str]
spec:
containers:
- name: ENC[AES256_GCM,data:o//iDf99xA==,iv:yuxcUqVo+rq83MCsxhcSOaNzHBNiTBVJkyBxjFuk/SE=,tag:iieWOQKPGYWyb+9ghEgmuw==,type:str]
image: ENC[AES256_GCM,data:1ebh8sBwMl+7p1q0fk2FMoZ0BS6phtce+U2tftHIdzOOFwYQFPmsCnw/7LQ=,iv:QyDkmXqp9h1KJWVCBfqGxPrGcVBhzo64ZBvcV38IYls=,tag:jblN9ZU/pfkWQqK0he+jyQ==,type:str]
args:
- ENC[AES256_GCM,data:ny9R+PJtel8d,iv:mzsX/5JoK58pDvTpt0BM4hac1bcm41RbiVcr2Zuj7gw=,tag:d61S57ziH6B/L6icOnxvgw==,type:str]
ports:
- containerPort: ENC[AES256_GCM,data:7PA=,iv:CrWgn0+5qFYtHZE4FvnFRo3D2sedD4W7GRWHYc3kXU0=,tag:xkFX+yT4NaZRjvKchypWvg==,type:int]
- name: ENC[AES256_GCM,data:jyAYi3UjxQ==,iv:A4yZeV7Paf8OPccs3UOzBzJUV1s2NUOdmz9XJZcV/yk=,tag:lKNkPY6OqZtI+SMhj7JR5w==,type:str]
image: ENC[AES256_GCM,data:s0oEdBYDCG/eCsujJwHYi63q6zrc/GpKe4/OKUx4ZJEH,iv:JPgMUJfH622MpzgnNfjyXOnuuzvv3ybhpxtiU2xlO9s=,tag:KTZ7vJRhieeaBGu4ggtTrA==,type:str]
args:
- ENC[AES256_GCM,data:eVhs9FqWUX0OAbo=,iv:1+KSjflXnEZZc/ykA7B1+xHxknd+8SJKlqsHiH53UQU=,tag:EvzWHtsopeunX8w2im4aIg==,type:str]
ports:
- containerPort: ENC[AES256_GCM,data:9zbcIA==,iv:Pm+m/RchBryI1QkLs79Yih7SzhDq0l/SJMq3TIuT4hc=,tag:Ez3o8n5P1JrhN15MwjQ2WA==,type:int]
sops:
kms: []
gcp_kms: []
azure_kv: []
lastmodified: '2019-11-29T12:11:15Z'
mac: ENC[AES256_GCM,data:E3f6Q0F0vdXCLhQ0CIKTLk1UmEGr94xqVThsMXqXXZaKAllcy8cduIAPA1WqKkFyu2dAFumgzBvRa69pbClk2h/K1AAnBAbErHN9H7cQVCCxNZmclS7IHBMunoiaRiY+7Oey5agwFfJskAgibXrf23ePcWLO+xfWw9dIG7Y83OE=,iv:D+2mgEqXxA7x0Drqn+2j1xY8Avb8OVfgB30o3wDJB4k=,tag:1S/zCcM9vIIxQ2CGfl9Cyw==,type:str]
pgp:
- created_at: '2019-11-29T12:11:13Z'
enc: |
-----BEGIN PGP MESSAGE-----

hIwDVtT8p6MQvmgBA/9uGrPbdNPT1ajHjZ0/TQXLn4eH8vHtM6qfSgVLXtO5sT8/
t5panOKVZc7TqYWMER2yA8rHb7kzfPd7rNbJYmV7UgZfz8MtMMbHqUQrwWvoI+OU
u521j38G/PdyNCYsF3EAuUXLzUR2ka9O1qLnepM6/fwJvipQJuNvpWfNcaQkjtJe
AaNqL5jlmK63nQbXtbOBhCBJVP1j6821aBbIGdI8W2ryaS9ZFhKI7KAcU1spB3eG
oQRWo/i6CZ6GxNX+BC2FCdN7v72/MUaq1iBt+eHWMJmpItZO8J2UHkFcXwLnQQ==
=5S7f
-----END PGP MESSAGE-----
fp: 56D4FCA7A310BE68
unencrypted_suffix: _unencrypted
version: 3.5.0
`,"multi.yaml": `apiVersion: ENC[AES256_GCM,data:8yqGSWgi16xjFnNa,iv:xMZAis2SzZuK88p2+vQ1sgGrNDtxTSzKetqUQ1XX1TY=,tag:8W3UsUzuvt8BKblVh4EVjg==,type:str]
kind: ENC[AES256_GCM,data:HEzLbU4MwuXioQ==,iv:Y6kFrsqekf6fC7/cLdPhCiVcq8T8LiBoZsG9F2WjB6Q=,tag:CLlUTvzxfo2PWcb/sV4qgw==,type:str]
metadata:
annotations:
flux.weave.works/automated: ENC[AES256_GCM,data:E+LmLg==,iv:h0SVx9ZPDXe/MmBATqPq0OEhAddpCG6S59nmCzbJ5GQ=,tag:/Bj2utiV3y37bsFPLU6ITQ==,type:str]
name: ENC[AES256_GCM,data:8vXvzZyuySNCvDQG,iv:J/mJkH3WKkORVLAskIXjsb+hagHpWdyAYbyW1SbEPYU=,tag:B/xYXClFHV/nsp3LWC9MGg==,type:str]
spec:
replicas: ENC[AES256_GCM,data:Ww==,iv:0s+8Y0mjmWtu51gvT20edS8tLJeJOmPryTPdBmhShas=,tag:+7kf94hvGkJ3/A2LKSofFw==,type:int]
template:
metadata:
labels:
app: ENC[AES256_GCM,data:Gwrkpeug8TUv,iv:RFieExWfC9SEIL20FqLU3EtjQ4NB0smHGIrNwtloqCA=,tag:BjZhh/Yq94qxmV0dWijClQ==,type:str]
spec:
containers:
- name: ENC[AES256_GCM,data:bqH/S7g=,iv:ZSRqaUA4I9JzYoNHystJhJmwPGWbRuTVC33kr1Mf9Rw=,tag:P1KpeBXPe4zaDfFEsLFsKA==,type:str]
image: ENC[AES256_GCM,data:wzR31BZNM4yqRl5SufFUlDaee3cBeNm8BHvcZg5lBJlC+mlT78ICa08+qkI=,iv:tGXMno8BVZ3wRCM5pvWvxWNUb3H4KTUilKHgy9V8pmE=,tag:VkdplBRDMsMTCWryOQoc2A==,type:str]
imagePullPolicy: ENC[AES256_GCM,data:sGhJjMQN,iv:bEuucUaoCT0SSZ2qhHpFJNjpekUldxug8hfsaoUcvnk=,tag:nIbjalYAyJogStP8f12ecg==,type:str]
ports:
- containerPort: ENC[AES256_GCM,data:P4w=,iv:VsEBrStHzce907EbAL8CLbSBFaekwu8N59qrBxUSWf0=,tag:9LcQlzSKCSB9pVDEdycJSQ==,type:int]
sops:
kms: []
gcp_kms: []
azure_kv: []
lastmodified: '2019-11-29T13:10:50Z'
mac: ENC[AES256_GCM,data:n2LtRfzJm14Lh5NPPWMH6lQw7vLDEjAOiAwqLwiQJYBYXF84yRERnNtC+pEYNrFBJmc3IrKTePVwDWkRAX/9c3b3yWi65jqQg1dxYnVg828osOe1RG6EkBIxCnM/f31DFw1gxHIGPJtNevjmEep/xAS37iEkdFQ8aJol0yLTKac=,iv:07lpkLYonPuL8gDn0O+7c/ccws7eaYzU7ONjxas+US4=,tag:WKEpV3ulK7+YyUnnm2m9pw==,type:str]
pgp:
- created_at: '2019-11-29T13:10:50Z'
enc: |
-----BEGIN PGP MESSAGE-----

hIwDVtT8p6MQvmgBBACu6Eg1bFkdm/SaLa2trlVDiNVZ5v19xo/TwSAUP/K3CmlT
UH1K65aWXF3YaD9hmXX9AS3FnmtHKTt/yLsBpFttA3k4N/4z8Itr6DbLyg0a8xo3
zbhzJX6udTq6RcLTChUKR3HFPYMs1WtYw/9vKUrDxvosYBlH/wyX11d8Pzh919Je
AY6ZKtw+V3lk8QQosJ6hHofOirdY9WVfgXxIEUeDA6olKp4skMo6yba79RprpSNJ
kMqasq4FZlOZDzNl4qSyoeba5awb7jvsAQ51a/v6dNyW479U4HR7XC1qgGqvgA==
=++AZ
-----END PGP MESSAGE-----
fp: 56D4FCA7A310BE68
unencrypted_suffix: _unencrypted
version: 3.5.0
---
apiVersion: ENC[AES256_GCM,data:V5o=,iv:8a6VgSPy9PkenvXxWwL6/YU3T00+5HVt9t27EE1kgJc=,tag:Lhk+lmVrQ28ff4oYX5RPNQ==,type:str]
kind: ENC[AES256_GCM,data:v221CKuSFg==,iv:p2aNIff3rIBnRxc1YTiPbgaUUJSeTijNqP7zy60OlsA=,tag:5CvdmVgenVkzvCm7upvivA==,type:str]
metadata:
name: ENC[AES256_GCM,data:69PoFQWEW7GcRQzkgw==,iv:At0BENGgFgzySF2Yg6hlpoIBaVerY4V9SrYO0uNDqPk=,tag:nNS0Epk0+dFXhRKfdtLEGQ==,type:str]
spec:
type: ENC[AES256_GCM,data:Wf6waA7KilM=,iv:LfltJfrrb69L8vUhJ5nCtqqr36v0FEJQ1WpA//Hu2xo=,tag:k7xGKs9wDghNCnXQ8Kel+Q==,type:str]
ports:
- port: ENC[AES256_GCM,data:s38=,iv:xOAzQJv2KML98XH+soFAe+s2riff1V/JRSXCNb6Ra/o=,tag:dA7ZdxcuTNRUh6kTBVEqDw==,type:int]
protocol: ENC[AES256_GCM,data:M299,iv:gh8Wl/umwcN9qVnfkZKUGO43OI97eI40tsLJChhUzzc=,tag:GBAkrQQpQqDIlczlfgVGPA==,type:str]
selector:
app: ENC[AES256_GCM,data:C2XEHwHfxzde,iv:ak87axygw1vVIOaF0KS2XWUdA4NLg33loAkmqCU4Vw0=,tag:tHeFtLMRWSvh4fjO96vxIg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
lastmodified: '2019-11-29T13:10:50Z'
mac: ENC[AES256_GCM,data:n2LtRfzJm14Lh5NPPWMH6lQw7vLDEjAOiAwqLwiQJYBYXF84yRERnNtC+pEYNrFBJmc3IrKTePVwDWkRAX/9c3b3yWi65jqQg1dxYnVg828osOe1RG6EkBIxCnM/f31DFw1gxHIGPJtNevjmEep/xAS37iEkdFQ8aJol0yLTKac=,iv:07lpkLYonPuL8gDn0O+7c/ccws7eaYzU7ONjxas+US4=,tag:WKEpV3ulK7+YyUnnm2m9pw==,type:str]
pgp:
- created_at: '2019-11-29T13:10:50Z'
enc: |
-----BEGIN PGP MESSAGE-----

hIwDVtT8p6MQvmgBBACu6Eg1bFkdm/SaLa2trlVDiNVZ5v19xo/TwSAUP/K3CmlT
UH1K65aWXF3YaD9hmXX9AS3FnmtHKTt/yLsBpFttA3k4N/4z8Itr6DbLyg0a8xo3
zbhzJX6udTq6RcLTChUKR3HFPYMs1WtYw/9vKUrDxvosYBlH/wyX11d8Pzh919Je
AY6ZKtw+V3lk8QQosJ6hHofOirdY9WVfgXxIEUeDA6olKp4skMo6yba79RprpSNJ
kMqasq4FZlOZDzNl4qSyoeba5awb7jvsAQ51a/v6dNyW479U4HR7XC1qgGqvgA==
=++AZ
-----END PGP MESSAGE-----
fp: 56D4FCA7A310BE68
unencrypted_suffix: _unencrypted
version: 3.5.0
`,
}

var EncryptedResourceMap = map[resource.ID]string{
resource.MustParseID("<cluster>:deployment/helloworld"): "helloworld-deploy.yaml",
resource.MustParseID("<cluster>:deployment/multi-deploy"): "multi.yaml",
resource.MustParseID("<cluster>:service/multi-service"): "multi.yaml",
}

var TestPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

lQHYBF3hCAwBBADCAXKG8FGitaQhsfWCQv0N+f2ESEoRu7GXaXO97NvTg0RyJThM
8PFXLsGeSOBERTnQcAYqpirSGBsPItU0ZtkjMsKJcIehgJzyXIOGOuiBYOjRAg5f
o5YA+nvdfWT3SDKepPnsMBVLSMqHy1tbeiFj9JWB3nQ1hKxqSBJJWyT/nwARAQAB
AAP+M61RBXKkPDQoKTWPEQipAX0Ss5bR7BFUB+H2C6Q5FglERSd27L/NeYyh1HjT
DDxoXwZIDjo+88GqC4kaw5+VvNxz/Cr6vhMxaeYR/GEz7EJ9ojMQZS4RIs3dRcIY
tqQ1K6XvHwdn86AF8fDr89spEie/XT+ipe4g7K+E8KFDP7ECAM99XnKqDAoI5jy3
kdKqt5oFjhNDy7sPH/aPg2K1VqHCh1eVOv8lysS35WClh+JXF29T6Cfuq0OdnOrQ
exFwiKcCAO9dCGX8Ti3zt8ftlrZXMfZ9mKbeDH0THlP56FhyShJMfMtlHjM5OHRU
TZWEjoVfX+joxujHXHW4dbFZcWY6uEkB/0ac+jxJTxjkTMOZYPtWah0N+/o1aPSk
x2GR6Oc/Po6bB5ZqX1GWsHeQgay65I1Zf/E8PMHeIrhadvy+d7464duhCrQXRmx1
eCA8Zmx1eEB3ZWF2ZS53b3Jrcz6IzgQTAQgAOBYhBPGqhmR86rD1iqdGPVbU/Kej
EL5oBQJd4QgMAhsvBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFbU/KejEL5o
PUoEAJ11Tambrn9ypClTGnaaNrXd3V4PAOUSOoVESPymDY0QBtfC98BnHwbWAb/t
wQfsXhWC8aRYBv2W5/oXA7XDbtFyElqcsI5IJ0z5sWipnhSNrkqS3KqUidTnNnXx
56TSgLfWNbzngwqfNaFXhPvEjay/UYOJPZzfa4jZpR8iFOdY
=5y9F
-----END PGP PRIVATE KEY BLOCK-----
`
24 changes: 24 additions & 0 deletions pkg/gpg/gpgtest/gpg.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,30 @@ import (
"github.com/fluxcd/flux/pkg/cluster/kubernetes/testfiles"
)

// ImportGPGKey imports a gpg key into a temporary home directory. It returns
// the gpg home directory and a cleanup function to be called after the caller
// is finished with this key.
func ImportGPGKey(t *testing.T, key string) (string, func()){
newDir, cleanup := testfiles.TempDir(t)

cmd := exec.Command("gpg", "--homedir", newDir, "--import", "--")

stdin, err := cmd.StdinPipe()
if err != nil {
cleanup()
t.Fatal(err)
}
io.WriteString(stdin, key)
stdin.Close()

if err := cmd.Run(); err != nil {
cleanup()
t.Fatal(err)
}

return newDir, cleanup
}

// GPGKey creates a new, temporary GPG home directory and a public/private key
// pair. It returns the GPG home directory, the ID of the created key, and a
// cleanup function to be called after the caller is finished with this key.
Expand Down