mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Chroot Listener (#22304)
* Initial oss-patch apply * Added changelog * Renamed changelog txt * Added the imports to the handler file * Added a check that no two ports are the same, and modified changelog * Edited go sum entry * Tidy up using go mod * Use strutil instead * Revert go sum and go mod * Revert sdk go sum * Edited go.sum to before * Edited go.sum again to initial * Revert changes
This commit is contained in:
3
changelog/22304.txt
Normal file
3
changelog/22304.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
core: add a listener configuration "chroot_namespace" that forces requests to use a namespace hierarchy
|
||||||
|
```
|
||||||
@@ -789,7 +789,8 @@ func testConfig_Sanitized(t *testing.T) {
|
|||||||
"listeners": []interface{}{
|
"listeners": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"config": map[string]interface{}{
|
"config": map[string]interface{}{
|
||||||
"address": "127.0.0.1:443",
|
"address": "127.0.0.1:443",
|
||||||
|
"chroot_namespace": "admin/",
|
||||||
},
|
},
|
||||||
"type": "tcp",
|
"type": "tcp",
|
||||||
},
|
},
|
||||||
@@ -882,6 +883,7 @@ listener "tcp" {
|
|||||||
proxy_api {
|
proxy_api {
|
||||||
enable_quit = true
|
enable_quit = true
|
||||||
}
|
}
|
||||||
|
chroot_namespace = "admin"
|
||||||
}`))
|
}`))
|
||||||
|
|
||||||
config := Config{
|
config := Config{
|
||||||
@@ -926,6 +928,7 @@ listener "tcp" {
|
|||||||
EnableQuit: true,
|
EnableQuit: true,
|
||||||
},
|
},
|
||||||
CustomResponseHeaders: DefaultCustomHeaders,
|
CustomResponseHeaders: DefaultCustomHeaders,
|
||||||
|
ChrootNamespace: "admin/",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ cluster_addr = "top_level_cluster_addr"
|
|||||||
|
|
||||||
listener "tcp" {
|
listener "tcp" {
|
||||||
address = "127.0.0.1:443"
|
address = "127.0.0.1:443"
|
||||||
|
chroot_namespace="admin/"
|
||||||
}
|
}
|
||||||
|
|
||||||
backend "consul" {
|
backend "consul" {
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -1815,6 +1815,7 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
|
|||||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
|
||||||
|
github.com/hashicorp/go-set v0.1.13/go.mod h1:0/D+R4MFUzJ6XmvjU7liXtznF1eQDxh84GJlhXw+lvo=
|
||||||
github.com/hashicorp/go-slug v0.11.1 h1:c6lLdQnlhUWbS5I7hw8SvfymoFuy6EmiFDedy6ir994=
|
github.com/hashicorp/go-slug v0.11.1 h1:c6lLdQnlhUWbS5I7hw8SvfymoFuy6EmiFDedy6ir994=
|
||||||
github.com/hashicorp/go-slug v0.11.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
|
github.com/hashicorp/go-slug v0.11.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
@@ -2620,6 +2621,7 @@ github.com/sethvargo/go-limiter v0.7.1/go.mod h1:C0kbSFbiriE5k2FFOe18M1YZbAR2Fiw
|
|||||||
github.com/shirou/gopsutil/v3 v3.22.6 h1:FnHOFOh+cYAM0C30P+zysPISzlknLC5Z1G4EAElznfQ=
|
github.com/shirou/gopsutil/v3 v3.22.6 h1:FnHOFOh+cYAM0C30P+zysPISzlknLC5Z1G4EAElznfQ=
|
||||||
github.com/shirou/gopsutil/v3 v3.22.6/go.mod h1:EdIubSnZhbAvBS1yJ7Xi+AShB/hxwLHOMz4MCYz7yMs=
|
github.com/shirou/gopsutil/v3 v3.22.6/go.mod h1:EdIubSnZhbAvBS1yJ7Xi+AShB/hxwLHOMz4MCYz7yMs=
|
||||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||||
|
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
|
|||||||
@@ -358,6 +358,7 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
} else {
|
} else {
|
||||||
ctx, cancelFunc = context.WithTimeout(ctx, maxRequestDuration)
|
ctx, cancelFunc = context.WithTimeout(ctx, maxRequestDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if maxRequestSize < 0, no need to set context value
|
// if maxRequestSize < 0, no need to set context value
|
||||||
// Add a size limiter if desired
|
// Add a size limiter if desired
|
||||||
if maxRequestSize > 0 {
|
if maxRequestSize > 0 {
|
||||||
@@ -379,11 +380,14 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
nw.Header().Set("X-Vault-Hostname", hostname)
|
nw.Header().Set("X-Vault-Hostname", hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract the namespace from the header before we modify it
|
||||||
|
ns := r.Header.Get(consts.NamespaceHeaderName)
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(r.URL.Path, "/v1/"):
|
case strings.HasPrefix(r.URL.Path, "/v1/"):
|
||||||
newR, status := adjustRequest(core, r)
|
// Setting the namespace in the header to be included in the error message
|
||||||
|
newR, status, err := adjustRequest(core, props.ListenerConfig, r)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
respondError(nw, status, nil)
|
respondError(nw, status, err)
|
||||||
cancelFunc()
|
cancelFunc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -434,7 +438,6 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Setting the namespace in the header to be included in the error message
|
// Setting the namespace in the header to be included in the error message
|
||||||
ns := r.Header.Get(consts.NamespaceHeaderName)
|
|
||||||
if ns != "" {
|
if ns != "" {
|
||||||
nw.Header().Set(consts.NamespaceHeaderName, ns)
|
nw.Header().Set(consts.NamespaceHeaderName, ns)
|
||||||
}
|
}
|
||||||
|
|||||||
16
http/handler_stubs_oss.go
Normal file
16
http/handler_stubs_oss.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build !enterprise
|
||||||
|
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/internalshared/configutil"
|
||||||
|
"github.com/hashicorp/vault/vault"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/hashicorp/vault/tools/stubmaker
|
||||||
|
|
||||||
|
func adjustRequest(c *vault.Core, listener *configutil.Listener, r *http.Request) (*http.Request, int, error) {
|
||||||
|
return r, 0, nil
|
||||||
|
}
|
||||||
@@ -20,10 +20,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
adjustRequest = func(c *vault.Core, r *http.Request) (*http.Request, int) {
|
|
||||||
return r, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
genericWrapping = func(core *vault.Core, in http.Handler, props *vault.HandlerProperties) http.Handler {
|
genericWrapping = func(core *vault.Core, in http.Handler, props *vault.HandlerProperties) http.Handler {
|
||||||
// Wrap the help wrapped handler with another layer with a generic
|
// Wrap the help wrapped handler with another layer with a generic
|
||||||
// handler
|
// handler
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/hashicorp/go-sockaddr/template"
|
"github.com/hashicorp/go-sockaddr/template"
|
||||||
"github.com/hashicorp/hcl"
|
"github.com/hashicorp/hcl"
|
||||||
"github.com/hashicorp/hcl/hcl/ast"
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListenerTelemetry struct {
|
type ListenerTelemetry struct {
|
||||||
@@ -118,6 +119,10 @@ type Listener struct {
|
|||||||
// Custom Http response headers
|
// Custom Http response headers
|
||||||
CustomResponseHeaders map[string]map[string]string `hcl:"-"`
|
CustomResponseHeaders map[string]map[string]string `hcl:"-"`
|
||||||
CustomResponseHeadersRaw interface{} `hcl:"custom_response_headers"`
|
CustomResponseHeadersRaw interface{} `hcl:"custom_response_headers"`
|
||||||
|
|
||||||
|
// ChrootNamespace will prepend the specified namespace to requests
|
||||||
|
ChrootNamespaceRaw interface{} `hcl:"chroot_namespace"`
|
||||||
|
ChrootNamespace string `hcl:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgentAPI allows users to select which parts of the Agent API they want enabled.
|
// AgentAPI allows users to select which parts of the Agent API they want enabled.
|
||||||
@@ -201,7 +206,6 @@ func ParseListeners(result *SharedConfig, list *ast.ObjectList) error {
|
|||||||
return multierror.Prefix(fmt.Errorf("unsupported listener role %q", l.Role), fmt.Sprintf("listeners.%d:", i))
|
return multierror.Prefix(fmt.Errorf("unsupported listener role %q", l.Role), fmt.Sprintf("listeners.%d:", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request Parameters
|
// Request Parameters
|
||||||
{
|
{
|
||||||
if l.MaxRequestSizeRaw != nil {
|
if l.MaxRequestSizeRaw != nil {
|
||||||
@@ -423,6 +427,20 @@ func ParseListeners(result *SharedConfig, list *ast.ObjectList) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.Listeners = append(result.Listeners, &l)
|
result.Listeners = append(result.Listeners, &l)
|
||||||
|
|
||||||
|
// Chroot Namespace
|
||||||
|
{
|
||||||
|
// If a valid ChrootNamespace value exists, then canonicalize the namespace value
|
||||||
|
if l.ChrootNamespaceRaw != nil {
|
||||||
|
if l.ChrootNamespace, err = parseutil.ParseString(l.ChrootNamespaceRaw); err != nil {
|
||||||
|
return multierror.Prefix(fmt.Errorf("invalid value for chroot_namespace: %w", err), fmt.Sprintf("listeners.%d", i))
|
||||||
|
} else {
|
||||||
|
l.ChrootNamespace = namespace.Canonicalize(l.ChrootNamespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.ChrootNamespaceRaw = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ require (
|
|||||||
github.com/hashicorp/go-secure-stdlib/password v0.1.1
|
github.com/hashicorp/go-secure-stdlib/password v0.1.1
|
||||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2
|
||||||
|
github.com/hashicorp/go-set v0.1.13
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2
|
github.com/hashicorp/go-sockaddr v1.0.2
|
||||||
github.com/hashicorp/go-uuid v1.0.3
|
github.com/hashicorp/go-uuid v1.0.3
|
||||||
github.com/hashicorp/go-version v1.6.0
|
github.com/hashicorp/go-version v1.6.0
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
|
|||||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
|
||||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
|
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
|
||||||
|
github.com/hashicorp/go-set v0.1.13 h1:k1B5goY3c7OKEzpK+gwAhJexxzAJwDN8kId8YvWrihA=
|
||||||
|
github.com/hashicorp/go-set v0.1.13/go.mod h1:0/D+R4MFUzJ6XmvjU7liXtznF1eQDxh84GJlhXw+lvo=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
@@ -231,6 +233,7 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4
|
|||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import (
|
|||||||
"github.com/hashicorp/vault/api"
|
"github.com/hashicorp/vault/api"
|
||||||
dockhelper "github.com/hashicorp/vault/sdk/helper/docker"
|
dockhelper "github.com/hashicorp/vault/sdk/helper/docker"
|
||||||
"github.com/hashicorp/vault/sdk/helper/logging"
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/strutil"
|
||||||
"github.com/hashicorp/vault/sdk/helper/testcluster"
|
"github.com/hashicorp/vault/sdk/helper/testcluster"
|
||||||
uberAtomic "go.uber.org/atomic"
|
uberAtomic "go.uber.org/atomic"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
@@ -479,6 +480,7 @@ type DockerClusterNode struct {
|
|||||||
ImageTag string
|
ImageTag string
|
||||||
DataVolumeName string
|
DataVolumeName string
|
||||||
cleanupVolume func()
|
cleanupVolume func()
|
||||||
|
AllClients []*api.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *DockerClusterNode) TLSConfig() *tls.Config {
|
func (n *DockerClusterNode) TLSConfig() *tls.Config {
|
||||||
@@ -506,6 +508,30 @@ func (n *DockerClusterNode) APIClient() *api.Client {
|
|||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *DockerClusterNode) APIClientN(listenerNumber int) (*api.Client, error) {
|
||||||
|
// We clone to ensure that whenever this method is called, the caller gets
|
||||||
|
// back a pristine client, without e.g. any namespace or token changes that
|
||||||
|
// might pollute a shared client. We clone the config instead of the
|
||||||
|
// client because (1) Client.clone propagates the replicationStateStore and
|
||||||
|
// the httpClient pointers, (2) it doesn't copy the tlsConfig at all, and
|
||||||
|
// (3) if clone returns an error, it doesn't feel as appropriate to panic
|
||||||
|
// below. Who knows why clone might return an error?
|
||||||
|
if listenerNumber >= len(n.AllClients) {
|
||||||
|
return nil, fmt.Errorf("invalid listener number %d", listenerNumber)
|
||||||
|
}
|
||||||
|
cfg := n.AllClients[listenerNumber].CloneConfig()
|
||||||
|
client, err := api.NewClient(cfg)
|
||||||
|
if err != nil {
|
||||||
|
// It seems fine to panic here, since this should be the same input
|
||||||
|
// we provided to NewClient when we were setup, and we didn't panic then.
|
||||||
|
// Better not to completely ignore the error though, suppose there's a
|
||||||
|
// bug in CloneConfig?
|
||||||
|
panic(fmt.Sprintf("NewClient error on cloned config: %v", err))
|
||||||
|
}
|
||||||
|
client.SetToken(n.Cluster.rootToken)
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewAPIClient creates and configures a Vault API client to communicate with
|
// NewAPIClient creates and configures a Vault API client to communicate with
|
||||||
// the running Vault Cluster for this DockerClusterNode
|
// the running Vault Cluster for this DockerClusterNode
|
||||||
func (n *DockerClusterNode) apiConfig() (*api.Config, error) {
|
func (n *DockerClusterNode) apiConfig() (*api.Config, error) {
|
||||||
@@ -544,6 +570,20 @@ func (n *DockerClusterNode) newAPIClient() (*api.Client, error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *DockerClusterNode) newAPIClientForAddress(address string) (*api.Client, error) {
|
||||||
|
config, err := n.apiConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.Address = fmt.Sprintf("https://%s", address)
|
||||||
|
client, err := api.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client.SetToken(n.Cluster.GetRootToken())
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup kills the container of the node and deletes its data volume
|
// Cleanup kills the container of the node and deletes its data volume
|
||||||
func (n *DockerClusterNode) Cleanup() {
|
func (n *DockerClusterNode) Cleanup() {
|
||||||
n.cleanup()
|
n.cleanup()
|
||||||
@@ -563,6 +603,17 @@ func (n *DockerClusterNode) cleanup() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *DockerClusterNode) createDefaultListenerConfig() map[string]interface{} {
|
||||||
|
return map[string]interface{}{"tcp": map[string]interface{}{
|
||||||
|
"address": fmt.Sprintf("%s:%d", "0.0.0.0", 8200),
|
||||||
|
"tls_cert_file": "/vault/config/cert.pem",
|
||||||
|
"tls_key_file": "/vault/config/key.pem",
|
||||||
|
"telemetry": map[string]interface{}{
|
||||||
|
"unauthenticated_metrics_access": true,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOptions) error {
|
func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOptions) error {
|
||||||
if n.DataVolumeName == "" {
|
if n.DataVolumeName == "" {
|
||||||
vol, err := n.DockerAPI.VolumeCreate(ctx, volume.CreateOptions{})
|
vol, err := n.DockerAPI.VolumeCreate(ctx, volume.CreateOptions{})
|
||||||
@@ -575,16 +626,25 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
vaultCfg := map[string]interface{}{}
|
vaultCfg := map[string]interface{}{}
|
||||||
vaultCfg["listener"] = map[string]interface{}{
|
var listenerConfig []map[string]interface{}
|
||||||
"tcp": map[string]interface{}{
|
listenerConfig = append(listenerConfig, n.createDefaultListenerConfig())
|
||||||
"address": fmt.Sprintf("%s:%d", "0.0.0.0", 8200),
|
ports := []string{"8200/tcp", "8201/tcp"}
|
||||||
"tls_cert_file": "/vault/config/cert.pem",
|
|
||||||
"tls_key_file": "/vault/config/key.pem",
|
if opts.VaultNodeConfig != nil && opts.VaultNodeConfig.AdditionalListeners != nil {
|
||||||
"telemetry": map[string]interface{}{
|
for _, config := range opts.VaultNodeConfig.AdditionalListeners {
|
||||||
"unauthenticated_metrics_access": true,
|
cfg := n.createDefaultListenerConfig()
|
||||||
},
|
listener := cfg["tcp"].(map[string]interface{})
|
||||||
},
|
listener["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port)
|
||||||
|
listener["chroot_namespace"] = config.ChrootNamespace
|
||||||
|
listenerConfig = append(listenerConfig, cfg)
|
||||||
|
portStr := fmt.Sprintf("%d/tcp", config.Port)
|
||||||
|
if strutil.StrListContains(ports, portStr) {
|
||||||
|
return fmt.Errorf("duplicate port %d specified", config.Port)
|
||||||
|
}
|
||||||
|
ports = append(ports, portStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
vaultCfg["listener"] = listenerConfig
|
||||||
vaultCfg["telemetry"] = map[string]interface{}{
|
vaultCfg["telemetry"] = map[string]interface{}{
|
||||||
"disable_hostname": true,
|
"disable_hostname": true,
|
||||||
}
|
}
|
||||||
@@ -675,6 +735,7 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
|
|||||||
}
|
}
|
||||||
testcluster.JSONLogNoTimestamp(n.Logger, s)
|
testcluster.JSONLogNoTimestamp(n.Logger, s)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
r, err := dockhelper.NewServiceRunner(dockhelper.RunOptions{
|
r, err := dockhelper.NewServiceRunner(dockhelper.RunOptions{
|
||||||
ImageRepo: n.ImageRepo,
|
ImageRepo: n.ImageRepo,
|
||||||
ImageTag: n.ImageTag,
|
ImageTag: n.ImageTag,
|
||||||
@@ -689,7 +750,7 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
|
|||||||
"VAULT_LOG_FORMAT=json",
|
"VAULT_LOG_FORMAT=json",
|
||||||
"VAULT_LICENSE=" + opts.VaultLicense,
|
"VAULT_LICENSE=" + opts.VaultLicense,
|
||||||
},
|
},
|
||||||
Ports: []string{"8200/tcp", "8201/tcp"},
|
Ports: ports,
|
||||||
ContainerName: n.Name(),
|
ContainerName: n.Name(),
|
||||||
NetworkName: opts.NetworkName,
|
NetworkName: opts.NetworkName,
|
||||||
CopyFromTo: copyFromTo,
|
CopyFromTo: copyFromTo,
|
||||||
@@ -772,6 +833,19 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
|
|||||||
}
|
}
|
||||||
client.SetToken(n.Cluster.rootToken)
|
client.SetToken(n.Cluster.rootToken)
|
||||||
n.client = client
|
n.client = client
|
||||||
|
|
||||||
|
n.AllClients = append(n.AllClients, client)
|
||||||
|
|
||||||
|
for _, addr := range svc.StartResult.Addrs[2:] {
|
||||||
|
// The second element of this list of addresses is the cluster address
|
||||||
|
// We do not want to create a client for the cluster address mapping
|
||||||
|
client, err := n.newAPIClientForAddress(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client.SetToken(n.Cluster.rootToken)
|
||||||
|
n.AllClients = append(n.AllClients, client)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ type VaultNodeConfig struct {
|
|||||||
// ServiceRegistrationType string
|
// ServiceRegistrationType string
|
||||||
// ServiceRegistrationOptions map[string]string
|
// ServiceRegistrationOptions map[string]string
|
||||||
|
|
||||||
StorageOptions map[string]string
|
StorageOptions map[string]string
|
||||||
|
AdditionalListeners []VaultNodeListenerConfig
|
||||||
|
|
||||||
DefaultMaxRequestDuration time.Duration `json:"default_max_request_duration"`
|
DefaultMaxRequestDuration time.Duration `json:"default_max_request_duration"`
|
||||||
LogFormat string `json:"log_format"`
|
LogFormat string `json:"log_format"`
|
||||||
@@ -102,6 +103,11 @@ type ClusterOptions struct {
|
|||||||
AdministrativeNamespacePath string
|
AdministrativeNamespacePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VaultNodeListenerConfig struct {
|
||||||
|
Port int
|
||||||
|
ChrootNamespace string
|
||||||
|
}
|
||||||
|
|
||||||
type CA struct {
|
type CA struct {
|
||||||
CACert *x509.Certificate
|
CACert *x509.Certificate
|
||||||
CACertBytes []byte
|
CACertBytes []byte
|
||||||
|
|||||||
Reference in New Issue
Block a user