VAULT-17292 CE portion of changes (#24667)

* VAULT-17292 CE portion of changes

* VAULT-17292 docs

* VAULT-17292 changelog
This commit is contained in:
Violet Hynes 2024-01-04 13:01:38 -05:00 committed by GitHub
parent ade75bcf00
commit a649d2b9a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 106 additions and 23 deletions

6
changelog/24667.txt Normal file
View File

@ -0,0 +1,6 @@
```release-note:improvement
agent: Added new namespace top level configuration parameter, which can be used to make requests made by Agent to go to that namespace.
```
```release-note:improvement
proxy: Added new namespace top level configuration parameter, and prepend_configured_namespace API Proxy configuration parameter, which can be used to make requests made to Proxy get proxied to that namespace.
```

View File

@ -309,14 +309,25 @@ func (c *AgentCommand) Run(args []string) int {
} }
c.metricsHelper = metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled) c.metricsHelper = metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled)
var templateNamespace string
// This indicates whether the namespace for the client has been set by environment variable.
// If it has, we don't touch it
namespaceSetByEnvironmentVariable := client.Namespace() != ""
if !namespaceSetByEnvironmentVariable && config.Vault != nil && config.Vault.Namespace != "" {
client.SetNamespace(config.Vault.Namespace)
}
var method auth.AuthMethod var method auth.AuthMethod
var sinks []*sink.SinkConfig var sinks []*sink.SinkConfig
var templateNamespace string
if config.AutoAuth != nil { if config.AutoAuth != nil {
if client.Headers().Get(consts.NamespaceHeaderName) == "" && config.AutoAuth.Method.Namespace != "" { // Note: This will only set namespace header to the value in config.AutoAuth.Method.Namespace
// only if it hasn't been set by config.Vault.Namespace above. In that case, the config value
// present at config.AutoAuth.Method.Namespace will still be used for auto-auth.
if !namespaceSetByEnvironmentVariable && config.AutoAuth.Method.Namespace != "" {
client.SetNamespace(config.AutoAuth.Method.Namespace) client.SetNamespace(config.AutoAuth.Method.Namespace)
} }
templateNamespace = client.Headers().Get(consts.NamespaceHeaderName) templateNamespace = client.Namespace()
sinkClient, err := client.CloneWithHeaders() sinkClient, err := client.CloneWithHeaders()
if err != nil { if err != nil {
@ -707,6 +718,11 @@ func (c *AgentCommand) Run(args []string) int {
return 1 return 1
} }
// Override the set namespace with the auto-auth specific namespace
if !namespaceSetByEnvironmentVariable && config.AutoAuth.Method.Namespace != "" {
ahClient.SetNamespace(config.AutoAuth.Method.Namespace)
}
if config.DisableIdleConnsAutoAuth { if config.DisableIdleConnsAutoAuth {
ahClient.SetMaxIdleConnections(-1) ahClient.SetMaxIdleConnections(-1)
} }

View File

@ -91,6 +91,7 @@ type Vault struct {
ClientCert string `hcl:"client_cert"` ClientCert string `hcl:"client_cert"`
ClientKey string `hcl:"client_key"` ClientKey string `hcl:"client_key"`
TLSServerName string `hcl:"tls_server_name"` TLSServerName string `hcl:"tls_server_name"`
Namespace string `hcl:"namespace"`
Retry *Retry `hcl:"retry"` Retry *Retry `hcl:"retry"`
} }

View File

@ -262,7 +262,7 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
} }
if ah.wrapTTL > 0 { if ah.wrapTTL > 0 {
wrapClient, err := clientToUse.Clone() wrapClient, err := clientToUse.CloneWithHeaders()
if err != nil { if err != nil {
ah.logger.Error("error creating client for wrapped call", "error", err, "backoff", backoffCfg) ah.logger.Error("error creating client for wrapped call", "error", err, "backoff", backoffCfg)
metrics.IncrCounter([]string{ah.metricsSignifier, "auth", "failure"}, 1) metrics.IncrCounter([]string{ah.metricsSignifier, "auth", "failure"}, 1)
@ -289,7 +289,7 @@ func (ah *AuthHandler) Run(ctx context.Context, am AuthMethod) error {
isTokenFileMethod = path == "auth/token/lookup-self" isTokenFileMethod = path == "auth/token/lookup-self"
if isTokenFileMethod { if isTokenFileMethod {
token, _ := data["token"].(string) token, _ := data["token"].(string)
lookupSelfClient, err := clientToUse.Clone() lookupSelfClient, err := clientToUse.CloneWithHeaders()
if err != nil { if err != nil {
ah.logger.Error("failed to clone client to perform token lookup") ah.logger.Error("failed to clone client to perform token lookup")
return err return err

View File

@ -12,6 +12,7 @@ import (
hclog "github.com/hashicorp/go-hclog" hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/go-retryablehttp"
"github.com/hashicorp/vault/api" "github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/http" "github.com/hashicorp/vault/http"
) )
@ -41,6 +42,10 @@ type APIProxy struct {
lastIndexStates []string lastIndexStates []string
userAgentString string userAgentString string
userAgentStringFunction func(string) string userAgentStringFunction func(string) string
// clientNamespace is a one-time set representation of the namespace of the client
// (i.e. client.Namespace()) to avoid repeated calls and lock usage.
clientNamespace string
prependConfiguredNamespace bool
} }
var _ Proxier = &APIProxy{} var _ Proxier = &APIProxy{}
@ -56,6 +61,9 @@ type APIProxyConfig struct {
// UserAgentStringFunction is the function to transform the proxied client's // UserAgentStringFunction is the function to transform the proxied client's
// user agent into one that includes Vault-specific information. // user agent into one that includes Vault-specific information.
UserAgentStringFunction func(string) string UserAgentStringFunction func(string) string
// PrependConfiguredNamespace configures whether the client's namespace
// should be prepended to proxied requests
PrependConfiguredNamespace bool
} }
func NewAPIProxy(config *APIProxyConfig) (Proxier, error) { func NewAPIProxy(config *APIProxyConfig) (Proxier, error) {
@ -69,6 +77,8 @@ func NewAPIProxy(config *APIProxyConfig) (Proxier, error) {
whenInconsistentAction: config.WhenInconsistentAction, whenInconsistentAction: config.WhenInconsistentAction,
userAgentString: config.UserAgentString, userAgentString: config.UserAgentString,
userAgentStringFunction: config.UserAgentStringFunction, userAgentStringFunction: config.UserAgentStringFunction,
prependConfiguredNamespace: config.PrependConfiguredNamespace,
clientNamespace: namespace.Canonicalize(config.Client.Namespace()),
}, nil }, nil
} }
@ -102,6 +112,11 @@ func (ap *APIProxy) Send(ctx context.Context, req *SendRequest) (*SendResponse,
} }
client.SetHeaders(req.Request.Header) client.SetHeaders(req.Request.Header)
if ap.prependConfiguredNamespace && ap.clientNamespace != "" {
currentNamespace := namespace.Canonicalize(client.Namespace())
newNamespace := namespace.Canonicalize(ap.clientNamespace + currentNamespace)
client.SetNamespace(newNamespace)
}
fwReq := client.NewRequest(req.Request.Method, req.Request.URL.Path) fwReq := client.NewRequest(req.Request.Method, req.Request.URL.Path)
fwReq.BodyBytes = req.RequestBody fwReq.BodyBytes = req.RequestBody

View File

@ -284,10 +284,21 @@ func (c *ProxyCommand) Run(args []string) int {
} }
c.metricsHelper = metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled) c.metricsHelper = metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled)
// This indicates whether the namespace for the client has been set by environment variable.
// If it has, we don't touch it
namespaceSetByEnvironmentVariable := client.Namespace() != ""
if !namespaceSetByEnvironmentVariable && config.Vault != nil && config.Vault.Namespace != "" {
client.SetNamespace(config.Vault.Namespace)
}
var method auth.AuthMethod var method auth.AuthMethod
var sinks []*sink.SinkConfig var sinks []*sink.SinkConfig
if config.AutoAuth != nil { if config.AutoAuth != nil {
if client.Headers().Get(consts.NamespaceHeaderName) == "" && config.AutoAuth.Method.Namespace != "" { // Note: This will only set namespace header to the value in config.AutoAuth.Method.Namespace
// only if it hasn't been set by config.Vault.Namespace above. In that case, the config value
// present at config.AutoAuth.Method.Namespace will still be used for auto-auth.
if !namespaceSetByEnvironmentVariable && config.AutoAuth.Method.Namespace != "" {
client.SetNamespace(config.AutoAuth.Method.Namespace) client.SetNamespace(config.AutoAuth.Method.Namespace)
} }
@ -427,6 +438,7 @@ func (c *ProxyCommand) Run(args []string) int {
WhenInconsistentAction: whenInconsistent, WhenInconsistentAction: whenInconsistent,
UserAgentStringFunction: useragent.ProxyStringWithProxiedUserAgent, UserAgentStringFunction: useragent.ProxyStringWithProxiedUserAgent,
UserAgentString: useragent.ProxyAPIProxyString(), UserAgentString: useragent.ProxyAPIProxyString(),
PrependConfiguredNamespace: config.APIProxy != nil && config.APIProxy.PrependConfiguredNamespace,
}) })
if err != nil { if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API proxy: %v", err)) c.UI.Error(fmt.Sprintf("Error creating API proxy: %v", err))
@ -686,6 +698,11 @@ func (c *ProxyCommand) Run(args []string) int {
return 1 return 1
} }
// Override the set namespace with the auto-auth specific namespace
if !namespaceSetByEnvironmentVariable && config.AutoAuth.Method.Namespace != "" {
ahClient.SetNamespace(config.AutoAuth.Method.Namespace)
}
if config.DisableIdleConnsAutoAuth { if config.DisableIdleConnsAutoAuth {
ahClient.SetMaxIdleConnections(-1) ahClient.SetMaxIdleConnections(-1)
} }

View File

@ -77,6 +77,7 @@ type Vault struct {
ClientCert string `hcl:"client_cert"` ClientCert string `hcl:"client_cert"`
ClientKey string `hcl:"client_key"` ClientKey string `hcl:"client_key"`
TLSServerName string `hcl:"tls_server_name"` TLSServerName string `hcl:"tls_server_name"`
Namespace string `hcl:"namespace"`
Retry *Retry `hcl:"retry"` Retry *Retry `hcl:"retry"`
} }
@ -97,6 +98,7 @@ type APIProxy struct {
ForceAutoAuthToken bool `hcl:"-"` ForceAutoAuthToken bool `hcl:"-"`
EnforceConsistency string `hcl:"enforce_consistency"` EnforceConsistency string `hcl:"enforce_consistency"`
WhenInconsistent string `hcl:"when_inconsistent"` WhenInconsistent string `hcl:"when_inconsistent"`
PrependConfiguredNamespace bool `hcl:"prepend_configured_namespace"`
} }
// Cache contains any configuration needed for Cache mode // Cache contains any configuration needed for Cache mode

View File

@ -214,6 +214,12 @@ configuration entries:
connecting via TLS. This value can be overridden by setting the connecting via TLS. This value can be overridden by setting the
`VAULT_TLS_SERVER_NAME` environment variable. `VAULT_TLS_SERVER_NAME` environment variable.
- `namespace` `(string: <optional>)` - Namespace to use for all of Vault Agent's
requests to Vault. This can also be specified by command line or environment variable.
The order of precedence is: this setting lowest, followed by the environment variable
`VAULT_NAMESPACE`, and then the highest precedence command-line option `-namespace`.
If none of these are specified, defaults to the root namespace.
#### retry stanza #### retry stanza
The `vault` stanza may contain a `retry` stanza that controls how failing Vault The `vault` stanza may contain a `retry` stanza that controls how failing Vault

View File

@ -128,6 +128,10 @@ These are common configuration values that live within the `method` block:
If none of these are specified, defaults to the root namespace. If none of these are specified, defaults to the root namespace.
Note that because sink response wrapping and templating are also based Note that because sink response wrapping and templating are also based
on the client created by auto-auth, they use the same namespace. on the client created by auto-auth, they use the same namespace.
If specified alongside the `namespace` option in the Vault Stanza of
[Vault Agent](/vault/docs/agent-and-proxy/agent#vault-stanza) or
[Vault Proxy](/vault/docs/agent-and-proxy/proxy#vault-stanza), that
configuration will take precedence on everything except auto-auth.
- `wrap_ttl` `(string or integer: optional)` - If specified, the written token - `wrap_ttl` `(string or integer: optional)` - If specified, the written token
will be response-wrapped by auto-auth. This is more secure than wrapping by will be response-wrapped by auto-auth. This is more secure than wrapping by

View File

@ -55,6 +55,16 @@ configuration will be overridden and the token in the request will be used to
forward the request to the Vault server. If set to `"force"` Proxy will use the forward the request to the Vault server. If set to `"force"` Proxy will use the
auto-auth token, overwriting the attached Vault token if set. auto-auth token, overwriting the attached Vault token if set.
- `prepend_configured_namespace` `(bool: false)` - If set, when Proxy has a
namespace configured, such as through the
[Vault stanza](/vault/docs/agent-and-proxy/proxy#vault-stanza), all requests
proxied to Vault will have the configured namespace prepended to the namespace
header. If Proxy's namespace is set to `ns1` and Proxy is sent a request with the
namespace `ns2`, the request will go to the `ns1/ns2` namespace. Likewise, if Proxy
is sent a request without a namespace, the request will go to the `ns1` namespace.
In essence, what this means is that all proxied requests must go to the configured
namespace or to its child namespaces.
The following two `api_proxy` options are only useful when making requests to a Vault The following two `api_proxy` options are only useful when making requests to a Vault
Enterprise cluster, and are documented as part of its Enterprise cluster, and are documented as part of its
[Eventual Consistency](/vault/docs/enterprise/consistency#vault-agent-and-consistency-headers) [Eventual Consistency](/vault/docs/enterprise/consistency#vault-agent-and-consistency-headers)

View File

@ -188,6 +188,12 @@ be overridden by setting the `VAULT_SKIP_VERIFY` environment variable.
connecting via TLS. This value can be overridden by setting the connecting via TLS. This value can be overridden by setting the
`VAULT_TLS_SERVER_NAME` environment variable. `VAULT_TLS_SERVER_NAME` environment variable.
- `namespace` `(string: <optional>)` - Namespace to use for all of Vault Proxy's
requests to Vault. This can also be specified by command line or environment variable.
The order of precedence is: this setting lowest, followed by the environment variable
`VAULT_NAMESPACE`, and then the highest precedence command-line option `-namespace`.
If none of these are specified, defaults to the root namespace.
#### retry stanza #### retry stanza
The `vault` stanza may contain a `retry` stanza that controls how failing Vault The `vault` stanza may contain a `retry` stanza that controls how failing Vault