-
Notifications
You must be signed in to change notification settings - Fork 171
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
Possibility to use template and template-file annotations without sec… #505
Possibility to use template and template-file annotations without sec… #505
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the concept for this, and would love to get it merged. My comments just resolve around wanting to preserve backwards compatibility so we don't break existing users. We can discuss a breaking change if you think it's necessary, but my read is that it shouldn't be too hard to avoid it.
@tomhjp Ready, old test cases are now works and I added new ones to cover case when only template or template-file annotation set up |
agent-inject/agent/annotations.go
Outdated
for _, secret := range templateSecrets { | ||
secrets = append(secrets, secret) | ||
} | ||
|
||
templateName := fmt.Sprintf("%s-%s", AnnotationAgentInjectTemplate, raw) | ||
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 | ||
} | ||
} | ||
for _, secret := range simpleSecrets { | ||
if templateSecrets[secret.Name] == nil && templateFileSecrets[secret.Name] == nil { | ||
secrets = append(secrets, secret) | ||
} | ||
} | ||
|
||
s.MountPath = a.Annotations[AnnotationVaultSecretVolumePath] | ||
mountPathAnnotationName := fmt.Sprintf("%s-%s", AnnotationVaultSecretVolumePath, raw) | ||
if val, ok := a.Annotations[mountPathAnnotationName]; ok { | ||
s.MountPath = val | ||
} | ||
for _, secret := range templateFileSecrets { | ||
if templateSecrets[secret.Name] == nil { | ||
secrets = append(secrets, secret) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The order of precedence here doesn't look quite right to me. To make the new behaviour a superset of the previous behaviour, we should always set secret.Path
and secret.Template
if those annotations are present. Then we should set secret.TemplateFile
if that annotation is present and secret.Template == ""
.
I think we could probably simplify by separating the logic for parsing secret names from the logic for reading in config for each secret. It might not be quite right, but I pushed b00bf8d to illustrate the idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you can check, Path is only required in case when Template is not set. to put this value in template, so my changes won't affect anything. Here's the only one place where Path is used: https://github.com/hashicorp/vault-k8s/blob/main/agent-inject/agent/config.go#L186.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we're setting Path unconditionally, why we should set TemplateFile conditionally? I pushed some changes, please check if you're ok with them
@tomhjp any issues with this implementation? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay doing another round of reviewing. This looks really close now, one change that I think is a requirement and the other comments are just nits.
if len(agent.Secrets) == 0 { | ||
t.Error("Secrets length was zero, it shouldn't have been") | ||
} | ||
var found bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updated assertions for this test are reasonable, but please could we tighten them a bit further? The test case input should probably now specify an array of struct { key, template string }
to expect so it can handle the fourth test case precisely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rewrote it to maps
@@ -495,7 +526,7 @@ func TestSecretTemplateFileAnnotations(t *testing.T) { | |||
"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", "", | |||
}, "foobar", "foobarTemplate", "/etc/config.tmpl", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this change makes sense in the context of what the test is trying to assert. And I think it's highlighting a backwards incompatibility. I'll leave another comment on the actual fix site.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you wish :)
agent-inject/agent/annotations.go
Outdated
for _, secret := range secrets { | ||
secret.Path = a.annotationsSecretValue(AnnotationAgentInjectSecret, secret.RawName, secret.Path) | ||
secret.Template = a.annotationsSecretValue(AnnotationAgentInjectTemplate, secret.RawName, secret.Template) | ||
secret.TemplateFile = a.annotationsSecretValue(AnnotationAgentInjectTemplateFile, secret.RawName, secret.TemplateFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secret.TemplateFile = a.annotationsSecretValue(AnnotationAgentInjectTemplateFile, secret.RawName, secret.TemplateFile) | |
if secret.Template == "" { | |
secret.TemplateFile = a.annotationsSecretValue(AnnotationAgentInjectTemplateFile, secret.RawName, secret.TemplateFile) | |
} |
I know you disagreed with this elsewhere, but I still think this is worth doing. Here's where the downstream processing of secret.Template
and secret.TemplateFile
takes place:
vault-k8s/agent-inject/agent/config.go
Lines 180 to 214 in 02af6ab
var templates []*Template | |
for _, secret := range a.Secrets { | |
template := secret.Template | |
templateFile := secret.TemplateFile | |
if templateFile == "" { | |
template = secret.Template | |
if template == "" { | |
switch a.DefaultTemplate { | |
case "json": | |
template = fmt.Sprintf(DefaultJSONTemplate, secret.Path) | |
case "map": | |
template = fmt.Sprintf(DefaultMapTemplate, secret.Path) | |
} | |
} | |
} | |
filePathAndName := fmt.Sprintf("%s/%s", secret.MountPath, secret.Name) | |
if secret.FilePathAndName != "" { | |
filePathAndName = filepath.Join(secret.MountPath, secret.FilePathAndName) | |
} | |
tmpl := &Template{ | |
Source: templateFile, | |
Contents: template, | |
Destination: filePathAndName, | |
LeftDelim: "{{", | |
RightDelim: "}}", | |
Command: secret.Command, | |
} | |
if secret.FilePermission != "" { | |
tmpl.Perms = secret.FilePermission | |
} | |
templates = append(templates, tmpl) | |
} | |
return templates |
The logic is kind of confusingly written, but take the case where both the template and template-file annotations are non-empty. Previously, secret.Template
is non-empty and secret.TemplateFile
is empty, and the same happens in tmpl
. Now, both are non-empty in secret
and the same in tmpl
. Maybe we could chase the behaviour of what happens next all the way down into consul-template, but I'd rather just take the high confidence route of keeping the localised behaviour the same here.
agent-inject/agent/annotations.go
Outdated
secrets = append(secrets, s) | ||
} | ||
for _, secret := range secrets { | ||
secret.Path = a.annotationsSecretValue(AnnotationAgentInjectSecret, secret.RawName, secret.Path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It reads a little strangely to me to use the values of fields we haven't set yet as the default. Could we just pass in "" as the default for all the lines except volume path to make it a little easier to read?
secret.Path = a.annotationsSecretValue(AnnotationAgentInjectSecret, secret.RawName, secret.Path) | |
secret.Path = a.annotationsSecretValue(AnnotationAgentInjectSecret, secret.RawName, "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wrote like this just in case if there will be some default values setted at the top, so this one will not overwrite them.
@saturn4er I'm going to start kicking off a release soon, but I'd love to get this merged first. LMK if you're able to address the remaining comments - I pushed a commit that implements the comments here if that's helpful: 92153f6 |
@tomhjp, I've made revisions based on your suggestions. Could you please review the changes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks great 👍
Summary
This Pull Request introduces enhancements to the Vault Kubernetes integration by simplifying the secret injection process. Specifically, it removes the need for the redundant and ineffective
vault.hashicorp.com/agent-inject-secret-foo: someKey
annotation.Motivation
In the current implementation, users are required to include the
vault.hashicorp.com/agent-inject-secret-foo: someKey
annotation in their configuration. However, this annotation doesn't contribute to the functionality and only adds unnecessary complexity.Changes Introduced
With this PR, users will no longer need to specify the
vault.hashicorp.com/agent-inject-secret-foo: someKey
annotation. Instead, the necessary information about secrets can be fully determined by the provided templates or template files, such asvault.hashicorp.com/agent-inject-template-foo: "{{- with secret "someKey" -}} {{- end }}"
orvault.hashicorp.com/agent-inject-template-file-foo: "someFile"
.This results in a cleaner and more intuitive configuration.