rebase: Bump the github-dependencies group with 2 updates

Bumps the github-dependencies group with 2 updates: [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) and [github.com/hashicorp/vault/api](https://github.com/hashicorp/vault).


Updates `github.com/aws/aws-sdk-go` from 1.45.2 to 1.45.7
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.45.2...v1.45.7)

Updates `github.com/hashicorp/vault/api` from 1.9.2 to 1.10.0
- [Release notes](https://github.com/hashicorp/vault/releases)
- [Changelog](https://github.com/hashicorp/vault/blob/v1.10.0/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/vault/compare/v1.9.2...v1.10.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-dependencies
- dependency-name: github.com/hashicorp/vault/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-09-11 20:46:24 +00:00
committed by mergify[bot]
parent c198348680
commit 907c4f38f6
15 changed files with 806 additions and 99 deletions

View File

@ -4,6 +4,6 @@ Vault API
This provides the `github.com/hashicorp/vault/api` package which contains code useful for interacting with a Vault server.
For examples of how to use this module, see the [vault-examples](https://github.com/hashicorp/vault-examples) repo.
For a step-by-step walkthrough on using these client libraries, see the [developer quickstart](https://www.vaultproject.io/docs/get-started/developer-qs).
For a step-by-step walkthrough on using these client libraries, see the [developer quickstart](https://developer.hashicorp.com/vault/docs/get-started/developer-qs).
[![GoDoc](https://godoc.org/github.com/hashicorp/vault/api?status.png)](https://godoc.org/github.com/hashicorp/vault/api)

View File

@ -185,6 +185,9 @@ type Config struct {
// CloneToken from parent.
CloneToken bool
// CloneTLSConfig from parent (tls.Config).
CloneTLSConfig bool
// ReadYourWrites ensures isolated read-after-write semantics by
// providing discovered cluster replication states in each request.
// The shared state is automatically propagated to all Client clones.
@ -290,7 +293,14 @@ func (c *Config) configureTLS(t *TLSConfig) error {
if c.HttpClient == nil {
c.HttpClient = DefaultConfig().HttpClient
}
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
transport, ok := c.HttpClient.Transport.(*http.Transport)
if !ok {
return fmt.Errorf(
"unsupported HTTPClient transport type %T", c.HttpClient.Transport)
}
clientTLSConfig := transport.TLSClientConfig
var clientCert tls.Certificate
foundClientCert := false
@ -535,7 +545,7 @@ func (c *Config) ParseAddress(address string) (*url.URL, error) {
// be pointing to the protocol used in the application layer and not to
// the transport layer. Hence, setting the fields accordingly.
u.Scheme = "http"
u.Host = socket
u.Host = "localhost"
u.Path = ""
} else {
return nil, fmt.Errorf("attempting to specify unix:// address with non-transport transport")
@ -988,7 +998,9 @@ func (c *Client) Namespace() string {
func (c *Client) WithNamespace(namespace string) *Client {
c2 := *c
c2.modifyLock = sync.RWMutex{}
c2.headers = c.Headers()
c.modifyLock.RLock()
c2.headers = c.headersInternal()
c.modifyLock.RUnlock()
if namespace == "" {
c2.ClearNamespace()
} else {
@ -1025,7 +1037,12 @@ func (c *Client) ClearToken() {
func (c *Client) Headers() http.Header {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.headersInternal()
}
// headersInternal gets the current set of headers used for requests. Must be called
// with the read modifyLock held.
func (c *Client) headersInternal() http.Header {
if c.headers == nil {
return nil
}
@ -1143,6 +1160,26 @@ func (c *Client) ReadYourWrites() bool {
return c.config.ReadYourWrites
}
// SetCloneTLSConfig from parent.
func (c *Client) SetCloneTLSConfig(clone bool) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.config.CloneTLSConfig = clone
}
// CloneTLSConfig gets the configured CloneTLSConfig value.
func (c *Client) CloneTLSConfig() bool {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.CloneTLSConfig
}
// Clone creates a new client with the same configuration. Note that the same
// underlying http.Client is used; modifying the client from more than one
// goroutine at once may not be safe, so modify the client as needed and then
@ -1153,24 +1190,28 @@ func (c *Client) ReadYourWrites() bool {
// the api.Config struct, such as policy override and wrapping function
// behavior, must currently then be set as desired on the new client.
func (c *Client) Clone() (*Client, error) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.clone(c.config.CloneHeaders)
}
// CloneWithHeaders creates a new client similar to Clone, with the difference
// being that the headers are always cloned
// being that the headers are always cloned
func (c *Client) CloneWithHeaders() (*Client, error) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.clone(true)
}
// clone creates a new client, with the headers being cloned based on the
// passed in cloneheaders boolean
// passed in cloneheaders boolean.
// Must be called with the read lock and config read lock held.
func (c *Client) clone(cloneHeaders bool) (*Client, error) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
config := c.config
config.modifyLock.RLock()
defer config.modifyLock.RUnlock()
newConfig := &Config{
Address: config.Address,
@ -1189,13 +1230,18 @@ func (c *Client) clone(cloneHeaders bool) (*Client, error) {
CloneToken: config.CloneToken,
ReadYourWrites: config.ReadYourWrites,
}
if config.CloneTLSConfig {
newConfig.clientTLSConfig = config.clientTLSConfig
}
client, err := NewClient(newConfig)
if err != nil {
return nil, err
}
if cloneHeaders {
client.SetHeaders(c.Headers().Clone())
client.SetHeaders(c.headersInternal().Clone())
}
if config.CloneToken {
@ -1226,6 +1272,7 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
mfaCreds := c.mfaCreds
wrappingLookupFunc := c.wrappingLookupFunc
policyOverride := c.policyOverride
headers := c.headersInternal()
c.modifyLock.RUnlock()
host := addr.Host
@ -1270,7 +1317,7 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
}
req.Headers = c.Headers()
req.Headers = headers
req.PolicyOverride = policyOverride
return req

View File

@ -38,7 +38,7 @@ type KVSecret struct {
// by default when a server is started in -dev mode. See the kvv2 struct.
//
// Learn more about the KV secrets engine here:
// https://www.vaultproject.io/docs/secrets/kv
// https://developer.hashicorp.com/vault/docs/secrets/kv
func (c *Client) KVv1(mountPath string) *KVv1 {
return &KVv1{c: c, mountPath: mountPath}
}
@ -53,7 +53,7 @@ func (c *Client) KVv1(mountPath string) *KVv1 {
// as these are the default settings when a server is started in -dev mode.
//
// Learn more about the KV secrets engine here:
// https://www.vaultproject.io/docs/secrets/kv
// https://developer.hashicorp.com/vault/docs/secrets/kv
func (c *Client) KVv2(mountPath string) *KVv2 {
return &KVv2{c: c, mountPath: mountPath}
}

View File

@ -12,13 +12,23 @@ import (
"flag"
"net/url"
"os"
"regexp"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/hashicorp/errwrap"
)
// This file contains helper code used when writing Vault auth method or secrets engine plugins.
//
// As such, it would be better located in the sdk module with the rest of the code which is only to support plugins,
// rather than api, but is here for historical reasons. (The api module used to depend on the sdk module, this code
// calls NewClient within the api package, so placing it in the sdk would have created a dependency cycle. This reason
// is now historical, as the dependency between sdk and api has since been reversed in direction.)
// Moving this code to the sdk would be appropriate if an api v2.0.0 release is ever planned.
//
// This helper code is used when a plugin is hosted by Vault 1.11 and earlier. Vault 1.12 and sdk v0.6.0 introduced
// version 5 of the backend plugin interface, which uses go-plugin's AutoMTLS feature instead of this code.
const (
// PluginAutoMTLSEnv is used to ensure AutoMTLS is used. This will override
// setting a TLSProviderFunc for a plugin.
@ -33,50 +43,6 @@ const (
PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN"
)
// sudoPaths is a map containing the paths that require a token's policy
// to have the "sudo" capability. The keys are the paths as strings, in
// the same format as they are returned by the OpenAPI spec. The values
// are the regular expressions that can be used to test whether a given
// path matches that path or not (useful specifically for the paths that
// contain templated fields.)
var sudoPaths = map[string]*regexp.Regexp{
"/auth/token/accessors/": regexp.MustCompile(`^/auth/token/accessors/?$`),
"/pki/root": regexp.MustCompile(`^/pki/root$`),
"/pki/root/sign-self-issued": regexp.MustCompile(`^/pki/root/sign-self-issued$`),
"/sys/audit": regexp.MustCompile(`^/sys/audit$`),
"/sys/audit/{path}": regexp.MustCompile(`^/sys/audit/.+$`),
"/sys/auth/{path}": regexp.MustCompile(`^/sys/auth/.+$`),
"/sys/auth/{path}/tune": regexp.MustCompile(`^/sys/auth/.+/tune$`),
"/sys/config/auditing/request-headers": regexp.MustCompile(`^/sys/config/auditing/request-headers$`),
"/sys/config/auditing/request-headers/{header}": regexp.MustCompile(`^/sys/config/auditing/request-headers/.+$`),
"/sys/config/cors": regexp.MustCompile(`^/sys/config/cors$`),
"/sys/config/ui/headers/": regexp.MustCompile(`^/sys/config/ui/headers/?$`),
"/sys/config/ui/headers/{header}": regexp.MustCompile(`^/sys/config/ui/headers/.+$`),
"/sys/leases": regexp.MustCompile(`^/sys/leases$`),
"/sys/leases/lookup/": regexp.MustCompile(`^/sys/leases/lookup/?$`),
"/sys/leases/lookup/{prefix}": regexp.MustCompile(`^/sys/leases/lookup/.+$`),
"/sys/leases/revoke-force/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-force/.+$`),
"/sys/leases/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-prefix/.+$`),
"/sys/plugins/catalog/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[^/]+$`),
"/sys/plugins/catalog/{type}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+$`),
"/sys/plugins/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+/[^/]+$`),
"/sys/raw": regexp.MustCompile(`^/sys/raw$`),
"/sys/raw/{path}": regexp.MustCompile(`^/sys/raw/.+$`),
"/sys/remount": regexp.MustCompile(`^/sys/remount$`),
"/sys/revoke-force/{prefix}": regexp.MustCompile(`^/sys/revoke-force/.+$`),
"/sys/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/revoke-prefix/.+$`),
"/sys/rotate": regexp.MustCompile(`^/sys/rotate$`),
"/sys/internal/inspect/router/{tag}": regexp.MustCompile(`^/sys/internal/inspect/router/.+$`),
// enterprise-only paths
"/sys/replication/dr/primary/secondary-token": regexp.MustCompile(`^/sys/replication/dr/primary/secondary-token$`),
"/sys/replication/performance/primary/secondary-token": regexp.MustCompile(`^/sys/replication/performance/primary/secondary-token$`),
"/sys/replication/primary/secondary-token": regexp.MustCompile(`^/sys/replication/primary/secondary-token$`),
"/sys/replication/reindex": regexp.MustCompile(`^/sys/replication/reindex$`),
"/sys/storage/raft/snapshot-auto/config/": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/?$`),
"/sys/storage/raft/snapshot-auto/config/{name}": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/[^/]+$`),
}
// PluginAPIClientMeta is a helper that plugins can use to configure TLS connections
// back to Vault.
type PluginAPIClientMeta struct {
@ -244,28 +210,3 @@ func VaultPluginTLSProviderContext(ctx context.Context, apiTLSConfig *TLSConfig)
return tlsConfig, nil
}
}
func SudoPaths() map[string]*regexp.Regexp {
return sudoPaths
}
// Determine whether the given path requires the sudo capability
func IsSudoPath(path string) bool {
// Return early if the path is any of the non-templated sudo paths.
if _, ok := sudoPaths[path]; ok {
return true
}
// Some sudo paths have templated fields in them.
// (e.g. /sys/revoke-prefix/{prefix})
// The values in the sudoPaths map are actually regular expressions,
// so we can check if our path matches against them.
for _, sudoPathRegexp := range sudoPaths {
match := sudoPathRegexp.MatchString(path)
if match {
return true
}
}
return false
}

View File

@ -0,0 +1,41 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
// NOTE: this file was copied from
// https://github.com/hashicorp/vault/blob/main/sdk/helper/consts/plugin_runtime_types.go
// Any changes made should be made to both files at the same time.
import "fmt"
var PluginRuntimeTypes = []PluginRuntimeType{
PluginRuntimeTypeUnsupported,
PluginRuntimeTypeContainer,
}
type PluginRuntimeType uint32
// This is a list of PluginRuntimeTypes used by Vault.
const (
PluginRuntimeTypeUnsupported PluginRuntimeType = iota
PluginRuntimeTypeContainer
)
func (r PluginRuntimeType) String() string {
switch r {
case PluginRuntimeTypeContainer:
return "container"
default:
return "unsupported"
}
}
func ParsePluginRuntimeType(PluginRuntimeType string) (PluginRuntimeType, error) {
switch PluginRuntimeType {
case "container":
return PluginRuntimeTypeContainer, nil
default:
return PluginRuntimeTypeUnsupported, fmt.Errorf("%q is not a supported plugin runtime type", PluginRuntimeType)
}
}

View File

@ -0,0 +1,130 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/mitchellh/mapstructure"
)
const (
apiRepPerformanceStatusPath = "/v1/sys/replication/performance/status"
apiRepDRStatusPath = "/v1/sys/replication/dr/status"
apiRepStatusPath = "/v1/sys/replication/status"
)
type ClusterInfo struct {
APIAddr string `json:"api_address,omitempty" mapstructure:"api_address"`
ClusterAddress string `json:"cluster_address,omitempty" mapstructure:"cluster_address"`
ConnectionStatus string `json:"connection_status,omitempty" mapstructure:"connection_status"`
LastHeartBeat string `json:"last_heartbeat,omitempty" mapstructure:"last_heartbeat"`
NodeID string `json:"node_id,omitempty" mapstructure:"node_id"`
}
type ReplicationStatusGenericResponse struct {
LastDRWAL uint64 `json:"last_dr_wal,omitempty" mapstructure:"last_dr_wal"`
LastReindexEpoch string `json:"last_reindex_epoch,omitempty" mapstructure:"last_reindex_epoch"`
ClusterID string `json:"cluster_id,omitempty" mapstructure:"cluster_id"`
LastWAL uint64 `json:"last_wal,omitempty" mapstructure:"last_wal"`
MerkleRoot string `json:"merkle_root,omitempty" mapstructure:"merkle_root"`
Mode string `json:"mode,omitempty" mapstructure:"mode"`
PrimaryClusterAddr string `json:"primary_cluster_addr,omitempty" mapstructure:"primary_cluster_addr"`
LastPerformanceWAL uint64 `json:"last_performance_wal,omitempty" mapstructure:"last_performance_wal"`
State string `json:"state,omitempty" mapstructure:"state"`
LastRemoteWAL uint64 `json:"last_remote_wal,omitempty" mapstructure:"last_remote_wal"`
SecondaryID string `json:"secondary_id,omitempty" mapstructure:"secondary_id"`
SSCTGenerationCounter uint64 `json:"ssct_generation_counter,omitempty" mapstructure:"ssct_generation_counter"`
KnownSecondaries []string `json:"known_secondaries,omitempty" mapstructure:"known_secondaries"`
KnownPrimaryClusterAddrs []string `json:"known_primary_cluster_addrs,omitempty" mapstructure:"known_primary_cluster_addrs"`
Primaries []ClusterInfo `json:"primaries,omitempty" mapstructure:"primaries"`
Secondaries []ClusterInfo `json:"secondaries,omitempty" mapstructure:"secondaries"`
}
type ReplicationStatusResponse struct {
DR ReplicationStatusGenericResponse `json:"dr,omitempty" mapstructure:"dr"`
Performance ReplicationStatusGenericResponse `json:"performance,omitempty" mapstructure:"performance"`
}
func (c *Sys) ReplicationStatus() (*ReplicationStatusResponse, error) {
return c.ReplicationStatusWithContext(context.Background(), apiRepStatusPath)
}
func (c *Sys) ReplicationPerformanceStatusWithContext(ctx context.Context) (*ReplicationStatusGenericResponse, error) {
s, err := c.ReplicationStatusWithContext(ctx, apiRepPerformanceStatusPath)
if err != nil {
return nil, err
}
return &s.Performance, nil
}
func (c *Sys) ReplicationDRStatusWithContext(ctx context.Context) (*ReplicationStatusGenericResponse, error) {
s, err := c.ReplicationStatusWithContext(ctx, apiRepDRStatusPath)
if err != nil {
return nil, err
}
return &s.DR, nil
}
func (c *Sys) ReplicationStatusWithContext(ctx context.Context, path string) (*ReplicationStatusResponse, error) {
// default to replication/status
if path == "" {
path = apiRepStatusPath
}
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
r := c.c.NewRequest(http.MethodGet, path)
resp, err := c.c.rawRequestWithContext(ctx, r)
if err != nil {
return nil, err
}
defer func() { _ = resp.Body.Close() }()
// First decode response into a map[string]interface{}
data := make(map[string]interface{})
dec := json.NewDecoder(resp.Body)
dec.UseNumber()
if err := dec.Decode(&data); err != nil {
return nil, err
}
rawData, ok := data["data"]
if !ok {
return nil, fmt.Errorf("empty data in replication status response")
}
s := &ReplicationStatusResponse{}
g := &ReplicationStatusGenericResponse{}
switch {
case path == apiRepPerformanceStatusPath:
err = mapstructure.Decode(rawData, g)
if err != nil {
return nil, err
}
s.Performance = *g
case path == apiRepDRStatusPath:
err = mapstructure.Decode(rawData, g)
if err != nil {
return nil, err
}
s.DR = *g
default:
err = mapstructure.Decode(rawData, s)
if err != nil {
return nil, err
}
return s, err
}
return s, err
}

87
vendor/github.com/hashicorp/vault/api/sudo_paths.go generated vendored Normal file
View File

@ -0,0 +1,87 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
import (
"regexp"
)
// sudoPaths is a map containing the paths that require a token's policy
// to have the "sudo" capability. The keys are the paths as strings, in
// the same format as they are returned by the OpenAPI spec. The values
// are the regular expressions that can be used to test whether a given
// path matches that path or not (useful specifically for the paths that
// contain templated fields.)
var sudoPaths = map[string]*regexp.Regexp{
"/auth/token/accessors": regexp.MustCompile(`^/auth/token/accessors/?$`),
"/auth/token/revoke-orphan": regexp.MustCompile(`^/auth/token/revoke-orphan$`),
"/pki/root": regexp.MustCompile(`^/pki/root$`),
"/pki/root/sign-self-issued": regexp.MustCompile(`^/pki/root/sign-self-issued$`),
"/sys/audit": regexp.MustCompile(`^/sys/audit$`),
"/sys/audit/{path}": regexp.MustCompile(`^/sys/audit/.+$`),
"/sys/auth/{path}": regexp.MustCompile(`^/sys/auth/.+$`),
"/sys/auth/{path}/tune": regexp.MustCompile(`^/sys/auth/.+/tune$`),
"/sys/config/auditing/request-headers": regexp.MustCompile(`^/sys/config/auditing/request-headers$`),
"/sys/config/auditing/request-headers/{header}": regexp.MustCompile(`^/sys/config/auditing/request-headers/.+$`),
"/sys/config/cors": regexp.MustCompile(`^/sys/config/cors$`),
"/sys/config/ui/headers": regexp.MustCompile(`^/sys/config/ui/headers/?$`),
"/sys/config/ui/headers/{header}": regexp.MustCompile(`^/sys/config/ui/headers/.+$`),
"/sys/internal/inspect/router/{tag}": regexp.MustCompile(`^/sys/internal/inspect/router/.+$`),
"/sys/leases": regexp.MustCompile(`^/sys/leases$`),
// This entry is a bit wrong... sys/leases/lookup does NOT require sudo. But sys/leases/lookup/ with a trailing
// slash DOES require sudo. But the part of the Vault CLI that uses this logic doesn't pass operation-appropriate
// trailing slashes, it always strips them off, so we end up giving the wrong answer for one of these.
"/sys/leases/lookup/{prefix}": regexp.MustCompile(`^/sys/leases/lookup(?:/.+)?$`),
"/sys/leases/revoke-force/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-force/.+$`),
"/sys/leases/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-prefix/.+$`),
"/sys/plugins/catalog/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[^/]+$`),
"/sys/plugins/catalog/{type}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+$`),
"/sys/plugins/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+/[^/]+$`),
"/sys/plugins/runtimes/catalog": regexp.MustCompile(`^/sys/plugins/runtimes/catalog/?$`),
"/sys/plugins/runtimes/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/runtimes/catalog/[\w-]+/[^/]+$`),
"/sys/raw/{path}": regexp.MustCompile(`^/sys/raw(?:/.+)?$`),
"/sys/remount": regexp.MustCompile(`^/sys/remount$`),
"/sys/revoke-force/{prefix}": regexp.MustCompile(`^/sys/revoke-force/.+$`),
"/sys/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/revoke-prefix/.+$`),
"/sys/rotate": regexp.MustCompile(`^/sys/rotate$`),
"/sys/seal": regexp.MustCompile(`^/sys/seal$`),
"/sys/step-down": regexp.MustCompile(`^/sys/step-down$`),
// enterprise-only paths
"/sys/replication/dr/primary/secondary-token": regexp.MustCompile(`^/sys/replication/dr/primary/secondary-token$`),
"/sys/replication/performance/primary/secondary-token": regexp.MustCompile(`^/sys/replication/performance/primary/secondary-token$`),
"/sys/replication/primary/secondary-token": regexp.MustCompile(`^/sys/replication/primary/secondary-token$`),
"/sys/replication/reindex": regexp.MustCompile(`^/sys/replication/reindex$`),
"/sys/storage/raft/snapshot-auto/config": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/?$`),
"/sys/storage/raft/snapshot-auto/config/{name}": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/[^/]+$`),
}
func SudoPaths() map[string]*regexp.Regexp {
return sudoPaths
}
// Determine whether the given path requires the sudo capability.
// Note that this uses hardcoded static path information, so will return incorrect results for paths in namespaces,
// or for secret engines mounted at non-default paths.
// Expects to receive a path with an initial slash, but no trailing slashes, as the Vault CLI (the only known and
// expected user of this function) sanitizes its paths that way.
func IsSudoPath(path string) bool {
// Return early if the path is any of the non-templated sudo paths.
if _, ok := sudoPaths[path]; ok {
return true
}
// Some sudo paths have templated fields in them.
// (e.g. /sys/revoke-prefix/{prefix})
// The values in the sudoPaths map are actually regular expressions,
// so we can check if our path matches against them.
for _, sudoPathRegexp := range sudoPaths {
match := sudoPathRegexp.MatchString(path)
if match {
return true
}
}
return false
}

View File

@ -144,6 +144,7 @@ type GetPluginResponse struct {
Args []string `json:"args"`
Builtin bool `json:"builtin"`
Command string `json:"command"`
OCIImage string `json:"oci_image"`
Name string `json:"name"`
SHA256 string `json:"sha256"`
DeprecationStatus string `json:"deprecation_status,omitempty"`
@ -201,6 +202,13 @@ type RegisterPluginInput struct {
// Version is the optional version of the plugin being registered
Version string `json:"version,omitempty"`
// OCIImage specifies the container image to run as a plugin.
OCIImage string `json:"oci_image,omitempty"`
// Env specifies a list of key=value pairs to add to the plugin's environment
// variables.
Env []string `json:"env,omitempty"`
}
// RegisterPlugin wraps RegisterPluginWithContext using context.Background.

View File

@ -0,0 +1,189 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/mitchellh/mapstructure"
)
// GetPluginRuntimeInput is used as input to the GetPluginRuntime function.
type GetPluginRuntimeInput struct {
Name string `json:"-"`
// Type of the plugin runtime. Required.
Type PluginRuntimeType `json:"type"`
}
// GetPluginRuntimeResponse is the response from the GetPluginRuntime call.
type GetPluginRuntimeResponse struct {
Type string `json:"type"`
Name string `json:"name"`
OCIRuntime string `json:"oci_runtime"`
CgroupParent string `json:"cgroup_parent"`
CPU int64 `json:"cpu_nanos"`
Memory int64 `json:"memory_bytes"`
}
// GetPluginRuntime retrieves information about the plugin.
func (c *Sys) GetPluginRuntime(ctx context.Context, i *GetPluginRuntimeInput) (*GetPluginRuntimeResponse, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
path := pluginRuntimeCatalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodGet, path)
resp, err := c.c.rawRequestWithContext(ctx, req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Data *GetPluginRuntimeResponse
}
err = resp.DecodeJSON(&result)
if err != nil {
return nil, err
}
return result.Data, err
}
// RegisterPluginRuntimeInput is used as input to the RegisterPluginRuntime function.
type RegisterPluginRuntimeInput struct {
// Name is the name of the plugin. Required.
Name string `json:"-"`
// Type of the plugin. Required.
Type PluginRuntimeType `json:"type"`
OCIRuntime string `json:"oci_runtime,omitempty"`
CgroupParent string `json:"cgroup_parent,omitempty"`
CPU int64 `json:"cpu,omitempty"`
Memory int64 `json:"memory,omitempty"`
}
// RegisterPluginRuntime registers the plugin with the given information.
func (c *Sys) RegisterPluginRuntime(ctx context.Context, i *RegisterPluginRuntimeInput) error {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
path := pluginRuntimeCatalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodPut, path)
if err := req.SetJSONBody(i); err != nil {
return err
}
resp, err := c.c.rawRequestWithContext(ctx, req)
if err == nil {
defer resp.Body.Close()
}
return err
}
// DeregisterPluginRuntimeInput is used as input to the DeregisterPluginRuntime function.
type DeregisterPluginRuntimeInput struct {
// Name is the name of the plugin runtime. Required.
Name string `json:"-"`
// Type of the plugin. Required.
Type PluginRuntimeType `json:"type"`
}
// DeregisterPluginRuntime removes the plugin with the given name from the plugin
// catalog.
func (c *Sys) DeregisterPluginRuntime(ctx context.Context, i *DeregisterPluginRuntimeInput) error {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
path := pluginRuntimeCatalogPathByType(i.Type, i.Name)
req := c.c.NewRequest(http.MethodDelete, path)
resp, err := c.c.rawRequestWithContext(ctx, req)
if err == nil {
defer resp.Body.Close()
}
return err
}
type PluginRuntimeDetails struct {
Type string `json:"type" mapstructure:"type"`
Name string `json:"name" mapstructure:"name"`
OCIRuntime string `json:"oci_runtime" mapstructure:"oci_runtime"`
CgroupParent string `json:"cgroup_parent" mapstructure:"cgroup_parent"`
CPU int64 `json:"cpu_nanos" mapstructure:"cpu_nanos"`
Memory int64 `json:"memory_bytes" mapstructure:"memory_bytes"`
}
// ListPluginRuntimesInput is used as input to the ListPluginRuntimes function.
type ListPluginRuntimesInput struct {
// Type of the plugin. Required.
Type PluginRuntimeType `json:"type"`
}
// ListPluginRuntimesResponse is the response from the ListPluginRuntimes call.
type ListPluginRuntimesResponse struct {
// RuntimesByType is the list of plugin runtimes by type.
Runtimes []PluginRuntimeDetails `json:"runtimes"`
}
// ListPluginRuntimes lists all plugin runtimes in the catalog and returns their names as a
// list of strings.
func (c *Sys) ListPluginRuntimes(ctx context.Context, input *ListPluginRuntimesInput) (*ListPluginRuntimesResponse, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
if input != nil && input.Type == PluginRuntimeTypeUnsupported {
return nil, fmt.Errorf("%q is not a supported runtime type", input.Type.String())
}
resp, err := c.c.rawRequestWithContext(ctx, c.c.NewRequest(http.MethodGet, "/v1/sys/plugins/runtimes/catalog"))
if err != nil && resp == nil {
return nil, err
}
if resp == nil {
return nil, nil
}
defer resp.Body.Close()
secret, err := ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
if _, ok := secret.Data["runtimes"]; !ok {
return nil, fmt.Errorf("data from server response does not contain runtimes")
}
var runtimes []PluginRuntimeDetails
if err = mapstructure.Decode(secret.Data["runtimes"], &runtimes); err != nil {
return nil, err
}
// return all runtimes in the catalog
if input == nil {
return &ListPluginRuntimesResponse{Runtimes: runtimes}, nil
}
result := &ListPluginRuntimesResponse{
Runtimes: []PluginRuntimeDetails{},
}
for _, runtime := range runtimes {
if runtime.Type == input.Type.String() {
result.Runtimes = append(result.Runtimes, runtime)
}
}
return result, nil
}
// pluginRuntimeCatalogPathByType is a helper to construct the proper API path by plugin type
func pluginRuntimeCatalogPathByType(runtimeType PluginRuntimeType, name string) string {
return fmt.Sprintf("/v1/sys/plugins/runtimes/catalog/%s/%s", runtimeType, name)
}

View File

@ -276,11 +276,19 @@ func (c *Sys) RaftAutopilotState() (*AutopilotState, error) {
return c.RaftAutopilotStateWithContext(context.Background())
}
// RaftAutopilotStateWithToken wraps RaftAutopilotStateWithContext using the given token.
func (c *Sys) RaftAutopilotStateWithDRToken(drToken string) (*AutopilotState, error) {
return c.RaftAutopilotStateWithContext(context.WithValue(context.Background(), "dr-token", drToken))
}
// RaftAutopilotStateWithContext returns the state of the raft cluster as seen by autopilot.
func (c *Sys) RaftAutopilotStateWithContext(ctx context.Context) (*AutopilotState, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
if ctx.Value("dr-token") != nil {
c.c.SetToken(ctx.Value("dr-token").(string))
}
r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/state")
resp, err := c.c.rawRequestWithContext(ctx, r)
@ -316,11 +324,20 @@ func (c *Sys) RaftAutopilotConfiguration() (*AutopilotConfig, error) {
return c.RaftAutopilotConfigurationWithContext(context.Background())
}
// RaftAutopilotConfigurationWithDRToken wraps RaftAutopilotConfigurationWithContext using the given token.
func (c *Sys) RaftAutopilotConfigurationWithDRToken(drToken string) (*AutopilotConfig, error) {
return c.RaftAutopilotConfigurationWithContext(context.WithValue(context.Background(), "dr-token", drToken))
}
// RaftAutopilotConfigurationWithContext fetches the autopilot config.
func (c *Sys) RaftAutopilotConfigurationWithContext(ctx context.Context) (*AutopilotConfig, error) {
ctx, cancelFunc := c.c.withConfiguredTimeout(ctx)
defer cancelFunc()
if ctx.Value("dr-token") != nil {
c.c.SetToken(ctx.Value("dr-token").(string))
}
r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/configuration")
resp, err := c.c.rawRequestWithContext(ctx, r)