mirror of
https://github.com/fluxcd/flux2.git
synced 2026-02-09 17:27:28 +00:00
Mask dockerconfigjson secret types and support StringData secrets
If implemented, flux diff kustomization will managed correctly sops managed dockerconfigjson secrets. Sops encrypted secret with stringData maps are supported too. Signed-off-by: Soule BA <soule@weave.works>
This commit is contained in:
parent
cf3f729f98
commit
2e9fd33ce5
19 changed files with 281 additions and 24 deletions
|
|
@ -79,6 +79,18 @@ func TestDiffKustomization(t *testing.T) {
|
|||
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
|
||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
|
||||
},
|
||||
{
|
||||
name: "diff with a sops dockerconfigjson secret object",
|
||||
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
|
||||
objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml",
|
||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"),
|
||||
},
|
||||
{
|
||||
name: "diff with a sops stringdata secret object",
|
||||
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
|
||||
objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml",
|
||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-stringdata-sops-secret.golden"),
|
||||
},
|
||||
}
|
||||
|
||||
tmpl := map[string]string{
|
||||
|
|
|
|||
|
|
@ -153,12 +153,18 @@ func NewRootFlags() rootFlags {
|
|||
func main() {
|
||||
log.SetFlags(0)
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
logger.Failuref("%v", err)
|
||||
|
||||
if err, ok := err.(*RequestError); ok {
|
||||
if err.StatusCode == 1 {
|
||||
logger.Warningf("%v", err)
|
||||
} else {
|
||||
logger.Failuref("%v", err)
|
||||
}
|
||||
|
||||
os.Exit(err.StatusCode)
|
||||
}
|
||||
|
||||
logger.Failuref("%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,31 @@ spec:
|
|||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
||||
name: docker-secret
|
||||
namespace: default
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
||||
name: secret-basic-auth-stringdata
|
||||
namespace: default
|
||||
stringData:
|
||||
password: KipTT1BTKio=
|
||||
username: KipTT1BTKio=
|
||||
type: kubernetes.io/basic-auth
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
token: KipTT1BTKio=
|
||||
kind: Secret
|
||||
|
|
|
|||
27
cmd/flux/testdata/build-kustomization/podinfo/dockerconfigjson-sops-secret.yaml
vendored
Normal file
27
cmd/flux/testdata/build-kustomization/podinfo/dockerconfigjson-sops-secret.yaml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: docker-secret
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eU1CTEJhVXZ4eEVYYkVV
|
||||
OU90TEcrR2pYckttN0pBanJoSUZWSW1RQXlRCkUydFJ3V1NZUTBuVFF0aC9GUEcw
|
||||
bUdhNjJWTkoyL1FUVi9Dc1dxUDBkM0UKLS0tIE1sQXkwcWdGaEFuY0RHQTVXM0J6
|
||||
dWpJcThEbW15V3dXYXpPZklBdW1Hd1kKoIAdmGNPrEctV8h1w8KuvQ5S+BGmgqN9
|
||||
MgpNmUhJjWhgcQpb5BRYpQesBOgU5TBGK7j58A6DMDKlSiYZsdQchQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2022-02-03T16:03:17Z"
|
||||
mac: ENC[AES256_GCM,data:AHdYSawajwgAFwlmDN1IPNmT9vWaYKzyVIra2d6sPcjTbZ8/p+VRSRpVm4XZFFsaNnW5AUJaouwXnKYDTmJDXKlr/rQcu9kXqsssQgdzcXaA6l5uJlgsnml8ba7J3OK+iEKMax23mwQEx2EUskCd9ENOwFDkunP02sxqDNOz20k=,iv:8F5OamHt3fAVorf6p+SoIrWoqkcATSGWVoM0EK87S4M=,tag:E1mxXnc7wWkEX5BxhpLtng==,type:str]
|
||||
pgp: []
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.7.1
|
||||
|
|
@ -4,6 +4,8 @@ resources:
|
|||
- ./deployment.yaml
|
||||
- ./hpa.yaml
|
||||
- ./service.yaml
|
||||
- ./dockerconfigjson-sops-secret.yaml
|
||||
- ./stringdata-secret.yaml
|
||||
secretGenerator:
|
||||
- files:
|
||||
- token=token.encrypted
|
||||
|
|
|
|||
28
cmd/flux/testdata/build-kustomization/podinfo/stringdata-secret.yaml
vendored
Normal file
28
cmd/flux/testdata/build-kustomization/podinfo/stringdata-secret.yaml
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-basic-auth-stringdata
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
username: ENC[AES256_GCM,data:uKiQR48=,iv:jh2lgyAVu7igJAgoJsnOGhjxFyvUAa9lvT21u3hhqpU=,tag:zXM2JEpk3ZEH7WfkcWXXkw==,type:str]
|
||||
password: ENC[AES256_GCM,data:PyhZmNhy929JGQ==,iv:PBqPaJmSw21+kn4gIlg5VdjLNZyf613z5RUTCesBoVw=,tag:Hjc7DsuUrtsz7PYPdNkL3g==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJd0xxbDZhYjVoZzY4YWhK
|
||||
d2NvMVgrSGRVUGhHRGg3R1FpVURnbmh1TDBzCjcwby85M3JaK09QVk0yZFNMb2NL
|
||||
c2NQZW5hS1FhYlBHU0VoUzBVYzZYUUUKLS0tIEdaNEw2Y0VjVHpZc3pyYUtLVmJk
|
||||
NmN3K2VLU0NiZ1d0VHBYbGlCM1lrNmMKeWz3yfFbMNE+ly21oLfc1XnDSPRmnlPP
|
||||
wIs8lk/qrzVZ45C9GdWnnPeGZZiia46Yop9TxseUS8gCjJ6KCxJCAg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2022-02-06T12:51:07Z"
|
||||
mac: ENC[AES256_GCM,data:jtdzwj19uxdxvnmXg1HkAkDA6XlKMJOYFy7uLI5t/t11LwGop5Yeo7a4nQEEELehRx9J7B6U6NiySxAxBxWx5uW5vI5c8+069VV6dkiCIefnYSzuoIhQafjlFl1/KvH7VEjIWfHYuXF09v9PEKXkxEHUYDpS3QqQ3ymHRRI08pU=, iv:xX3E7F+AM29Pm8G5oqxRfYu9E7tEBGIaHeCJYgrtFmc=,tag:MJPGusNvu05z939jg8PAwQ==,type:str]
|
||||
pgp: []
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.7.1
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
|
|
|
|||
6
cmd/flux/testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden
vendored
Normal file
6
cmd/flux/testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 drifted
|
||||
|
||||
data
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c drifted
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ spec.ports.http.port
|
|||
- 9899
|
||||
+ 9898
|
||||
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
|
|
|
|||
6
cmd/flux/testdata/diff-kustomization/diff-with-stringdata-sops-secret.golden
vendored
Normal file
6
cmd/flux/testdata/diff-kustomization/diff-with-stringdata-sops-secret.golden
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
11
cmd/flux/testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml
vendored
Normal file
11
cmd/flux/testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
||||
name: docker-secret
|
||||
namespace: default
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
► Deployment/default/podinfo created
|
||||
► HorizontalPodAutoscaler/default/podinfo created
|
||||
► Service/default/podinfo created
|
||||
► Secret/default/docker-secret created
|
||||
► Secret/default/secret-basic-auth-stringdata created
|
||||
► Secret/default/podinfo-token-77t89m9b67 created
|
||||
► Secret/default/db-user-pass-bkbd782d2c created
|
||||
|
|
|
|||
12
cmd/flux/testdata/diff-kustomization/stringdata-sops-secret.yaml
vendored
Normal file
12
cmd/flux/testdata/diff-kustomization/stringdata-sops-secret.yaml
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
||||
name: secret-basic-auth-stringdata
|
||||
namespace: default
|
||||
stringData:
|
||||
password: KipTT1BTKio=
|
||||
username: KipTT1BTKio=
|
||||
type: kubernetes.io/basic-auth
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -40,9 +41,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
controllerName = "kustomize-controller"
|
||||
controllerGroup = "kustomize.toolkit.fluxcd.io"
|
||||
mask = "**SOPS**"
|
||||
controllerName = "kustomize-controller"
|
||||
controllerGroup = "kustomize.toolkit.fluxcd.io"
|
||||
mask = "**SOPS**"
|
||||
dockercfgSecretType = "kubernetes.io/dockerconfigjson"
|
||||
typeField = "type"
|
||||
dataField = "data"
|
||||
stringDataField = "stringData"
|
||||
)
|
||||
|
||||
var defaultTimeout = 80 * time.Second
|
||||
|
|
@ -183,7 +188,7 @@ func (b *Builder) build() (m resmap.ResMap, err error) {
|
|||
}
|
||||
|
||||
// make sure secrets are masked
|
||||
err = trimSopsData(res)
|
||||
err = maskSopsData(res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -257,40 +262,131 @@ func (b *Builder) setOwnerLabels(res *resource.Resource) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func trimSopsData(res *resource.Resource) error {
|
||||
func maskSopsData(res *resource.Resource) error {
|
||||
// sopsMess is the base64 encoded mask
|
||||
sopsMess := base64.StdEncoding.EncodeToString([]byte(mask))
|
||||
|
||||
if res.GetKind() == "Secret" {
|
||||
// get both data and stringdata maps as a secret can have both
|
||||
dataMap := res.GetDataMap()
|
||||
stringDataMap := getStringDataMap(res)
|
||||
asYaml, err := res.AsYAML()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode secret %s data: %w", res.GetName(), err)
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
|
||||
//delete any sops data as we don't want to expose it
|
||||
// delete any sops data as we don't want to expose it
|
||||
// assume that both data and stringdata are encrypted
|
||||
if bytes.Contains(asYaml, []byte("sops:")) && bytes.Contains(asYaml, []byte("mac: ENC[")) {
|
||||
// delete the sops object
|
||||
res.PipeE(yaml.FieldClearer{Name: "sops"})
|
||||
for k := range dataMap {
|
||||
dataMap[k] = sopsMess
|
||||
|
||||
secretType, err := res.GetFieldValue(typeField)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
|
||||
} else {
|
||||
for k, v := range dataMap {
|
||||
data, err := base64.StdEncoding.DecodeString(v)
|
||||
if v, ok := secretType.(string); ok && v == dockercfgSecretType {
|
||||
// if the secret is a json docker config secret, we need to mask the data with a json object
|
||||
err := maskDockerconfigjsonSopsData(dataMap)
|
||||
if err != nil {
|
||||
if _, ok := err.(base64.CorruptInputError); ok {
|
||||
return fmt.Errorf("failed to decode secret %s data: %w", res.GetName(), err)
|
||||
}
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
|
||||
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
|
||||
err = maskDockerconfigjsonSopsData(stringDataMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
|
||||
} else {
|
||||
for k := range dataMap {
|
||||
dataMap[k] = sopsMess
|
||||
}
|
||||
|
||||
for k := range stringDataMap {
|
||||
stringDataMap[k] = sopsMess
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := maskBase64EncryptedSopsData(dataMap, sopsMess)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
|
||||
err = maskSopsDataInStringDataSecret(stringDataMap, sopsMess)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
}
|
||||
|
||||
// set the data and stringdata maps
|
||||
res.SetDataMap(dataMap)
|
||||
|
||||
if len(stringDataMap) > 0 {
|
||||
err = res.SetMapField(yaml.NewMapRNode(&stringDataMap), stringDataField)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStringDataMap(rn *resource.Resource) map[string]string {
|
||||
n, err := rn.Pipe(yaml.Lookup(stringDataField))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result := map[string]string{}
|
||||
_ = n.VisitFields(func(node *yaml.MapNode) error {
|
||||
result[yaml.GetValue(node.Key)] = yaml.GetValue(node.Value)
|
||||
return nil
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
func maskDockerconfigjsonSopsData(dataMap map[string]string) error {
|
||||
sopsMess := struct {
|
||||
Mask string `json:"mask"`
|
||||
}{
|
||||
Mask: mask,
|
||||
}
|
||||
|
||||
maskJson, err := json.Marshal(sopsMess)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k := range dataMap {
|
||||
dataMap[k] = base64.StdEncoding.EncodeToString(maskJson)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func maskBase64EncryptedSopsData(dataMap map[string]string, mask string) error {
|
||||
for k, v := range dataMap {
|
||||
data, err := base64.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
if _, ok := err.(base64.CorruptInputError); ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
|
||||
dataMap[k] = mask
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func maskSopsDataInStringDataSecret(stringDataMap map[string]string, mask string) error {
|
||||
for k, v := range stringDataMap {
|
||||
if bytes.Contains([]byte(v), []byte("sops")) && bytes.Contains([]byte(v), []byte("ENC[")) {
|
||||
stringDataMap[k] = mask
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ type: kubernetes.io/basic-auth
|
|||
name: "secret sops secret",
|
||||
yamlStr: `apiVersion: v1
|
||||
data:
|
||||
.dockercfg: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
|
||||
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret
|
||||
|
|
@ -125,7 +125,7 @@ sops:
|
|||
`,
|
||||
expected: `apiVersion: v1
|
||||
data:
|
||||
.dockercfg: KipTT1BTKio=
|
||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret
|
||||
|
|
@ -142,7 +142,7 @@ type: kubernetes.io/dockerconfigjson
|
|||
}
|
||||
|
||||
resource := &resource.Resource{RNode: *r}
|
||||
err = trimSopsData(resource)
|
||||
err = maskSopsData(resource)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to trim sops data: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,17 +199,31 @@ func diff(liveFile, mergedFile string, output io.Writer) error {
|
|||
}
|
||||
|
||||
func diffSopsSecret(obj, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
||||
data := obj.Object["data"]
|
||||
for _, v := range data.(map[string]interface{}) {
|
||||
// get both data and stringdata maps
|
||||
data := obj.Object[dataField]
|
||||
stringData := obj.Object[stringDataField]
|
||||
|
||||
if m, ok := data.(map[string]interface{}); ok && m != nil {
|
||||
applySopsDiff(m, liveObject, mergedObject, change)
|
||||
}
|
||||
|
||||
if m, ok := stringData.(map[string]interface{}); ok && m != nil {
|
||||
applySopsDiff(m, liveObject, mergedObject, change)
|
||||
}
|
||||
}
|
||||
|
||||
func applySopsDiff(data map[string]interface{}, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
||||
for _, v := range data {
|
||||
v, err := base64.StdEncoding.DecodeString(v.(string))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
if bytes.Contains(v, []byte(mask)) {
|
||||
if liveObject != nil && mergedObject != nil {
|
||||
change.Action = string(ssa.UnchangedAction)
|
||||
dataLive := liveObject.Object["data"].(map[string]interface{})
|
||||
dataMerged := mergedObject.Object["data"].(map[string]interface{})
|
||||
dataLive := liveObject.Object[dataField].(map[string]interface{})
|
||||
dataMerged := mergedObject.Object[dataField].(map[string]interface{})
|
||||
if cmp.Diff(keys(dataLive), keys(dataMerged)) != "" {
|
||||
change.Action = string(ssa.ConfiguredAction)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue