Skip to content

Commit

Permalink
Add MaxConnectionsPerHost to Agent Injector (#579)
Browse files Browse the repository at this point in the history
* add MaxConnectionsPerHost to agent injector

* update tests to account for MaxConnectionsPerHost

* fix annotation

* properly format max conns per host annotation

* change bool and int parsing from strconv to parseutil

* fix parseutil.ParseInt args

* fix default max conns value

* fix TestCouldErrorAnnotations to account for valid empty string bools

* fix TestAgentJsonPatch

* more TestAgentJsonPatch fixes

* remove DefaultTemplateConfigMaxConnectionsPerHost

* fix indentation

* add changelog entry
  • Loading branch information
ccapurso authored Jan 24, 2024
1 parent a3b5402 commit 4c7876b
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 39 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## Unreleased
Features:
* Add support for `max_connections_per_host` within Agent injector [GH-579](https://github.com/hashicorp/vault-k8s/pull/579)

Changes:
* Dependency updates:
Expand Down
19 changes: 15 additions & 4 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"

jsonpatch "github.com/evanphx/json-patch"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/pointer"
Expand Down Expand Up @@ -340,6 +340,11 @@ type VaultAgentTemplateConfig struct {
// StaticSecretRenderInterval If specified, configures how often
// Vault Agent Template should render non-leased secrets such as KV v2
StaticSecretRenderInterval string

// MaxConnectionsPerHost limits the total number of connections
// that the Vault Agent templating engine can use for a particular Vault host. This limit
// includes connections in the dialing, active, and idle states.
MaxConnectionsPerHost int64
}

// New creates a new instance of Agent by parsing all the Kubernetes annotations.
Expand Down Expand Up @@ -439,12 +444,12 @@ func New(pod *corev1.Pod) (*Agent, error) {
return agent, err
}

agent.RunAsUser, err = strconv.ParseInt(pod.Annotations[AnnotationAgentRunAsUser], 10, 64)
agent.RunAsUser, err = parseutil.ParseInt(pod.Annotations[AnnotationAgentRunAsUser])
if err != nil {
return agent, err
}

agent.RunAsGroup, err = strconv.ParseInt(pod.Annotations[AnnotationAgentRunAsGroup], 10, 64)
agent.RunAsGroup, err = parseutil.ParseInt(pod.Annotations[AnnotationAgentRunAsGroup])
if err != nil {
return agent, err
}
Expand Down Expand Up @@ -503,9 +508,15 @@ func New(pod *corev1.Pod) (*Agent, error) {
return nil, err
}

maxConnectionsPerHost, err := agent.templateConfigMaxConnectionsPerHost()
if err != nil {
return nil, err
}

agent.VaultAgentTemplateConfig = VaultAgentTemplateConfig{
ExitOnRetryFailure: exitOnRetryFailure,
StaticSecretRenderInterval: pod.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval],
MaxConnectionsPerHost: maxConnectionsPerHost,
}

agent.EnableQuit, err = agent.getEnableQuit()
Expand Down Expand Up @@ -537,7 +548,7 @@ func ShouldInject(pod *corev1.Pod) (bool, error) {
return false, nil
}

inject, err := strconv.ParseBool(raw)
inject, err := parseutil.ParseBool(raw)
if err != nil {
return false, err
}
Expand Down
55 changes: 38 additions & 17 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

jsonpatch "github.com/evanphx/json-patch"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
)
Expand All @@ -24,7 +25,7 @@ const (

// AnnotationAgentInject is the key of the annotation that controls whether
// injection is explicitly enabled or disabled for a pod. This should
// be set to a true or false value, as parseable by strconv.ParseBool
// be set to a true or false value, as parseable by parseutil.ParseBool
AnnotationAgentInject = "vault.hashicorp.com/agent-inject"

// AnnotationAgentInjectSecret is the key annotation that configures Vault
Expand Down Expand Up @@ -273,6 +274,11 @@ const (
// Defaults to 5 minutes.
AnnotationTemplateConfigStaticSecretRenderInterval = "vault.hashicorp.com/template-static-secret-render-interval"

// AnnotationTemplateConfigMaxConnectionsPerHost limits the total number of connections
// that the Vault Agent templating engine can use for a particular Vault host. This limit
// includes connections in the dialing, active, and idle states.
AnnotationTemplateConfigMaxConnectionsPerHost = "vault.hashicorp.com/template-max-connections-per-host"

// AnnotationAgentEnableQuit configures whether the quit endpoint is
// enabled in the injected agent config
AnnotationAgentEnableQuit = "vault.hashicorp.com/agent-enable-quit"
Expand Down Expand Up @@ -335,6 +341,7 @@ type AgentConfig struct {
ResourceLimitEphemeral string
ExitOnRetryFailure bool
StaticSecretRenderInterval string
MaxConnectionsPerHost int64
AuthMinBackoff string
AuthMaxBackoff string
DisableIdleConnections string
Expand Down Expand Up @@ -519,6 +526,10 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval] = cfg.StaticSecretRenderInterval
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationTemplateConfigMaxConnectionsPerHost]; !ok {
pod.ObjectMeta.Annotations[AnnotationTemplateConfigMaxConnectionsPerHost] = strconv.FormatInt(cfg.MaxConnectionsPerHost, 10)
}

if minBackoffString, ok := pod.ObjectMeta.Annotations[AnnotationAgentAuthMinBackoff]; ok {
if minBackoffString != "" {
_, err := time.ParseDuration(minBackoffString)
Expand Down Expand Up @@ -662,7 +673,7 @@ func (a *Agent) inject() (bool, error) {
return true, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) initFirst() (bool, error) {
Expand All @@ -671,7 +682,7 @@ func (a *Agent) initFirst() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) prePopulate() (bool, error) {
Expand All @@ -680,7 +691,7 @@ func (a *Agent) prePopulate() (bool, error) {
return true, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) prePopulateOnly() (bool, error) {
Expand All @@ -689,7 +700,7 @@ func (a *Agent) prePopulateOnly() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) revokeOnShutdown() (bool, error) {
Expand All @@ -698,7 +709,7 @@ func (a *Agent) revokeOnShutdown() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) revokeGrace() (uint64, error) {
Expand All @@ -716,7 +727,7 @@ func (a *Agent) tlsSkipVerify() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) preserveSecretCase(secretName string) (bool, error) {
Expand All @@ -732,15 +743,15 @@ func (a *Agent) preserveSecretCase(secretName string) (bool, error) {
return false, nil
}
}
return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) runAsSameID(pod *corev1.Pod) (bool, error) {
raw, ok := a.Annotations[AnnotationAgentRunAsSameUser]
if !ok {
return DefaultAgentRunAsSameUser, nil
}
runAsSameID, err := strconv.ParseBool(raw)
runAsSameID, err := parseutil.ParseBool(raw)
if err != nil {
return DefaultAgentRunAsSameUser, err
}
Expand Down Expand Up @@ -769,7 +780,7 @@ func (a *Agent) setShareProcessNamespace(pod *corev1.Pod) (bool, bool, error) {
if !ok {
return false, false, nil
}
shareProcessNamespace, err := strconv.ParseBool(raw)
shareProcessNamespace, err := parseutil.ParseBool(raw)
if err != nil {
return false, true, fmt.Errorf(
"invalid value %v for annotation %q, err=%w", raw, annotation, err)
Expand All @@ -791,7 +802,7 @@ func (a *Agent) setSecurityContext() (bool, error) {
return DefaultAgentSetSecurityContext, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) cacheEnable() (bool, error) {
Expand All @@ -800,7 +811,7 @@ func (a *Agent) cacheEnable() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) templateConfigExitOnRetryFailure() (bool, error) {
Expand All @@ -809,23 +820,33 @@ func (a *Agent) templateConfigExitOnRetryFailure() (bool, error) {
return DefaultTemplateConfigExitOnRetryFailure, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) templateConfigMaxConnectionsPerHost() (int64, error) {
raw, ok := a.Annotations[AnnotationTemplateConfigMaxConnectionsPerHost]
if !ok {
return 0, nil
}

return parseutil.ParseInt(raw)
}

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

return parseutil.ParseBool(raw)
}

func (a *Agent) getEnableQuit() (bool, error) {
raw, ok := a.Annotations[AnnotationAgentEnableQuit]
if !ok {
return DefaultEnableQuit, nil
}
return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

func (a *Agent) cachePersist(cacheEnabled bool) bool {
Expand All @@ -841,15 +862,15 @@ func (a *Agent) cacheExitOnErr() (bool, error) {
return false, nil
}

return strconv.ParseBool(raw)
return parseutil.ParseBool(raw)
}

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

// telemetryConfig accumulates the agent-telemetry annotations into a map which is
Expand Down
16 changes: 8 additions & 8 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentInject, "f", true},
{AnnotationAgentInject, "tRuE", false},
{AnnotationAgentInject, "fAlSe", false},
{AnnotationAgentInject, "", false},
{AnnotationAgentInject, "", true},

{AnnotationAgentPrePopulate, "true", true},
{AnnotationAgentPrePopulate, "false", true},
Expand All @@ -710,7 +710,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentPrePopulate, "f", true},
{AnnotationAgentPrePopulate, "tRuE", false},
{AnnotationAgentPrePopulate, "fAlSe", false},
{AnnotationAgentPrePopulate, "", false},
{AnnotationAgentPrePopulate, "", true},

{AnnotationAgentPrePopulateOnly, "true", true},
{AnnotationAgentPrePopulateOnly, "false", true},
Expand All @@ -722,7 +722,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentPrePopulateOnly, "f", true},
{AnnotationAgentPrePopulateOnly, "tRuE", false},
{AnnotationAgentPrePopulateOnly, "fAlSe", false},
{AnnotationAgentPrePopulateOnly, "", false},
{AnnotationAgentPrePopulateOnly, "", true},

{AnnotationVaultTLSSkipVerify, "true", true},
{AnnotationVaultTLSSkipVerify, "false", true},
Expand All @@ -734,7 +734,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationVaultTLSSkipVerify, "f", true},
{AnnotationVaultTLSSkipVerify, "tRuE", false},
{AnnotationVaultTLSSkipVerify, "fAlSe", false},
{AnnotationVaultTLSSkipVerify, "", false},
{AnnotationVaultTLSSkipVerify, "", true},

{AnnotationAgentRevokeOnShutdown, "true", true},
{AnnotationAgentRevokeOnShutdown, "false", true},
Expand All @@ -746,7 +746,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentRevokeOnShutdown, "f", true},
{AnnotationAgentRevokeOnShutdown, "tRuE", false},
{AnnotationAgentRevokeOnShutdown, "fAlSe", false},
{AnnotationAgentRevokeOnShutdown, "", false},
{AnnotationAgentRevokeOnShutdown, "", true},

{AnnotationAgentRevokeGrace, "5", true},
{AnnotationAgentRevokeGrace, "0", true},
Expand All @@ -768,12 +768,12 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentShareProcessNamespace, "FALSE", true},
{AnnotationAgentShareProcessNamespace, "tRuE", false},
{AnnotationAgentShareProcessNamespace, "fAlSe", false},
{AnnotationAgentShareProcessNamespace, "", false},
{AnnotationAgentShareProcessNamespace, "", true},

{AnnotationAgentSetSecurityContext, "true", true},
{AnnotationAgentSetSecurityContext, "false", true},
{AnnotationAgentSetSecurityContext, "secure", false},
{AnnotationAgentSetSecurityContext, "", false},
{AnnotationAgentSetSecurityContext, "", true},

{AnnotationAgentCacheEnable, "true", true},
{AnnotationAgentCacheEnable, "false", true},
Expand All @@ -785,7 +785,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentCacheEnable, "f", true},
{AnnotationAgentCacheEnable, "tRuE", false},
{AnnotationAgentCacheEnable, "fAlSe", false},
{AnnotationAgentCacheEnable, "", false},
{AnnotationAgentCacheEnable, "", true},

{AnnotationAgentAuthMinBackoff, "", true},
{AnnotationAgentAuthMinBackoff, "1s", true},
Expand Down
2 changes: 2 additions & 0 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type CachePersist struct {
type TemplateConfig struct {
ExitOnRetryFailure bool `json:"exit_on_retry_failure"`
StaticSecretRenderInterval string `json:"static_secret_render_interval,omitempty"`
MaxConnectionsPerHost int64 `json:"max_connections_per_host,omitempty"`
}

// Telemetry defines the configuration for agent telemetry in Vault Agent.
Expand Down Expand Up @@ -251,6 +252,7 @@ func (a *Agent) newConfig(init bool) ([]byte, error) {
TemplateConfig: &TemplateConfig{
ExitOnRetryFailure: a.VaultAgentTemplateConfig.ExitOnRetryFailure,
StaticSecretRenderInterval: a.VaultAgentTemplateConfig.StaticSecretRenderInterval,
MaxConnectionsPerHost: a.VaultAgentTemplateConfig.MaxConnectionsPerHost,
},
DisableIdleConnections: a.DisableIdleConnections,
DisableKeepAlives: a.DisableKeepAlives,
Expand Down
Loading

0 comments on commit 4c7876b

Please sign in to comment.