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

Add MaxConnectionsPerHost to Agent Injector #579

Merged
merged 13 commits into from
Jan 24, 2024
60 changes: 36 additions & 24 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,37 @@ 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"
)

const (
DefaultVaultImage = "hashicorp/vault:1.15.1"
DefaultVaultAuthType = "kubernetes"
DefaultVaultAuthPath = "auth/kubernetes"
DefaultAgentRunAsUser = 100
DefaultAgentRunAsGroup = 1000
DefaultAgentRunAsSameUser = false
DefaultAgentAllowPrivilegeEscalation = false
DefaultAgentDropCapabilities = "ALL"
DefaultAgentSetSecurityContext = true
DefaultAgentReadOnlyRoot = true
DefaultAgentCacheEnable = "false"
DefaultAgentCacheUseAutoAuthToken = "true"
DefaultAgentCacheListenerPort = "8200"
DefaultAgentCacheExitOnErr = false
DefaultAgentUseLeaderElector = false
DefaultAgentInjectToken = false
DefaultTemplateConfigExitOnRetryFailure = true
DefaultServiceAccountMount = "/var/run/secrets/vault.hashicorp.com/serviceaccount"
DefaultEnableQuit = false
DefaultAutoAuthEnableOnExit = false
DefaultVaultImage = "hashicorp/vault:1.15.1"
DefaultVaultAuthType = "kubernetes"
DefaultVaultAuthPath = "auth/kubernetes"
DefaultAgentRunAsUser = 100
DefaultAgentRunAsGroup = 1000
DefaultAgentRunAsSameUser = false
DefaultAgentAllowPrivilegeEscalation = false
DefaultAgentDropCapabilities = "ALL"
DefaultAgentSetSecurityContext = true
DefaultAgentReadOnlyRoot = true
DefaultAgentCacheEnable = "false"
DefaultAgentCacheUseAutoAuthToken = "true"
DefaultAgentCacheListenerPort = "8200"
DefaultAgentCacheExitOnErr = false
DefaultAgentUseLeaderElector = false
DefaultAgentInjectToken = false
DefaultTemplateConfigExitOnRetryFailure = true
DefaultTemplateConfigMaxConnectionsPerHost = 10
DefaultServiceAccountMount = "/var/run/secrets/vault.hashicorp.com/serviceaccount"
DefaultEnableQuit = false
DefaultAutoAuthEnableOnExit = false
)

// Agent is the top level structure holding all the
Expand Down Expand Up @@ -340,6 +341,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 +445,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 +509,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 +549,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
59 changes: 42 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,14 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationTemplateConfigStaticSecretRenderInterval] = cfg.StaticSecretRenderInterval
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationTemplateConfigMaxConnectionsPerHost]; !ok {
if cfg.MaxConnectionsPerHost == 0 {
cfg.MaxConnectionsPerHost = DefaultTemplateConfigMaxConnectionsPerHost
}

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 +677,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 +686,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 +695,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 +704,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 +713,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 +731,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 +747,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 +784,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 +806,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 +815,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 +824,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 DefaultTemplateConfigMaxConnectionsPerHost, 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 +866,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
Loading