agent: Add implementation for injecting secrets as environment variables to vault agent cmd (#20739)

* added exec and env_template config/parsing

* add tests

* we can reuse ctconfig here

* do not create a non-nil map

* check defaults

* Apply suggestions from code review

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* first go of exec server

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* convert to list

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* convert to list

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* sig test

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* add failing example

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* refactor for config changes

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* add test for invalid signal

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* account for auth token changes

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* only start the runner once we have a token

* tests in diff branch

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* fix rename

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update command/agent/exec/exec.go

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* apply suggestions from code review

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* cleanup

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* remove unnecessary lock

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* refactor to use enum

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* dont block

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* handle default

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* make more explicit

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* cleanup

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* remove unused

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* remove unused file

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* remove test app

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* apply suggestions from code review

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* update comment

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* add changelog

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* new channel for exec server token

* wire to run with vault agent

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* watch for child process to exit on its own

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* block before returning

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>

---------

Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>
Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>
This commit is contained in:
Daniel Huckins 2023-05-25 09:23:56 -04:00 committed by GitHub
parent 9723462891
commit 958ccda6b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 11 deletions

View File

@ -6,6 +6,7 @@ package command
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -24,8 +25,17 @@ import (
"github.com/hashicorp/go-secure-stdlib/gatedwriter" "github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/reloadutil" "github.com/hashicorp/go-secure-stdlib/reloadutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/oklog/run"
"github.com/posener/complete"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"google.golang.org/grpc/test/bufconn"
"github.com/hashicorp/vault/api" "github.com/hashicorp/vault/api"
agentConfig "github.com/hashicorp/vault/command/agent/config" agentConfig "github.com/hashicorp/vault/command/agent/config"
"github.com/hashicorp/vault/command/agent/exec"
"github.com/hashicorp/vault/command/agent/template" "github.com/hashicorp/vault/command/agent/template"
"github.com/hashicorp/vault/command/agentproxyshared" "github.com/hashicorp/vault/command/agentproxyshared"
"github.com/hashicorp/vault/command/agentproxyshared/auth" "github.com/hashicorp/vault/command/agentproxyshared/auth"
@ -42,13 +52,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/version" "github.com/hashicorp/vault/version"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/oklog/run"
"github.com/posener/complete"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"google.golang.org/grpc/test/bufconn"
) )
var ( var (
@ -271,7 +274,7 @@ func (c *AgentCommand) Run(args []string) int {
"functionality, plan to move to Vault Proxy instead.") "functionality, plan to move to Vault Proxy instead.")
} }
// ctx and cancelFunc are passed to the AuthHandler, SinkServer, and // ctx and cancelFunc are passed to the AuthHandler, SinkServer, ExecServer and
// TemplateServer that periodically listen for ctx.Done() to fire and shut // TemplateServer that periodically listen for ctx.Done() to fire and shut
// down accordingly. // down accordingly.
ctx, cancelFunc := context.WithCancel(context.Background()) ctx, cancelFunc := context.WithCancel(context.Background())
@ -724,6 +727,14 @@ func (c *AgentCommand) Run(args []string) int {
ExitAfterAuth: config.ExitAfterAuth, ExitAfterAuth: config.ExitAfterAuth,
}) })
es := exec.NewServer(&exec.ServerConfig{
AgentConfig: c.config,
Namespace: templateNamespace,
Logger: c.logger.Named("exec.server"),
LogLevel: c.logger.GetLevel(),
LogWriter: c.logWriter,
})
g.Add(func() error { g.Add(func() error {
return ah.Run(ctx, method) return ah.Run(ctx, method)
}, func(error) { }, func(error) {
@ -778,6 +789,17 @@ func (c *AgentCommand) Run(args []string) int {
ts.Stop() ts.Stop()
}) })
g.Add(func() error {
return es.Run(ctx, ah.ExecTokenCh)
}, func(err error) {
// Let the lease cache know this is a shutdown; no need to evict
// everything
if leaseCache != nil {
leaseCache.SetShuttingDown(true)
}
cancelFunc()
})
} }
// Server configuration output // Server configuration output
@ -816,7 +838,12 @@ func (c *AgentCommand) Run(args []string) int {
if err := g.Run(); err != nil { if err := g.Run(); err != nil {
c.logger.Error("runtime error encountered", "error", err) c.logger.Error("runtime error encountered", "error", err)
c.UI.Error("Error encountered during run, refer to logs for more details.") c.UI.Error("Error encountered during run, refer to logs for more details.")
exitCode = 1 var processExitError *exec.ProcessExitError
if errors.As(err, &processExitError) {
exitCode = processExitError.ExitCode
} else {
exitCode = 1
}
} }
c.notifySystemd(systemd.SdNotifyStopping) c.notifySystemd(systemd.SdNotifyStopping)
return exitCode return exitCode

View File

@ -99,6 +99,7 @@ func (s *Server) Run(ctx context.Context, incomingVaultToken chan string) error
if len(s.config.AgentConfig.EnvTemplates) == 0 || s.config.AgentConfig.Exec == nil { if len(s.config.AgentConfig.EnvTemplates) == 0 || s.config.AgentConfig.Exec == nil {
s.logger.Info("no env templates or exec config, exiting") s.logger.Info("no env templates or exec config, exiting")
<-ctx.Done()
return nil return nil
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/armon/go-metrics" "github.com/armon/go-metrics"
"github.com/hashicorp/go-hclog" "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api" "github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/helper/jsonutil"
) )
@ -52,6 +53,7 @@ type AuthConfig struct {
type AuthHandler struct { type AuthHandler struct {
OutputCh chan string OutputCh chan string
TemplateTokenCh chan string TemplateTokenCh chan string
ExecTokenCh chan string
token string token string
userAgent string userAgent string
metricsSignifier string metricsSignifier string
@ -63,6 +65,7 @@ type AuthHandler struct {
minBackoff time.Duration minBackoff time.Duration
enableReauthOnNewCredentials bool enableReauthOnNewCredentials bool
enableTemplateTokenCh bool enableTemplateTokenCh bool
enableExecTokenCh bool
exitOnError bool exitOnError bool
} }
@ -81,6 +84,7 @@ type AuthHandlerConfig struct {
MetricsSignifier string MetricsSignifier string
EnableReauthOnNewCredentials bool EnableReauthOnNewCredentials bool
EnableTemplateTokenCh bool EnableTemplateTokenCh bool
EnableExecTokenCh bool
ExitOnError bool ExitOnError bool
} }
@ -90,6 +94,7 @@ func NewAuthHandler(conf *AuthHandlerConfig) *AuthHandler {
// has been shut down, during agent/proxy shutdown, we won't block // has been shut down, during agent/proxy shutdown, we won't block
OutputCh: make(chan string, 1), OutputCh: make(chan string, 1),
TemplateTokenCh: make(chan string, 1), TemplateTokenCh: make(chan string, 1),
ExecTokenCh: make(chan string, 1),
token: conf.Token, token: conf.Token,
logger: conf.Logger, logger: conf.Logger,
client: conf.Client, client: conf.Client,
@ -99,6 +104,7 @@ func NewAuthHandler(conf *AuthHandlerConfig) *AuthHandler {
maxBackoff: conf.MaxBackoff, maxBackoff: conf.MaxBackoff,
enableReauthOnNewCredentials: conf.EnableReauthOnNewCredentials, enableReauthOnNewCredentials: conf.EnableReauthOnNewCredentials,
enableTemplateTokenCh: conf.EnableTemplateTokenCh, enableTemplateTokenCh: conf.EnableTemplateTokenCh,
enableExecTokenCh: conf.EnableExecTokenCh,
exitOnError: conf.ExitOnError, exitOnError: conf.ExitOnError,
userAgent: conf.UserAgent, userAgent: conf.UserAgent,
metricsSignifier: conf.MetricsSignifier, metricsSignifier: conf.MetricsSignifier,
@ -143,6 +149,7 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
am.Shutdown() am.Shutdown()
close(ah.OutputCh) close(ah.OutputCh)
close(ah.TemplateTokenCh) close(ah.TemplateTokenCh)
close(ah.ExecTokenCh)
ah.logger.Info("auth handler stopped") ah.logger.Info("auth handler stopped")
}() }()
@ -342,6 +349,9 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
if ah.enableTemplateTokenCh { if ah.enableTemplateTokenCh {
ah.TemplateTokenCh <- string(wrappedResp) ah.TemplateTokenCh <- string(wrappedResp)
} }
if ah.enableExecTokenCh {
ah.ExecTokenCh <- string(wrappedResp)
}
am.CredSuccess() am.CredSuccess()
backoffCfg.reset() backoffCfg.reset()
@ -397,6 +407,9 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
if ah.enableTemplateTokenCh { if ah.enableTemplateTokenCh {
ah.TemplateTokenCh <- token ah.TemplateTokenCh <- token
} }
if ah.enableExecTokenCh {
ah.ExecTokenCh <- token
}
tokenType := secret.Data["type"].(string) tokenType := secret.Data["type"].(string)
if tokenType == "batch" { if tokenType == "batch" {
@ -428,6 +441,9 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
if ah.enableTemplateTokenCh { if ah.enableTemplateTokenCh {
ah.TemplateTokenCh <- secret.Auth.ClientToken ah.TemplateTokenCh <- secret.Auth.ClientToken
} }
if ah.enableExecTokenCh {
ah.ExecTokenCh <- secret.Auth.ClientToken
}
} }
am.CredSuccess() am.CredSuccess()

2
go.sum
View File

@ -2914,8 +2914,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20230519143937-03e91628a987 h1:3xJIFvzUFbu4ls0BTBYcgbCGhA63eAOEMxIHugyXJqA=
golang.org/x/exp v0.0.0-20230519143937-03e91628a987/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE= golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE=