-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsealedsecret.go
126 lines (115 loc) · 3.59 KB
/
sealedsecret.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
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"strings"
"time"
"gopkg.in/yaml.v3"
)
type SealedSecret struct {
Environment string `json:"-" yaml:"-"`
ApiVersion string `json:"apiVersion" yaml:"apiVersion"`
Kind string `json:"kind" yaml:"kind"`
Metadata map[string]*string `json:"metadata" yaml:"metadata"`
Spec struct {
EncryptedData map[string]string `json:"encryptedData,omitempty" yaml:"encryptedData,omitempty"`
Template struct {
Data *map[string]*string `json:"data" yaml:"data"`
Metadata map[string]*string `json:"metadata" yaml:"metadata"`
} `json:"template" yaml:"template"`
} `json:"spec" yaml:"spec"`
}
func createSealedSecrets(secretYAML string, certFilename string) (sealedSecrets map[string]string, err error) {
ctx, timeout := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer timeout()
cmd := exec.CommandContext(ctx, "kubeseal", "-o", "json", "--cert", certFilename)
var stdout, stderr bytes.Buffer
stdin, err := cmd.StdinPipe()
if err != nil {
return
}
io.WriteString(stdin, secretYAML)
stdin.Close()
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return
}
if strings.TrimSpace(stderr.String()) != "" {
err = fmt.Errorf("%s", stderr.String())
}
var sealedSecret SealedSecret
err = json.Unmarshal(stdout.Bytes(), &sealedSecret)
if err != nil {
return
}
return sealedSecret.Spec.EncryptedData, nil
}
const firstLineTemplate = "{{- if eq .Values.environment \"%s\" }}"
const lastLineTemplate = `{{- end }}`
func (s *SealedSecret) Init(name string, namespace string) {
s.ApiVersion = "bitnami.com/v1alpha1"
s.Kind = "SealedSecret"
s.Metadata = map[string]*string{
"name": &name,
"namespace": &namespace,
}
s.Spec.Template.Metadata = s.Metadata
}
func sealedSecretFromTemplate(filename string, environment string, template string) (sealedSecret SealedSecret, err error) {
expectFirstLine := fmt.Sprintf(firstLineTemplate, environment)
const expectLastLine = lastLineTemplate
template = strings.TrimSpace(template)
lines := strings.Split(template, "\n")
if len(lines) < 3 {
err = fmt.Errorf("template file %s needs to contain at least 3 lines", filename)
return
}
firstLine := strings.TrimSpace(lines[0])
lastLine := strings.TrimSpace(lines[len(lines)-1])
manifestLines := bytes.Buffer{}
i := 0
for _, line := range lines {
i++
if i == 1 || i == len(lines) {
continue
}
manifestLines.WriteString(line)
manifestLines.WriteString("\n")
}
if firstLine != expectFirstLine {
err = fmt.Errorf("first line of template (%s) not in expected format.\nExpected:\n%s\nGot:\n%s", filename, expectFirstLine, firstLine)
return
}
if lastLine != expectLastLine {
err = fmt.Errorf("last line of template (%s) not in expected format.\nExpected:\n%s\nGot:\n%s", filename, expectLastLine, lastLine)
return
}
err = yaml.Unmarshal(manifestLines.Bytes(), &sealedSecret)
if err != nil {
err = fmt.Errorf("template (with first and last line removed) does not contain valid YAML (%s):\n%s", err, manifestLines.String())
return
}
sealedSecret.Environment = environment
return
}
func (ss *SealedSecret) ToTemplate(f *os.File, environment string) (out bytes.Buffer, err error) {
template, err := yaml.Marshal(ss)
if err != nil {
return
}
f.Truncate(0)
f.Seek(0, io.SeekStart)
for _, writer := range []io.StringWriter{f, &out} {
writer.WriteString(fmt.Sprintf(firstLineTemplate+"\n", environment))
writer.WriteString(string(template))
writer.WriteString(fmt.Sprintf(lastLineTemplate + "\n"))
}
return
}