From 51f0c74b60949c099913b0715c653202d5e080bd Mon Sep 17 00:00:00 2001 From: Andrei Burd Date: Fri, 13 Aug 2021 04:35:45 +0300 Subject: [PATCH] Feat: static_secret_render_interval (#276) Co-authored-by: Theron Voran --- agent-inject/agent/agent.go | 7 ++- agent-inject/agent/annotations.go | 43 +++++++++------ agent-inject/agent/config.go | 4 +- agent-inject/agent/config_test.go | 9 +++- agent-inject/handler.go | 74 ++++++++++++------------- subcommand/injector/command.go | 90 ++++++++++++++++--------------- subcommand/injector/flags.go | 10 ++++ subcommand/injector/flags_test.go | 1 + 8 files changed, 138 insertions(+), 100 deletions(-) diff --git a/agent-inject/agent/agent.go b/agent-inject/agent/agent.go index 4ec1e92d..398f0457 100644 --- a/agent-inject/agent/agent.go +++ b/agent-inject/agent/agent.go @@ -273,6 +273,10 @@ type VaultAgentTemplateConfig struct { // ExitOnRetryFailure configures whether agent should exit after failing // all its retry attempts when rendering templates ExitOnRetryFailure bool + + // StaticSecretRenderInterval If specified, configures how often + // Vault Agent Template should render non-leased secrets such as KV v2 + StaticSecretRenderInterval string } // New creates a new instance of Agent by parsing all the Kubernetes annotations. @@ -417,7 +421,8 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro } agent.VaultAgentTemplateConfig = VaultAgentTemplateConfig{ - ExitOnRetryFailure: exitOnRetryFailure, + ExitOnRetryFailure: exitOnRetryFailure, + StaticSecretRenderInterval: pod.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval], } return agent, nil diff --git a/agent-inject/agent/annotations.go b/agent-inject/agent/annotations.go index 4494f02a..f395a4b2 100644 --- a/agent-inject/agent/annotations.go +++ b/agent-inject/agent/annotations.go @@ -239,26 +239,32 @@ const ( // will exit on template render failures once it has exhausted all its retry // attempts. Defaults to true. AnnotationTemplateConfigExitOnRetryFailure = "vault.hashicorp.com/template-config-exit-on-retry-failure" + + // AnnotationTemplateConfigStaticSecretRenderInterval + // If specified, configures how often Vault Agent Template should render non-leased secrets such as KV v2. + // Defaults to 5 minutes. + AnnotationTemplateConfigStaticSecretRenderInterval = "vault.hashicorp.com/template-static-secret-render-interval" ) type AgentConfig struct { - Image string - Address string - AuthType string - AuthPath string - Namespace string - RevokeOnShutdown bool - UserID string - GroupID string - SameID bool - SetSecurityContext bool - ProxyAddress string - DefaultTemplate string - ResourceRequestCPU string - ResourceRequestMem string - ResourceLimitCPU string - ResourceLimitMem string - ExitOnRetryFailure bool + Image string + Address string + AuthType string + AuthPath string + Namespace string + RevokeOnShutdown bool + UserID string + GroupID string + SameID bool + SetSecurityContext bool + ProxyAddress string + DefaultTemplate string + ResourceRequestCPU string + ResourceRequestMem string + ResourceLimitCPU string + ResourceLimitMem string + ExitOnRetryFailure bool + StaticSecretRenderInterval string } // Init configures the expected annotations required to create a new instance @@ -410,6 +416,9 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error { if _, ok := pod.ObjectMeta.Annotations[AnnotationTemplateConfigExitOnRetryFailure]; !ok { pod.ObjectMeta.Annotations[AnnotationTemplateConfigExitOnRetryFailure] = strconv.FormatBool(cfg.ExitOnRetryFailure) } + if _, ok := pod.ObjectMeta.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval]; !ok { + pod.ObjectMeta.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval] = cfg.StaticSecretRenderInterval + } return nil } diff --git a/agent-inject/agent/config.go b/agent-inject/agent/config.go index b14b5679..9c5aef97 100644 --- a/agent-inject/agent/config.go +++ b/agent-inject/agent/config.go @@ -104,7 +104,8 @@ type CachePersist struct { // TemplateConfig defines the configuration for template_config in Vault Agent type TemplateConfig struct { - ExitOnRetryFailure bool `json:"exit_on_retry_failure"` + ExitOnRetryFailure bool `json:"exit_on_retry_failure"` + StaticSecretRenderInterval string `json:"static_secret_render_interval,omitempty"` } func (a *Agent) newTemplateConfigs() []*Template { @@ -177,6 +178,7 @@ func (a *Agent) newConfig(init bool) ([]byte, error) { Templates: a.newTemplateConfigs(), TemplateConfig: &TemplateConfig{ ExitOnRetryFailure: a.VaultAgentTemplateConfig.ExitOnRetryFailure, + StaticSecretRenderInterval: a.VaultAgentTemplateConfig.StaticSecretRenderInterval, }, } diff --git a/agent-inject/agent/config_test.go b/agent-inject/agent/config_test.go index a4db0a6b..899248f6 100644 --- a/agent-inject/agent/config_test.go +++ b/agent-inject/agent/config_test.go @@ -560,7 +560,14 @@ func TestConfigVaultAgentTemplateConfig(t *testing.T) { &TemplateConfig{ExitOnRetryFailure: false}, }, { - "exit_on_retry_failure absent", + "static_secret_render_interval 10s", + map[string]string{ + AnnotationTemplateConfigStaticSecretRenderInterval: "10s", + }, + &TemplateConfig{ExitOnRetryFailure: true, StaticSecretRenderInterval: "10s"}, + }, + { + "template_config_empty", map[string]string{}, &TemplateConfig{ExitOnRetryFailure: true}, }, diff --git a/agent-inject/handler.go b/agent-inject/handler.go index e8031621..b20abe69 100644 --- a/agent-inject/handler.go +++ b/agent-inject/handler.go @@ -35,25 +35,26 @@ var ( type Handler struct { // RequireAnnotation means that the annotation must be given to inject. // If this is false, injection is default. - RequireAnnotation bool - VaultAddress string - VaultAuthType string - VaultAuthPath string - ProxyAddress string - ImageVault string - Clientset *kubernetes.Clientset - Log hclog.Logger - RevokeOnShutdown bool - UserID string - GroupID string - SameID bool - SetSecurityContext bool - DefaultTemplate string - ResourceRequestCPU string - ResourceRequestMem string - ResourceLimitCPU string - ResourceLimitMem string - ExitOnRetryFailure bool + RequireAnnotation bool + VaultAddress string + VaultAuthType string + VaultAuthPath string + ProxyAddress string + ImageVault string + Clientset *kubernetes.Clientset + Log hclog.Logger + RevokeOnShutdown bool + UserID string + GroupID string + SameID bool + SetSecurityContext bool + DefaultTemplate string + ResourceRequestCPU string + ResourceRequestMem string + ResourceLimitCPU string + ResourceLimitMem string + ExitOnRetryFailure bool + StaticSecretRenderInterval string } // Handle is the http.HandlerFunc implementation that actually handles the @@ -149,23 +150,24 @@ func (h *Handler) Mutate(req *admissionv1.AdmissionRequest) *admissionv1.Admissi h.Log.Debug("setting default annotations..") var patches []*jsonpatch.JsonPatchOperation cfg := agent.AgentConfig{ - Image: h.ImageVault, - Address: h.VaultAddress, - AuthType: h.VaultAuthType, - AuthPath: h.VaultAuthPath, - ProxyAddress: h.ProxyAddress, - Namespace: req.Namespace, - RevokeOnShutdown: h.RevokeOnShutdown, - UserID: h.UserID, - GroupID: h.GroupID, - SameID: h.SameID, - SetSecurityContext: h.SetSecurityContext, - DefaultTemplate: h.DefaultTemplate, - ResourceRequestCPU: h.ResourceRequestCPU, - ResourceRequestMem: h.ResourceRequestMem, - ResourceLimitCPU: h.ResourceLimitCPU, - ResourceLimitMem: h.ResourceLimitMem, - ExitOnRetryFailure: h.ExitOnRetryFailure, + Image: h.ImageVault, + Address: h.VaultAddress, + AuthType: h.VaultAuthType, + AuthPath: h.VaultAuthPath, + ProxyAddress: h.ProxyAddress, + Namespace: req.Namespace, + RevokeOnShutdown: h.RevokeOnShutdown, + UserID: h.UserID, + GroupID: h.GroupID, + SameID: h.SameID, + SetSecurityContext: h.SetSecurityContext, + DefaultTemplate: h.DefaultTemplate, + ResourceRequestCPU: h.ResourceRequestCPU, + ResourceRequestMem: h.ResourceRequestMem, + ResourceLimitCPU: h.ResourceLimitCPU, + ResourceLimitMem: h.ResourceLimitMem, + ExitOnRetryFailure: h.ExitOnRetryFailure, + StaticSecretRenderInterval: h.StaticSecretRenderInterval, } err = agent.Init(&pod, cfg) if err != nil { diff --git a/subcommand/injector/command.go b/subcommand/injector/command.go index 1cbb64c7..2f71ed68 100644 --- a/subcommand/injector/command.go +++ b/subcommand/injector/command.go @@ -34,31 +34,32 @@ import ( type Command struct { UI cli.Ui - flagListen string // Address of Vault Server - flagLogLevel string // Log verbosity - flagLogFormat string // Log format - flagCertFile string // TLS Certificate to serve - flagKeyFile string // TLS private key to serve - flagExitOnRetryFailure bool // Set template_config.exit_on_retry_failure on agent - flagAutoName string // MutatingWebhookConfiguration for updating - flagAutoHosts string // SANs for the auto-generated TLS cert. - flagVaultService string // Name of the Vault service - flagProxyAddress string // HTTP proxy address used to talk to the Vault service - flagVaultImage string // Name of the Vault Image to use - flagVaultAuthType string // Type of Vault Auth Method to use - flagVaultAuthPath string // Mount path of the Vault Auth Method - flagRevokeOnShutdown bool // Revoke Vault Token on pod shutdown - flagRunAsUser string // User (uid) to run Vault agent as - flagRunAsGroup string // Group (gid) to run Vault agent as - flagRunAsSameUser bool // Run Vault agent as the User (uid) of the first application container - flagSetSecurityContext bool // Set SecurityContext in injected containers - flagTelemetryPath string // Path under which to expose metrics - flagUseLeaderElector bool // Use leader elector code - flagDefaultTemplate string // Toggles which default template to use - flagResourceRequestCPU string // Set CPU request in the injected containers - flagResourceRequestMem string // Set Memory request in the injected containers - flagResourceLimitCPU string // Set CPU limit in the injected containers - flagResourceLimitMem string // Set Memory limit in the injected containers + flagListen string // Address of Vault Server + flagLogLevel string // Log verbosity + flagLogFormat string // Log format + flagCertFile string // TLS Certificate to serve + flagKeyFile string // TLS private key to serve + flagExitOnRetryFailure bool // Set template_config.exit_on_retry_failure on agent + flagStaticSecretRenderInterval string // Set template_config.static_secret_render_interval on agent + flagAutoName string // MutatingWebhookConfiguration for updating + flagAutoHosts string // SANs for the auto-generated TLS cert. + flagVaultService string // Name of the Vault service + flagProxyAddress string // HTTP proxy address used to talk to the Vault service + flagVaultImage string // Name of the Vault Image to use + flagVaultAuthType string // Type of Vault Auth Method to use + flagVaultAuthPath string // Mount path of the Vault Auth Method + flagRevokeOnShutdown bool // Revoke Vault Token on pod shutdown + flagRunAsUser string // User (uid) to run Vault agent as + flagRunAsGroup string // Group (gid) to run Vault agent as + flagRunAsSameUser bool // Run Vault agent as the User (uid) of the first application container + flagSetSecurityContext bool // Set SecurityContext in injected containers + flagTelemetryPath string // Path under which to expose metrics + flagUseLeaderElector bool // Use leader elector code + flagDefaultTemplate string // Toggles which default template to use + flagResourceRequestCPU string // Set CPU request in the injected containers + flagResourceRequestMem string // Set Memory request in the injected containers + flagResourceLimitCPU string // Set CPU limit in the injected containers + flagResourceLimitMem string // Set Memory limit in the injected containers flagSet *flag.FlagSet @@ -160,25 +161,26 @@ func (c *Command) Run(args []string) int { // Build the HTTP handler and server injector := agentInject.Handler{ - VaultAddress: c.flagVaultService, - VaultAuthType: c.flagVaultAuthType, - VaultAuthPath: c.flagVaultAuthPath, - ProxyAddress: c.flagProxyAddress, - ImageVault: c.flagVaultImage, - Clientset: clientset, - RequireAnnotation: true, - Log: logger, - RevokeOnShutdown: c.flagRevokeOnShutdown, - UserID: c.flagRunAsUser, - GroupID: c.flagRunAsGroup, - SameID: c.flagRunAsSameUser, - SetSecurityContext: c.flagSetSecurityContext, - DefaultTemplate: c.flagDefaultTemplate, - ResourceRequestCPU: c.flagResourceRequestCPU, - ResourceRequestMem: c.flagResourceRequestMem, - ResourceLimitCPU: c.flagResourceLimitCPU, - ResourceLimitMem: c.flagResourceLimitMem, - ExitOnRetryFailure: c.flagExitOnRetryFailure, + VaultAddress: c.flagVaultService, + VaultAuthType: c.flagVaultAuthType, + VaultAuthPath: c.flagVaultAuthPath, + ProxyAddress: c.flagProxyAddress, + ImageVault: c.flagVaultImage, + Clientset: clientset, + RequireAnnotation: true, + Log: logger, + RevokeOnShutdown: c.flagRevokeOnShutdown, + UserID: c.flagRunAsUser, + GroupID: c.flagRunAsGroup, + SameID: c.flagRunAsSameUser, + SetSecurityContext: c.flagSetSecurityContext, + DefaultTemplate: c.flagDefaultTemplate, + ResourceRequestCPU: c.flagResourceRequestCPU, + ResourceRequestMem: c.flagResourceRequestMem, + ResourceLimitCPU: c.flagResourceLimitCPU, + ResourceLimitMem: c.flagResourceLimitMem, + ExitOnRetryFailure: c.flagExitOnRetryFailure, + StaticSecretRenderInterval: c.flagStaticSecretRenderInterval, } mux := http.NewServeMux() diff --git a/subcommand/injector/flags.go b/subcommand/injector/flags.go index f0b639f7..12061044 100644 --- a/subcommand/injector/flags.go +++ b/subcommand/injector/flags.go @@ -34,6 +34,10 @@ type Specification struct { // AGENT_INJECT_TEMPLATE_CONFIG_EXIT_ON_RETRY_FAILURE environment variable. TemplateConfigExitOnRetryFailure string `split_words:"true"` + // TemplateConfigStaticSecretRenderInterval is the + // AGENT_INJECT_TEMPLATE_STATIC_SECRET_RENDER_INTERVAL environment variable. + TemplateConfigStaticSecretRenderInterval string `envconfig:"AGENT_INJECT_TEMPLATE_STATIC_SECRET_RENDER_INTERVAL"` + // TLSAuto is the AGENT_INJECT_TLS_AUTO environment variable. TLSAuto string `envconfig:"tls_auto"` @@ -107,6 +111,8 @@ func (c *Command) init() { `Supported log formats: "standard", "json".`) c.flagSet.BoolVar(&c.flagExitOnRetryFailure, "template-config-exit-on-retry-failure", agent.DefaultTemplateConfigExitOnRetryFailure, fmt.Sprintf("Value for Agent's template_config.exit_on_retry_failure. Defaults to %t.", agent.DefaultTemplateConfigExitOnRetryFailure)) + c.flagSet.StringVar(&c.flagStaticSecretRenderInterval, "template-static-secret-render-interval", "", + "Value for Agent's template_config.exit_on_retry_failure.") c.flagSet.StringVar(&c.flagAutoName, "tls-auto", "", "MutatingWebhookConfiguration name. If specified, will auto generate cert bundle.") c.flagSet.StringVar(&c.flagAutoHosts, "tls-auto-hosts", "", @@ -205,6 +211,10 @@ func (c *Command) parseEnvs() error { } } + if envs.TemplateConfigStaticSecretRenderInterval != "" { + c.flagStaticSecretRenderInterval = envs.TemplateConfigStaticSecretRenderInterval + } + if envs.TLSAuto != "" { c.flagAutoName = envs.TLSAuto } diff --git a/subcommand/injector/flags_test.go b/subcommand/injector/flags_test.go index 9caed05e..374bf1ce 100644 --- a/subcommand/injector/flags_test.go +++ b/subcommand/injector/flags_test.go @@ -130,6 +130,7 @@ func TestCommandEnvs(t *testing.T) { {env: "AGENT_INJECT_MEM_REQUEST", value: "256m", cmdPtr: &cmd.flagResourceRequestMem}, {env: "AGENT_INJECT_CPU_LIMIT", value: "1000m", cmdPtr: &cmd.flagResourceLimitCPU}, {env: "AGENT_INJECT_MEM_LIMIT", value: "256m", cmdPtr: &cmd.flagResourceLimitMem}, + {env: "AGENT_INJECT_TEMPLATE_STATIC_SECRET_RENDER_INTERVAL", value: "12s", cmdPtr: &cmd.flagStaticSecretRenderInterval}, } for _, tt := range tests {