/
kubeseal.go
137 lines (123 loc) · 4.51 KB
/
kubeseal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package sealer
import (
"encoding/json"
"fmt"
"os"
"os/exec"
ssv1alpha1 "github.com/bitnami-labs/sealed-secrets/pkg/apis/sealed-secrets/v1alpha1"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
)
func Unseal(sealedSecretYAML []byte, sealedSecretsControllerNamespace string) (secretYAML []byte, err error) {
// create and open a temporary file
f, err := os.CreateTemp("", "kubectl-sealer-")
if err != nil {
return nil, fmt.Errorf("error creating temporary file: %v", err)
}
// close and remove the temporary file at the end of the program
defer f.Close()
defer os.Remove(f.Name())
// get sealing keys
kubectlCommandArgs := []string{
"get", "secret",
"-l", "sealedsecrets.bitnami.com/sealed-secrets-key",
"-n", sealedSecretsControllerNamespace,
"-o", "yaml",
}
kubectlCommand := exec.Command("kubectl", kubectlCommandArgs...)
sealingKeysYAML, err := kubectlCommand.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error invoking kubectl as %v: %v: %s", kubectlCommand.Args, err, sealingKeysYAML)
}
// store sealing keys into temporary file
_, err = f.Write(sealingKeysYAML)
if err != nil {
return nil, fmt.Errorf("error writing sealing keys to temporary file: %v", err)
}
// unseal
kubesealCommandArgs := []string{
"--recovery-unseal",
"--recovery-private-key", f.Name(),
}
kubesealCommand := exec.Command("kubeseal", kubesealCommandArgs...)
kubesealCommandStdin, _ := kubesealCommand.StdinPipe()
_, err = kubesealCommandStdin.Write(sealedSecretYAML)
if err != nil {
return nil, fmt.Errorf("error passing sealing keys as input to kubeseal: %v", err)
}
kubesealCommandStdin.Close()
secretJSON, err := kubesealCommand.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error invoking kubeseal as %v: %v: %s", kubesealCommand.Args, err, secretJSON)
}
// build struct
var secret corev1.Secret
if err := json.Unmarshal(secretJSON, &secret); err != nil {
return nil, fmt.Errorf("error unmarshalling json to kubernetes Secret: %v", err)
}
// convert .data to .StringData with base64 decoding values
secret.StringData = map[string]string{}
for k, v := range secret.Data {
secret.StringData[k] = string(v)
}
// we don't need this anymore
secret.Data = nil
// delete metadata.ownerReference
secret.ObjectMeta.OwnerReferences = nil
// generate YAML from struct
secretYAML, err = yaml.Marshal(secret)
if err != nil {
return nil, fmt.Errorf("error marshalling kubernetes Secret to YAML: %v", err)
}
return secretYAML, nil
}
func Seal(secretYAML []byte, allowEmptyData bool) (sealedSecretYAML []byte, err error) {
kubesealCommandArgs := []string{
"-o", "yaml",
}
if allowEmptyData {
kubesealCommandArgs = append(kubesealCommandArgs, "--allow-empty-data")
}
kubesealCommand := exec.Command("kubeseal", kubesealCommandArgs...)
kubesealCommandStdin, _ := kubesealCommand.StdinPipe()
_, err = kubesealCommandStdin.Write(secretYAML)
if err != nil {
return nil, fmt.Errorf("error passing sealing keys as input to kubeseal: %v", err)
}
kubesealCommandStdin.Close()
sealedSecretYAML, err = kubesealCommand.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error invoking kubeseal as %v: %v: %s", kubesealCommand.Args, err, sealedSecretYAML)
}
return sealedSecretYAML, nil
}
func EncryptRaw(value []byte, secret corev1.Secret) (encryptedValue []byte, err error) {
kubesealCommandArgs := []string{
"--raw",
"--from-file", "/dev/stdin",
}
scope := ssv1alpha1.SecretScope(&secret)
switch scope {
case ssv1alpha1.StrictScope:
kubesealCommandArgs = append(kubesealCommandArgs, "--scope", "strict")
kubesealCommandArgs = append(kubesealCommandArgs, "--name", secret.Name)
kubesealCommandArgs = append(kubesealCommandArgs, "--namespace", secret.Namespace)
case ssv1alpha1.NamespaceWideScope:
kubesealCommandArgs = append(kubesealCommandArgs, "--scope", "namespace-wide")
kubesealCommandArgs = append(kubesealCommandArgs, "--namespace", secret.Namespace)
case ssv1alpha1.ClusterWideScope:
kubesealCommandArgs = append(kubesealCommandArgs, "--scope", "cluster-wide")
}
kubesealCommand := exec.Command("kubeseal", kubesealCommandArgs...)
kubesealCommandStdin, _ := kubesealCommand.StdinPipe()
_, err = kubesealCommandStdin.Write(value)
if err != nil {
return nil, fmt.Errorf("error passing sealing keys as input to kubeseal: %v", err)
}
kubesealCommandStdin.Close()
encryptedValue, err = kubesealCommand.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error invoking kubeseal as %v: %v: %s", kubesealCommand.Args, err, encryptedValue)
}
return encryptedValue, nil
}