Skip to content

Commit

Permalink
Generalize Agent Auto Auth to allow all methods
Browse files Browse the repository at this point in the history
No fail if Role not specified unless K8s auth

Add tests

Signed-off-by: Pierce Bartine <piercebartine@gmail.com>
  • Loading branch information
pbar1 committed Jan 17, 2021
1 parent 902bcbd commit b5d27ae
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 30 deletions.
13 changes: 11 additions & 2 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

const (
DefaultVaultImage = "vault:1.6.1"
DefaultVaultAuthType = "kubernetes"
DefaultVaultAuthPath = "auth/kubernetes"
DefaultAgentRunAsUser = 100
DefaultAgentRunAsGroup = 1000
Expand Down Expand Up @@ -156,9 +157,15 @@ type Vault struct {
// Address is the Vault service address.
Address string

// AuthPath is the Mount Path of Vault Kubernetes Auth Method.
// AuthType is type of Vault Auth Method to use.
AuthType string

// AuthPath is the Mount Path of Vault Auth Method.
AuthPath string

// AuthConfig is the Auto Auth Method configuration.
AuthConfig map[string]interface{}

// CACert is the name of the Certificate Authority certificate
// to use when validating Vault's server certificates.
CACert string
Expand Down Expand Up @@ -236,6 +243,7 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
ExtraSecret: pod.Annotations[AnnotationAgentExtraSecret],
Vault: Vault{
Address: pod.Annotations[AnnotationVaultService],
AuthType: pod.Annotations[AnnotationVaultAuthType],
AuthPath: pod.Annotations[AnnotationVaultAuthPath],
CACert: pod.Annotations[AnnotationVaultCACert],
CAKey: pod.Annotations[AnnotationVaultCAKey],
Expand All @@ -253,6 +261,7 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro

var err error
agent.Secrets = agent.secrets()
agent.Vault.AuthConfig = agent.authConfig()
agent.Inject, err = agent.inject()
if err != nil {
return agent, err
Expand Down Expand Up @@ -495,7 +504,7 @@ func (a *Agent) Validate() error {
}

if a.ConfigMapName == "" {
if a.Vault.Role == "" {
if a.Vault.Role == "" && a.Vault.AuthType == DefaultVaultAuthType {
return errors.New("no Vault role found")
}

Expand Down
34 changes: 32 additions & 2 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,17 @@ const (
// method.
AnnotationVaultRole = "vault.hashicorp.com/role"

// AnnotationVaultAuthPath specifies the mount path to be used for the Kubernetes auto-auth
// method.
// AnnotationVaultAuthType specifies the auto-auth method type to be used.
AnnotationVaultAuthType = "vault.hashicorp.com/auth-type"

// AnnotationVaultAuthPath specifies the mount path to be used for the auto-auth method.
AnnotationVaultAuthPath = "vault.hashicorp.com/auth-path"

// AnnotationVaultAuthConfig specifies the Auto Auth Method configuration parameters.
// The name of the parameter is any unique string after "vault.hashicorp.com/auth-config-",
// such as "vault.hashicorp.com/auth-config-foobar".
AnnotationVaultAuthConfig = "vault.hashicorp.com/auth-config"

// AnnotationVaultSecretVolumePath specifies where the secrets are to be
// Mounted after fetching.
AnnotationVaultSecretVolumePath = "vault.hashicorp.com/secret-volume-path"
Expand All @@ -196,6 +203,7 @@ const (
type AgentConfig struct {
Image string
Address string
AuthType string
AuthPath string
Namespace string
RevokeOnShutdown bool
Expand Down Expand Up @@ -238,6 +246,10 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationVaultService] = cfg.Address
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationVaultAuthType]; !ok {
pod.ObjectMeta.Annotations[AnnotationVaultAuthType] = cfg.AuthType
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationVaultAuthPath]; !ok {
pod.ObjectMeta.Annotations[AnnotationVaultAuthPath] = cfg.AuthPath
}
Expand Down Expand Up @@ -514,3 +526,21 @@ func (a *Agent) agentCacheEnable() (bool, error) {

return strconv.ParseBool(raw)
}

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

prefix := fmt.Sprintf("%s-", AnnotationVaultAuthConfig)
for annotation, value := range a.Annotations {
if strings.HasPrefix(annotation, prefix) {
param := strings.TrimPrefix(annotation, prefix)
param = strings.ReplaceAll(param, "-", "_")
authConfig[param] = value
}
}
if len(authConfig) == 0 && a.Vault.AuthType == DefaultVaultAuthType {
authConfig["role"] = a.Vault.Role
}

return authConfig
}
86 changes: 74 additions & 12 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestInitCanSet(t *testing.T) {
pod := testPod(annotations)

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -55,7 +55,7 @@ func TestInitDefaults(t *testing.T) {
pod := testPod(annotations)

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "", "",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "", "",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -89,7 +89,7 @@ func TestInitError(t *testing.T) {
pod := testPod(annotations)

agentConfig := AgentConfig{
"image", "", "authPath", "namespace", true, "100", "1000",
"image", "", DefaultVaultAuthType, "authPath", "namespace", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -153,7 +153,7 @@ func TestSecretAnnotationsWithPreserveCaseSensitivityFlagOff(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -204,7 +204,7 @@ func TestSecretAnnotationsWithPreserveCaseSensitivityFlagOn(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -291,7 +291,7 @@ func TestSecretLocationFileAnnotations(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -376,7 +376,7 @@ func TestSecretTemplateAnnotations(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -436,7 +436,7 @@ func TestTemplateShortcuts(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -496,7 +496,7 @@ func TestSecretCommandAnnotations(t *testing.T) {
for _, tt := range tests {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -629,7 +629,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", "test", "test", true, "100", "1000",
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand All @@ -650,7 +650,7 @@ func TestInitEmptyPod(t *testing.T) {
var pod *corev1.Pod

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -679,7 +679,7 @@ func TestVaultNamespaceAnnotation(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -793,3 +793,65 @@ func Test_runAsSameID(t *testing.T) {
})
}
}

func TestAuthConfigAnnotations(t *testing.T) {
tests := []struct {
annotations map[string]string
expectedAuthConfig map[string]interface{}
}{
{
map[string]string{
"vault.hashicorp.com/role": "backwardscompat",
},
map[string]interface{}{
"role": "backwardscompat",
},
},
{
map[string]string{
"vault.hashicorp.com/role": "backwardscompat",
"vault.hashicorp.com/auth-config-role": "takesprecedence",
},
map[string]interface{}{
"role": "takesprecedence",
},
},
{
map[string]string{
"vault.hashicorp.com/auth-config-name": "foo",
"vault.hashicorp.com/auth-config-ca-cert": "bar",
"vault.hashicorp.com/auth-config-client_cert": "baz",
"vault.hashicorp.com/auth-config-credential_poll_interval": "1",
"vault.hashicorp.com/auth-config-remove_secret_id_file_after_reading": "false",
},
map[string]interface{}{
"name": "foo",
"ca_cert": "bar", // param name dashes converted to underscores for ease
"client_cert": "baz",
"credential_poll_interval": "1", // string->int conversion left up to consuming app HCL parser
"remove_secret_id_file_after_reading": "false", // string->bool, same as above
},
},
}

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

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "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)
}

require.Equal(t, agent.Vault.AuthConfig, tt.expectedAuthConfig, "expected AuthConfig %v, got %v", tt.expectedAuthConfig, agent.Vault.AuthConfig)
}
}
6 changes: 2 additions & 4 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,10 @@ func (a *Agent) newConfig(init bool) ([]byte, error) {
},
AutoAuth: &AutoAuth{
Method: &Method{
Type: "kubernetes",
Type: a.Vault.AuthType,
Namespace: a.Vault.Namespace,
MountPath: a.Vault.AuthPath,
Config: map[string]interface{}{
"role": a.Vault.Role,
},
Config: a.Vault.AuthConfig,
},
Sinks: []*Sink{
{
Expand Down
8 changes: 4 additions & 4 deletions agent-inject/agent/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestNewConfig(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -207,7 +207,7 @@ func TestFilePathAndName(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -239,7 +239,7 @@ func TestConfigVaultAgentCacheNotEnabledByDefault(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down Expand Up @@ -278,7 +278,7 @@ func TestConfigVaultAgentCache(t *testing.T) {
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
Expand Down
8 changes: 4 additions & 4 deletions agent-inject/agent/container_sidecar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestContainerSidecarVolume(t *testing.T) {
pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", "test", "test", true, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", DefaultVaultAuthType, "test", "test", true, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestContainerSidecar(t *testing.T) {
pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", "test", "test", false, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", DefaultVaultAuthType, "test", "test", false, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}
Expand Down Expand Up @@ -193,7 +193,7 @@ func TestContainerSidecarRevokeHook(t *testing.T) {
pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", "test", "test", tt.revokeFlag, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", DefaultVaultAuthType, "test", "test", tt.revokeFlag, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}
Expand Down Expand Up @@ -242,7 +242,7 @@ func TestContainerSidecarConfigMap(t *testing.T) {
pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", "test", "test", true, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
err := Init(pod, AgentConfig{"foobar-image", "http://foobar:1234", DefaultVaultAuthType, "test", "test", true, "1000", "100", DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext})
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}
Expand Down
2 changes: 2 additions & 0 deletions agent-inject/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Handler struct {
// If this is false, injection is default.
RequireAnnotation bool
VaultAddress string
VaultAuthType string
VaultAuthPath string
ImageVault string
Clientset *kubernetes.Clientset
Expand Down Expand Up @@ -143,6 +144,7 @@ func (h *Handler) Mutate(req *v1beta1.AdmissionRequest) *v1beta1.AdmissionRespon
cfg := agent.AgentConfig{
Image: h.ImageVault,
Address: h.VaultAddress,
AuthType: h.VaultAuthType,
AuthPath: h.VaultAuthPath,
Namespace: req.Namespace,
RevokeOnShutdown: h.RevokeOnShutdown,
Expand Down
Loading

0 comments on commit b5d27ae

Please sign in to comment.