mirror of
https://github.com/helmfile/helmfile.git
synced 2026-09-30 17:10:08 +02:00
Add helm-secrets-encrypted values template file (#1701)
Secret files ending with .gotmpl are now also rendered as a gotemplate.
```
releases:
- name: myapp
secrets:
- secrets.yaml.gotmpl
```
Note that currently, .gotmpl files must be valid YAML files as well.
The expected use-case of this feature is to compose a YAML array from values and encrypted secrets.
Without this feature, you would have tried to do something like the below, which didn't work.
**Example (doesn't work!)**
`values.yaml.gotmpl`:
```
environment:
- name: MY_EXTERNAL_IP
value: |
{{ exec "./get-external-ip.sh" (list "") }}
```
`secrets.yaml`:
```
_sops:
#...
environment:
- name: MY_SECRET_VALUE
value: (encrypted by sops)
```
`helmfile.yaml`:
```
releases:
- name: foo
values:
- values.yaml
secrets:
- secrets.yaml
```
This doesn't work because `values.yaml` and the decrypted `secrets.yaml` are passed to `helm` to be merged, and helm overrides the array instead of merging or concatenating the arrays.
**Example (works!)**
Instead of `values.yaml` and `secrets.yaml`, you provide a single `secrets.yaml.gotmpl` that is a valid YAML and encrypted by sops:
```
_sops:
#...
environment:
- name: MY_EXTERNAL_IP
value: |
{{ exec "./get-external-ip.sh" (list "") }}
- name: MY_SECRET_VALUE
value: (encrypted by sops)
```
`helmfile.yaml`:
```
releases:
- name: foo
secrets:
- secrets.yaml.gotmpl
```
Helmfile decrypts the gotmpl by handing it over to helm-secrets and then renders the result as a gotmpl file. The end result is that you have a two-element array `environments` that can be just passed to helm.
Resolves #1700
Co-authored-by: Yusuke Kuoka <ykuoka@gmail.com>
This commit is contained in:
co-authored by
Yusuke Kuoka
parent
a161796dc4
commit
85accf7330
+11
-2
@@ -278,7 +278,14 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||
if len(decSuffix) == 0 {
|
||||
decSuffix = ".yaml.dec"
|
||||
}
|
||||
decFilename := strings.Replace(absPath, ".yaml", decSuffix, 1)
|
||||
|
||||
// helm secrets replaces the extension with its suffix ONLY when the extension is ".yaml"
|
||||
var decFilename string
|
||||
if strings.HasSuffix(absPath, ".yaml") {
|
||||
decFilename = strings.Replace(absPath, ".yaml", decSuffix, 1)
|
||||
} else {
|
||||
decFilename = absPath + decSuffix
|
||||
}
|
||||
|
||||
secretBytes, err := ioutil.ReadFile(decFilename)
|
||||
if err != nil {
|
||||
@@ -308,7 +315,9 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
|
||||
|
||||
if tempFile == nil {
|
||||
tempFile = func(content []byte) (string, error) {
|
||||
tmpFile, err := ioutil.TempFile("", "secret")
|
||||
dir := filepath.Dir(name)
|
||||
extension := filepath.Ext(name)
|
||||
tmpFile, err := ioutil.TempFile(dir, "secret*"+extension)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -289,6 +289,29 @@ Found secret in cache %s/secretName
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DecryptSecretWithGotmpl(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
helm := MockExecer(logger, "dev")
|
||||
|
||||
tmpFilePath := "path/to/temp/file"
|
||||
helm.writeTempFile = func(content []byte) (string, error) {
|
||||
return tmpFilePath, nil
|
||||
}
|
||||
|
||||
secretName := "secretName.yaml.gotmpl"
|
||||
_, decryptErr := helm.DecryptSecret(HelmContext{}, secretName)
|
||||
cwd, err := filepath.Abs(".")
|
||||
if err != nil {
|
||||
t.Errorf("Error: %v", err)
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf(`%s/%s.yaml.dec`, cwd, secretName)
|
||||
if d := cmp.Diff(expected, decryptErr.(*os.PathError).Path); d != "" {
|
||||
t.Errorf("helmexec.DecryptSecret(): want (-), got (+):\n%s", d)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DiffRelease(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
logger := NewLogger(&buffer, "debug")
|
||||
|
||||
Reference in New Issue
Block a user