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:
parent
9723462891
commit
958ccda6b1
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
2
go.sum
|
@ -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=
|
||||||
|
|
Loading…
Reference in New Issue