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

Add annotation to use template path on disk #222

Merged
merged 1 commit into from
Apr 5, 2021
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 agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ type Secret struct {
// Template is the optional custom template to use when rendering the secret.
Template string

// Template file is the optional path on disk to the custom template to use when rendering the secret.
TemplateFile string

// Mount Path for the volume holding the rendered secret file
MountPath string

Expand Down
15 changes: 15 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ const (
// If not provided, a default generic template is used.
AnnotationAgentInjectTemplate = "vault.hashicorp.com/agent-inject-template"

// AnnotationAgentInjectTemplateFile is the optional key annotation that configures Vault
// Agent what template on disk to use for rendering the secrets. The name
// of the template is any unique string after "vault.hashicorp.com/agent-inject-template-file-",
// such as "vault.hashicorp.com/agent-inject-template-file-foobar". This should map
// to the same unique value provided in "vault.hashicorp.com/agent-inject-secret-".
// The value is the filename and path of the template used by the agent to render the secrets.
// If not provided, the template content key annotation is used.
AnnotationAgentInjectTemplateFile = "vault.hashicorp.com/agent-inject-template-file"

// AnnotationAgentInjectToken is the annotation key for injecting the token
// from auth/token/lookup-self
AnnotationAgentInjectToken = "vault.hashicorp.com/agent-inject-token"
Expand Down Expand Up @@ -379,6 +388,12 @@ func (a *Agent) secrets() []*Secret {
if val, ok := a.Annotations[templateName]; ok {
s.Template = val
}
if s.Template == "" {
templateFileAnnotation := fmt.Sprintf("%s-%s", AnnotationAgentInjectTemplateFile, raw)
if val, ok := a.Annotations[templateFileAnnotation]; ok {
s.TemplateFile = val
}
}

s.MountPath = a.Annotations[AnnotationVaultSecretVolumePath]
mountPathAnnotationName := fmt.Sprintf("%s-%s", AnnotationVaultSecretVolumePath, raw)
Expand Down
131 changes: 131 additions & 0 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,137 @@ func TestTemplateShortcuts(t *testing.T) {
}
}

func TestSecretMixedTemplatesAnnotations(t *testing.T) {
tests := []struct {
annotations map[string]string
expectedSecrets map[string]Secret
}{
{
map[string]string{
"vault.hashicorp.com/agent-inject-secret-foobar": "test1",
"vault.hashicorp.com/agent-inject-template-foobar": "",
"vault.hashicorp.com/agent-inject-template-file-foobar": "/etc/config.tmpl",
"vault.hashicorp.com/agent-inject-secret-test2": "test2",
"vault.hashicorp.com/agent-inject-template-test2": "foobarTemplate",
"vault.hashicorp.com/agent-inject-template-file-test2": "",
},
map[string]Secret{
"foobar": Secret{
Name: "foobar",
Path: "test1",
Template: "",
TemplateFile: "/etc/config.tmpl",
MountPath: secretVolumePath,
},
"test2": Secret{
Name: "test2",
Path: "test2",
Template: "foobarTemplate",
TemplateFile: "",
MountPath: secretVolumePath,
},
},
},
}
for _, tt := range tests {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

var patches []*jsonpatch.JsonPatchOperation

agent, err := New(pod, patches)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

if len(agent.Secrets) != len(tt.expectedSecrets) {
t.Errorf("agent Secrets length was %d, expected %d", len(agent.Secrets), len(tt.expectedSecrets))
}

for _, s := range agent.Secrets {
if s == nil {
t.Error("Got a nil agent Secret")
t.FailNow()
}
expectedSecret, found := tt.expectedSecrets[s.Name]
if !found {
t.Errorf("Unexpected agent secret name %q", s.Name)
t.FailNow()
}
if !reflect.DeepEqual(expectedSecret, *s) {
t.Errorf("expected secret %+v, got agent secret %+v", expectedSecret, *s)
}
}
}
}

func TestSecretTemplateFileAnnotations(t *testing.T) {
tests := []struct {
annotations map[string]string
expectedKey string
expectedTemplate string
expectedTemplateFile string
}{
{
map[string]string{
jasonodonnell marked this conversation as resolved.
Show resolved Hide resolved
"vault.hashicorp.com/agent-inject-secret-foobar": "test1",
"vault.hashicorp.com/agent-inject-template-foobar": "foobarTemplate",
"vault.hashicorp.com/agent-inject-template-file-foobar": "/etc/config.tmpl",
}, "foobar", "foobarTemplate", "",
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-secret-foobar": "test1",
"vault.hashicorp.com/agent-inject-template-foobar": "",
"vault.hashicorp.com/agent-inject-template-file-foobar": "/etc/config.tmpl",
}, "foobar", "", "/etc/config.tmpl",
},
}

for _, tt := range tests {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

agent, err := New(pod, patches)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

if len(agent.Secrets) == 0 {
t.Error("Secrets length was zero, it shouldn't have been")
}

if agent.Secrets[0].Name != tt.expectedKey {
t.Errorf("expected name %s, got %s", tt.expectedKey, agent.Secrets[0].Name)
}

if agent.Secrets[0].Template != tt.expectedTemplate {
t.Errorf("expected template %s, got %s", tt.expectedTemplate, agent.Secrets[0].Template)
}

if agent.Secrets[0].TemplateFile != tt.expectedTemplateFile {
t.Errorf("expected template file path %s, got %s", tt.expectedTemplateFile, agent.Secrets[0].TemplateFile)
}

}
}

func TestSecretCommandAnnotations(t *testing.T) {
tests := []struct {
annotations map[string]string
Expand Down
12 changes: 9 additions & 3 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ type Sink struct {
type Template struct {
CreateDestDirs bool `json:"create_dest_dirs,omitempty"`
Destination string `json:"destination"`
Contents string `json:"contents"`
Contents string `json:"contents,omitempty"`
LeftDelim string `json:"left_delimiter,omitempty"`
RightDelim string `json:"right_delimiter,omitempty"`
Command string `json:"command,omitempty"`
Source string `json:"source,omitempty"`
}

// Listener defines the configuration for Vault Agent Cache Listener
Expand All @@ -92,8 +93,12 @@ func (a *Agent) newTemplateConfigs() []*Template {
var templates []*Template
for _, secret := range a.Secrets {
template := secret.Template
if template == "" {
template = fmt.Sprintf(DefaultTemplate, secret.Path)
templateFile := secret.TemplateFile
if templateFile == "" {
template = secret.Template
if template == "" {
template = fmt.Sprintf(DefaultTemplate, secret.Path)
}
}

filePathAndName := fmt.Sprintf("%s/%s", secret.MountPath, secret.Name)
Expand All @@ -102,6 +107,7 @@ func (a *Agent) newTemplateConfigs() []*Template {
}

tmpl := &Template{
Source: templateFile,
Contents: template,
Destination: filePathAndName,
LeftDelim: "{{",
Expand Down
15 changes: 13 additions & 2 deletions agent-inject/agent/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func TestNewConfig(t *testing.T) {
"vault.hashicorp.com/agent-inject-secret-different-path": "different-path",
fmt.Sprintf("%s-%s", AnnotationVaultSecretVolumePath, "different-path"): "/etc/container_environment",

// render this secret from a template on disk
"vault.hashicorp.com/agent-inject-secret-with-file-template": "with-file-template",
fmt.Sprintf("%s-%s", AnnotationAgentInjectTemplateFile, "with-file-template"): "/etc/file-template",

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

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

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

for _, template := range config.Templates {
Expand All @@ -136,6 +140,13 @@ func TestNewConfig(t *testing.T) {
if template.Destination != "/etc/container_environment/different-path" {
t.Errorf("expected template destination to be %s, got %s", "/etc/container_environment", template.Destination)
}
} else if strings.Contains(template.Destination, "with-file-template") {
if template.Source != "/etc/file-template" {
t.Errorf("expected template file path to be %s, got %s", "/etc/file-template", template.Source)
}
if template.Contents != "" {
t.Errorf("expected template contents to be empty, got %s", template.Contents)
}
} else {
t.Error("shouldn't have got here")
}
Expand Down