Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delimiter annotation #664

Merged
merged 6 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Changes:
* `k8s.io/utils` v0.0.0-20240502163921-fe8a2dddb1d0 => v0.0.0-20240711033017-18e509b52bc8
* `sigs.k8s.io/controller-runtime` v0.18.4 => v0.19.1

Features:
* Add annotations for customizing template delimiters [GH-664](https://github.com/hashicorp/vault-k8s/pull/664)

Bugs:
* Disable handling update on pods [GH-619](https://github.com/hashicorp/vault-k8s/pull/619)

Expand Down
6 changes: 6 additions & 0 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ type Secret struct {
// ErrMissingKey is used to control how the template behaves when attempting
// to index a struct or a map key that does not exist
ErrMissingKey bool

// LeftDelimiter is the optional left delimiter to use when rendering a templated secret
LeftDelimiter string

// RightDelimiter is the optional right delimiter to use when rendering a templated secret
RightDelimiter string
}

type Vault struct {
Expand Down
18 changes: 18 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ const (
// If not provided, the template content key annotation is used.
AnnotationAgentInjectTemplateFile = "vault.hashicorp.com/agent-inject-template-file"

// AnnotationAgentInjectTemplateLeftDelim is the key annotation that configures Vault
// Agent what left delimiter to use for rendering the secrets. The name
// of the template is any unique string after "vault.hashicorp.com/agent-template-left-delim-",
// such as "vault.hashicorp.com/agent-template-left-delim-foobar". This should map
// to the same unique value provided in "vault.hashicorp.com/agent-inject-secret-".
// If not provided, a default left delimiter is used as defined by https://www.vaultproject.io/docs/agent/template#left_delimiter
AnnotationAgentInjectTemplateLeftDelim = "vault.hashicorp.com/agent-template-left-delim"

// AnnotationAgentInjectTemplateRightDelim is the key annotation that configures Vault
// Agent what right delimiter to use for rendering the secrets. The name
// of the template is any unique string after "vault.hashicorp.com/agent-template-right-delim-",
// such as "vault.hashicorp.com/agent-template-right-delim-foobar". This should map
// to the same unique value provided in "vault.hashicorp.com/agent-inject-secret-".
// If not provided, a default right delimiter is used as defined by https://www.vaultproject.io/docs/agent/template#right_delimiter
AnnotationAgentInjectTemplateRightDelim = "vault.hashicorp.com/agent-template-right-delim"

// AnnotationAgentInjectToken is the annotation key for injecting the
// auto-auth token into the secrets volume (e.g. /vault/secrets/token)
AnnotationAgentInjectToken = "vault.hashicorp.com/agent-inject-token"
Expand Down Expand Up @@ -646,6 +662,8 @@ func (a *Agent) secrets() ([]*Secret, error) {
}
secret.MountPath = a.annotationsSecretValue(AnnotationVaultSecretVolumePath, secret.RawName, a.Annotations[AnnotationVaultSecretVolumePath])
secret.Command = a.annotationsSecretValue(AnnotationAgentInjectCommand, secret.RawName, "")
secret.LeftDelimiter = a.annotationsSecretValue(AnnotationAgentInjectTemplateLeftDelim, secret.RawName, "")
secret.RightDelimiter = a.annotationsSecretValue(AnnotationAgentInjectTemplateRightDelim, secret.RawName, "")
tvoran marked this conversation as resolved.
Show resolved Hide resolved
secret.FilePathAndName = a.annotationsSecretValue(AnnotationAgentInjectFile, secret.RawName, "")
secret.FilePermission = a.annotationsSecretValue(AnnotationAgentInjectFilePermission, secret.RawName, "")

Expand Down
116 changes: 92 additions & 24 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,39 +461,107 @@ func TestSecretMixedTemplatesAnnotations(t *testing.T) {

"vault.hashicorp.com/agent-inject-template-only-template": "onlyTemplate",
"vault.hashicorp.com/agent-inject-template-file-only-template-file": "onlyTemplateFile",

"vault.hashicorp.com/agent-inject-secret-barfoo": "test1",
"vault.hashicorp.com/agent-inject-template-barfoo": "",
"vault.hashicorp.com/agent-template-left-delim-barfoo": "${",
"vault.hashicorp.com/agent-template-right-delim-barfoo": "}",
"vault.hashicorp.com/agent-inject-template-file-barfoo": "/etc/config.tmpl",

"vault.hashicorp.com/agent-inject-secret-test3": "test3",
"vault.hashicorp.com/agent-inject-template-test3": "foobarTemplate3",
"vault.hashicorp.com/agent-inject-template-file-test3": "",
"vault.hashicorp.com/agent-template-left-delim-test3": "",
"vault.hashicorp.com/agent-template-right-delim-test3": "",

"vault.hashicorp.com/agent-inject-template-only-template-2": "onlyTemplate2",
"vault.hashicorp.com/agent-template-left-delim-only-template-2": "${",
"vault.hashicorp.com/agent-template-right-delim-only-template-2": "}",

"vault.hashicorp.com/agent-inject-template-file-only-template-file-2": "onlyTemplateFile2",
"vault.hashicorp.com/agent-template-left-delim-only-template-file-2": "${",
"vault.hashicorp.com/agent-template-right-delim-only-template-file-2": "}",
},
map[string]Secret{
"foobar": {
Name: "foobar",
RawName: "foobar",
Path: "test1",
Template: "",
TemplateFile: "/etc/config.tmpl",
MountPath: secretVolumePath,
Name: "foobar",
RawName: "foobar",
Path: "test1",
Template: "",
LeftDelimiter: "",
RightDelimiter: "",
TemplateFile: "/etc/config.tmpl",
MountPath: secretVolumePath,
},
"test2": {
Name: "test2",
RawName: "test2",
Path: "test2",
Template: "foobarTemplate",
TemplateFile: "",
MountPath: secretVolumePath,
Name: "test2",
RawName: "test2",
Path: "test2",
Template: "foobarTemplate",
LeftDelimiter: "",
RightDelimiter: "",
TemplateFile: "",
MountPath: secretVolumePath,
},
"only-template": {
Name: "only-template",
RawName: "only-template",
Path: "",
Template: "onlyTemplate",
TemplateFile: "",
MountPath: secretVolumePath,
Name: "only-template",
RawName: "only-template",
Path: "",
Template: "onlyTemplate",
LeftDelimiter: "",
RightDelimiter: "",
TemplateFile: "",
MountPath: secretVolumePath,
},
"only-template-file": {
Name: "only-template-file",
RawName: "only-template-file",
Path: "",
Template: "",
TemplateFile: "onlyTemplateFile",
MountPath: secretVolumePath,
Name: "only-template-file",
RawName: "only-template-file",
Path: "",
Template: "",
LeftDelimiter: "",
RightDelimiter: "",
TemplateFile: "onlyTemplateFile",
MountPath: secretVolumePath,
},
"barfoo": {
Name: "barfoo",
RawName: "barfoo",
Path: "test1",
Template: "",
LeftDelimiter: "${",
RightDelimiter: "}",
TemplateFile: "/etc/config.tmpl",
MountPath: secretVolumePath,
},
"test3": {
Name: "test3",
RawName: "test3",
Path: "test3",
Template: "foobarTemplate3",
LeftDelimiter: "",
RightDelimiter: "",
TemplateFile: "",
MountPath: secretVolumePath,
},
"only-template-2": {
Name: "only-template-2",
RawName: "only-template-2",
Path: "",
Template: "onlyTemplate2",
LeftDelimiter: "${",
RightDelimiter: "}",
TemplateFile: "",
MountPath: secretVolumePath,
},
"only-template-file-2": {
Name: "only-template-file-2",
RawName: "only-template-file-2",
Path: "",
Template: "",
LeftDelimiter: "${",
RightDelimiter: "}",
TemplateFile: "onlyTemplateFile2",
MountPath: secretVolumePath,
},
},
},
Expand Down
16 changes: 14 additions & 2 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
const (
DefaultMapTemplate = "{{ with secret \"%s\" }}{{ range $k, $v := .Data }}{{ $k }}: {{ $v }}\n{{ end }}{{ end }}"
DefaultJSONTemplate = "{{ with secret \"%s\" }}{{ .Data | toJSON }}\n{{ end }}"
DefaultLeftDelim = "{{"
DefaultRightDelim = "}}"
DefaultTemplateType = "map"
PidFile = "/home/vault/.pid"
TokenFile = "/home/vault/.vault-token"
Expand Down Expand Up @@ -195,6 +197,16 @@ func (a *Agent) newTemplateConfigs() []*Template {
}
}

leftDelim := secret.LeftDelimiter
if leftDelim == "" {
leftDelim = DefaultLeftDelim
}

rightDelim := secret.RightDelimiter
if rightDelim == "" {
rightDelim = DefaultRightDelim
}

filePathAndName := fmt.Sprintf("%s/%s", secret.MountPath, secret.Name)
if secret.FilePathAndName != "" {
filePathAndName = filepath.Join(secret.MountPath, secret.FilePathAndName)
Expand All @@ -204,8 +216,8 @@ func (a *Agent) newTemplateConfigs() []*Template {
Source: templateFile,
Contents: template,
Destination: filePathAndName,
LeftDelim: "{{",
RightDelim: "}}",
LeftDelim: leftDelim,
RightDelim: rightDelim,
Command: secret.Command,
ErrMissingKey: secret.ErrMissingKey,
}
Expand Down
29 changes: 21 additions & 8 deletions agent-inject/agent/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func TestNewConfig(t *testing.T) {

"vault.hashicorp.com/agent-inject-command-bar": "pkill -HUP app",

"vault.hashicorp.com/agent-inject-secret-baz": "db/creds/baz",
"vault.hashicorp.com/agent-inject-template-baz": `[[ with secret "db/creds/baz" ]][[ range $k, $v := .Data ]][[ $k ]]: [[ $v ]]\n[[ end ]][[ end ]]`,
"vault.hashicorp.com/agent-template-left-delim-baz": "[[",
"vault.hashicorp.com/agent-template-right-delim-baz": "]]",

AnnotationAgentCacheEnable: "true",
}

Expand Down Expand Up @@ -121,8 +126,8 @@ func TestNewConfig(t *testing.T) {
t.Error("agent Cache should be disabled for init containers")
}

if len(config.Templates) != 6 {
t.Errorf("expected 4 template, got %d", len(config.Templates))
if len(config.Templates) != 7 {
t.Errorf("expected 7 templates, got %d", len(config.Templates))
}

for _, template := range config.Templates {
Expand All @@ -134,6 +139,10 @@ func TestNewConfig(t *testing.T) {
if template.Contents != "template foo" {
t.Errorf("expected template contents to be %s, got %s", "template foo", template.Contents)
}

if template.LeftDelim != DefaultLeftDelim || template.RightDelim != DefaultRightDelim {
t.Errorf("expected default delimiters to be %s (left) and %s (right), got %s (left) and %s (right)", DefaultLeftDelim, DefaultRightDelim, template.LeftDelim, template.RightDelim)
}
} else if strings.Contains(template.Destination, "bar") {
if template.Destination != "/vault/secrets/bar" {
t.Errorf("expected template destination to be %s, got %s", "/vault/secrets/bar", template.Destination)
Expand Down Expand Up @@ -170,6 +179,10 @@ func TestNewConfig(t *testing.T) {
if template.Destination != "/vault/secrets/just-template-file" {
t.Errorf("expected template destination to be %s, got %s", "/vault/secrets/just-template-file", template.Destination)
}
} else if strings.Contains(template.Destination, "baz") {
if template.LeftDelim != "[[" || template.RightDelim != "]]" {
t.Errorf("expected default delimiters to be %s (left) and %s (right), got %s (left) and %s (right)", "[[", "]]", template.LeftDelim, template.RightDelim)
}
} else {
t.Error("shouldn't have got here")
}
Expand Down Expand Up @@ -627,7 +640,7 @@ func TestConfigVaultAgentTemplateConfig(t *testing.T) {
AnnotationTemplateConfigExitOnRetryFailure: "true",
},
&TemplateConfig{
ExitOnRetryFailure: true,
ExitOnRetryFailure: true,
MaxConnectionsPerHost: 0,
},
},
Expand All @@ -637,7 +650,7 @@ func TestConfigVaultAgentTemplateConfig(t *testing.T) {
AnnotationTemplateConfigExitOnRetryFailure: "false",
},
&TemplateConfig{
ExitOnRetryFailure: false,
ExitOnRetryFailure: false,
MaxConnectionsPerHost: 0,
},
},
Expand All @@ -647,9 +660,9 @@ func TestConfigVaultAgentTemplateConfig(t *testing.T) {
AnnotationTemplateConfigStaticSecretRenderInterval: "10s",
},
&TemplateConfig{
ExitOnRetryFailure: true,
ExitOnRetryFailure: true,
StaticSecretRenderInterval: "10s",
MaxConnectionsPerHost: 0,
MaxConnectionsPerHost: 0,
},
},
{
Expand All @@ -658,15 +671,15 @@ func TestConfigVaultAgentTemplateConfig(t *testing.T) {
AnnotationTemplateConfigMaxConnectionsPerHost: "100",
},
&TemplateConfig{
ExitOnRetryFailure: true,
ExitOnRetryFailure: true,
MaxConnectionsPerHost: 100,
},
},
{
"template_config_empty",
map[string]string{},
&TemplateConfig{
ExitOnRetryFailure: true,
ExitOnRetryFailure: true,
MaxConnectionsPerHost: 0,
},
},
Expand Down