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

Use a file sink for agent-inject-token #250

Merged
merged 1 commit into from
Apr 22, 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
11 changes: 11 additions & 0 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
DefaultAgentCacheListenerPort = "8200"
DefaultAgentCacheExitOnErr = false
DefaultAgentUseLeaderElector = false
DefaultAgentInjectToken = false
)

// Agent is the top level structure holding all the
Expand Down Expand Up @@ -143,9 +144,14 @@ type Agent struct {
// where the JWT would be present
// Need this for IRSA aka pod identity
AwsIamTokenAccountPath string

// CopyVolumeMounts is the name of the container in the Pod whose volume mounts
// should be copied into the Vault Agent init and/or sidecar containers.
CopyVolumeMounts string

// InjectToken controls whether the auto-auth token is injected into the
// secrets volume (e.g. /vault/secrets/token)
InjectToken bool
}

type Secret struct {
Expand Down Expand Up @@ -378,6 +384,11 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
return agent, fmt.Errorf("invalid default template type: %s", agent.DefaultTemplate)
}

agent.InjectToken, err = agent.injectToken()
if err != nil {
return agent, err
}

agent.VaultAgentCache = VaultAgentCache{
Enable: agentCacheEnable,
ListenerPort: pod.Annotations[AnnotationAgentCacheListenerPort],
Expand Down
17 changes: 10 additions & 7 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ const (
// 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 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"

// AnnotationAgentInjectCommand is the key annotation that configures Vault Agent
Expand Down Expand Up @@ -407,11 +407,6 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
func (a *Agent) secrets() []*Secret {
var secrets []*Secret

// First check for the token-only injection annotation
if _, found := a.Annotations[AnnotationAgentInjectToken]; found {
a.Annotations[fmt.Sprintf("%s-%s", AnnotationAgentInjectSecret, "token")] = TokenSecret
a.Annotations[fmt.Sprintf("%s-%s", AnnotationAgentInjectTemplate, "token")] = TokenTemplate
}
for name, path := range a.Annotations {
secretName := fmt.Sprintf("%s-", AnnotationAgentInjectSecret)
if strings.Contains(name, secretName) {
Expand Down Expand Up @@ -602,6 +597,14 @@ func (a *Agent) cacheExitOnErr() (bool, error) {
return strconv.ParseBool(raw)
}

func (a *Agent) injectToken() (bool, error) {
raw, ok := a.Annotations[AnnotationAgentInjectToken]
if !ok {
return DefaultAgentInjectToken, nil
}
return strconv.ParseBool(raw)
}

func (a *Agent) authConfig() map[string]interface{} {
authConfig := make(map[string]interface{})

Expand Down
67 changes: 0 additions & 67 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,73 +411,6 @@ func TestSecretTemplateAnnotations(t *testing.T) {
}
}

func TestTemplateShortcuts(t *testing.T) {
tests := []struct {
name string
annotations map[string]string
expectedSecrets map[string]Secret
}{
{
"valid inject-token",
map[string]string{
AnnotationAgentInjectToken: "true",
},
map[string]Secret{
"token": Secret{
Name: "token",
Path: TokenSecret,
Template: TokenTemplate,
MountPath: secretVolumePath,
},
},
},
{
"invalid inject-token",
map[string]string{
"vault.hashicorp.com/agent-inject-token-invalid": "true",
},
map[string]Secret{},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pod := testPod(tt.annotations)
agentConfig := basicAgentConfig()
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 TestSecretMixedTemplatesAnnotations(t *testing.T) {
tests := []struct {
annotations map[string]string
Expand Down
12 changes: 10 additions & 2 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package agent
import (
"encoding/json"
"fmt"
"path"
"path/filepath"
"time"
)
Expand All @@ -11,8 +12,6 @@ const (
DefaultMapTemplate = "{{ with secret \"%s\" }}{{ range $k, $v := .Data }}{{ $k }}: {{ $v }}\n{{ end }}{{ end }}"
DefaultJSONTemplate = "{{ with secret \"%s\" }}{{ .Data | toJSON }}\n{{ end }}"
DefaultTemplateType = "map"
TokenTemplate = "{{ with secret \"auth/token/lookup-self\" }}{{ .Data.id }}\n{{ end }}"
TokenSecret = "auth/token/lookup-self"
PidFile = "/home/vault/.pid"
TokenFile = "/home/vault/.vault-token"
)
Expand Down Expand Up @@ -168,6 +167,15 @@ func (a *Agent) newConfig(init bool) ([]byte, error) {
Templates: a.newTemplateConfigs(),
}

if a.InjectToken {
config.AutoAuth.Sinks = append(config.AutoAuth.Sinks, &Sink{
Type: "file",
Config: map[string]interface{}{
"path": path.Join(a.Annotations[AnnotationVaultSecretVolumePath], "token"),
},
})
}

cacheListener := []*Listener{
{
Type: "tcp",
Expand Down
75 changes: 75 additions & 0 deletions agent-inject/agent/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,78 @@ func TestConfigVaultAgentCache_persistent(t *testing.T) {
}

}

func TestInjectTokenSink(t *testing.T) {

tokenHelperSink := &Sink{
Type: "file",
Config: map[string]interface{}{
"path": TokenFile,
},
}
injectTokenSink := &Sink{
Type: "file",
Config: map[string]interface{}{
"path": secretVolumePath + "/token",
},
}

tests := []struct {
name string
annotations map[string]string
expectedSinks []*Sink
}{
{
"token true",
map[string]string{
AnnotationAgentInjectToken: "true",
},
[]*Sink{tokenHelperSink, injectTokenSink},
},
{
"token false",
map[string]string{
AnnotationAgentInjectToken: "false",
},
[]*Sink{tokenHelperSink},
},
{
"custom secret volume path",
map[string]string{
AnnotationAgentInjectToken: "true",
AnnotationVaultSecretVolumePath: "/new/secrets",
},
[]*Sink{
tokenHelperSink,
{
Type: "file",
Config: map[string]interface{}{
"path": "/new/secrets/token",
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
require.NoError(t, err)

agent, err := New(pod, patches)
require.NoError(t, err)
cfg, err := agent.newConfig(true)
require.NoError(t, err)

config := &Config{}
err = json.Unmarshal(cfg, config)
require.NoError(t, err)

assert.Equal(t, tt.expectedSinks, config.AutoAuth.Sinks)
})
}
}