mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-03 20:17:59 +00:00 
			
		
		
		
	Integrate password policies into RabbitMQ secret engine (#9143)
* Add password policies to RabbitMQ & update docs * Also updates some parts of the password policies to aid/fix testing
This commit is contained in:
		@@ -2,7 +2,6 @@ package rabbitmq
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
@@ -73,18 +72,10 @@ func (b *backend) Client(ctx context.Context, s logical.Storage) (*rabbithole.Cl
 | 
			
		||||
	b.lock.RUnlock()
 | 
			
		||||
 | 
			
		||||
	// Otherwise, attempt to make connection
 | 
			
		||||
	entry, err := s.Get(ctx, "config/connection")
 | 
			
		||||
	connConfig, err := readConfig(ctx, s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if entry == nil {
 | 
			
		||||
		return nil, fmt.Errorf("configure the client connection with config/connection first")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var connConfig connectionConfig
 | 
			
		||||
	if err := entry.DecodeJSON(&connConfig); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.lock.Lock()
 | 
			
		||||
	defer b.lock.Unlock()
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"github.com/hashicorp/vault/helper/testhelpers/docker"
 | 
			
		||||
	logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
 | 
			
		||||
	"github.com/hashicorp/vault/sdk/helper/jsonutil"
 | 
			
		||||
	"github.com/hashicorp/vault/sdk/helper/random"
 | 
			
		||||
	"github.com/hashicorp/vault/sdk/logical"
 | 
			
		||||
	rabbithole "github.com/michaelklishin/rabbit-hole"
 | 
			
		||||
	"github.com/mitchellh/mapstructure"
 | 
			
		||||
@@ -27,6 +28,8 @@ const (
 | 
			
		||||
	testTags        = "administrator"
 | 
			
		||||
	testVHosts      = `{"/": {"configure": ".*", "write": ".*", "read": ".*"}}`
 | 
			
		||||
	testVHostTopics = `{"/": {"amq.topic": {"write": ".*", "read": ".*"}}}`
 | 
			
		||||
 | 
			
		||||
	roleName = "web"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func prepareRabbitMQTestContainer(t *testing.T) (func(), string, int) {
 | 
			
		||||
@@ -89,9 +92,9 @@ func TestBackend_basic(t *testing.T) {
 | 
			
		||||
		PreCheck:       testAccPreCheckFunc(t, uri),
 | 
			
		||||
		LogicalBackend: b,
 | 
			
		||||
		Steps: []logicaltest.TestStep{
 | 
			
		||||
			testAccStepConfig(t, uri),
 | 
			
		||||
			testAccStepConfig(t, uri, ""),
 | 
			
		||||
			testAccStepRole(t),
 | 
			
		||||
			testAccStepReadCreds(t, b, uri, "web"),
 | 
			
		||||
			testAccStepReadCreds(t, b, uri, roleName),
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
@@ -111,10 +114,10 @@ func TestBackend_returnsErrs(t *testing.T) {
 | 
			
		||||
		PreCheck:       testAccPreCheckFunc(t, uri),
 | 
			
		||||
		LogicalBackend: b,
 | 
			
		||||
		Steps: []logicaltest.TestStep{
 | 
			
		||||
			testAccStepConfig(t, uri),
 | 
			
		||||
			testAccStepConfig(t, uri, ""),
 | 
			
		||||
			{
 | 
			
		||||
				Operation: logical.CreateOperation,
 | 
			
		||||
				Path:      "roles/web",
 | 
			
		||||
				Path:      fmt.Sprintf("roles/%s", roleName),
 | 
			
		||||
				Data: map[string]interface{}{
 | 
			
		||||
					"tags":         testTags,
 | 
			
		||||
					"vhosts":       `{"invalid":{"write": ".*", "read": ".*"}}`,
 | 
			
		||||
@@ -123,7 +126,7 @@ func TestBackend_returnsErrs(t *testing.T) {
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				Operation: logical.ReadOperation,
 | 
			
		||||
				Path:      "creds/web",
 | 
			
		||||
				Path:      fmt.Sprintf("creds/%s", roleName),
 | 
			
		||||
				ErrorOk:   true,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
@@ -144,11 +147,35 @@ func TestBackend_roleCrud(t *testing.T) {
 | 
			
		||||
		PreCheck:       testAccPreCheckFunc(t, uri),
 | 
			
		||||
		LogicalBackend: b,
 | 
			
		||||
		Steps: []logicaltest.TestStep{
 | 
			
		||||
			testAccStepConfig(t, uri),
 | 
			
		||||
			testAccStepConfig(t, uri, ""),
 | 
			
		||||
			testAccStepRole(t),
 | 
			
		||||
			testAccStepReadRole(t, "web", testTags, testVHosts, testVHostTopics),
 | 
			
		||||
			testAccStepDeleteRole(t, "web"),
 | 
			
		||||
			testAccStepReadRole(t, "web", "", "", ""),
 | 
			
		||||
			testAccStepReadRole(t, roleName, testTags, testVHosts, testVHostTopics),
 | 
			
		||||
			testAccStepDeleteRole(t, roleName),
 | 
			
		||||
			testAccStepReadRole(t, roleName, "", "", ""),
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBackend_roleWithPasswordPolicy(t *testing.T) {
 | 
			
		||||
	if os.Getenv(logicaltest.TestEnvVar) == "" {
 | 
			
		||||
		t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	backendConfig := logical.TestBackendConfig()
 | 
			
		||||
	backendConfig.System.(*logical.StaticSystemView).SetPasswordPolicy("testpolicy", random.DefaultStringGenerator)
 | 
			
		||||
	b, _ := Factory(context.Background(), backendConfig)
 | 
			
		||||
 | 
			
		||||
	cleanup, uri, _ := prepareRabbitMQTestContainer(t)
 | 
			
		||||
	defer cleanup()
 | 
			
		||||
 | 
			
		||||
	logicaltest.Test(t, logicaltest.TestCase{
 | 
			
		||||
		PreCheck:       testAccPreCheckFunc(t, uri),
 | 
			
		||||
		LogicalBackend: b,
 | 
			
		||||
		Steps: []logicaltest.TestStep{
 | 
			
		||||
			testAccStepConfig(t, uri, "testpolicy"),
 | 
			
		||||
			testAccStepRole(t),
 | 
			
		||||
			testAccStepReadCreds(t, b, uri, roleName),
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -161,7 +188,7 @@ func testAccPreCheckFunc(t *testing.T, uri string) func() {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testAccStepConfig(t *testing.T, uri string) logicaltest.TestStep {
 | 
			
		||||
func testAccStepConfig(t *testing.T, uri string, passwordPolicy string) logicaltest.TestStep {
 | 
			
		||||
	username := os.Getenv(envRabbitMQUsername)
 | 
			
		||||
	if len(username) == 0 {
 | 
			
		||||
		username = "guest"
 | 
			
		||||
@@ -178,6 +205,7 @@ func testAccStepConfig(t *testing.T, uri string) logicaltest.TestStep {
 | 
			
		||||
			"connection_uri":  uri,
 | 
			
		||||
			"username":        username,
 | 
			
		||||
			"password":        password,
 | 
			
		||||
			"password_policy": passwordPolicy,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -185,7 +213,7 @@ func testAccStepConfig(t *testing.T, uri string) logicaltest.TestStep {
 | 
			
		||||
func testAccStepRole(t *testing.T) logicaltest.TestStep {
 | 
			
		||||
	return logicaltest.TestStep{
 | 
			
		||||
		Operation: logical.UpdateOperation,
 | 
			
		||||
		Path:      "roles/web",
 | 
			
		||||
		Path:      fmt.Sprintf("roles/%s", roleName),
 | 
			
		||||
		Data: map[string]interface{}{
 | 
			
		||||
			"tags":         testTags,
 | 
			
		||||
			"vhosts":       testVHosts,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								builtin/logical/rabbitmq/passwords.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								builtin/logical/rabbitmq/passwords.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package rabbitmq
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"github.com/hashicorp/vault/sdk/helper/base62"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *backend) generatePassword(ctx context.Context, policyName string) (password string, err error) {
 | 
			
		||||
	if policyName != "" {
 | 
			
		||||
		return b.System().GeneratePasswordFromPolicy(ctx, policyName)
 | 
			
		||||
	}
 | 
			
		||||
	return base62.Random(36)
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,10 @@ import (
 | 
			
		||||
	rabbithole "github.com/michaelklishin/rabbit-hole"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	storageKey = "config/connection"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func pathConfigConnection(b *backend) *framework.Path {
 | 
			
		||||
	return &framework.Path{
 | 
			
		||||
		Pattern: "config/connection",
 | 
			
		||||
@@ -30,6 +34,10 @@ func pathConfigConnection(b *backend) *framework.Path {
 | 
			
		||||
				Default:     true,
 | 
			
		||||
				Description: `If set, connection_uri is verified by actually connecting to the RabbitMQ management API`,
 | 
			
		||||
			},
 | 
			
		||||
			"password_policy": &framework.FieldSchema{
 | 
			
		||||
				Type:        framework.TypeString,
 | 
			
		||||
				Description: "Name of the password policy to use to generate passwords for dynamic credentials.",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		Callbacks: map[logical.Operation]framework.OperationFunc{
 | 
			
		||||
@@ -57,6 +65,8 @@ func (b *backend) pathConnectionUpdate(ctx context.Context, req *logical.Request
 | 
			
		||||
		return logical.ErrorResponse("missing password"), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	passwordPolicy := data.Get("password_policy").(string)
 | 
			
		||||
 | 
			
		||||
	// Don't check the connection_url if verification is disabled
 | 
			
		||||
	verifyConnection := data.Get("verify_connection").(bool)
 | 
			
		||||
	if verifyConnection {
 | 
			
		||||
@@ -73,15 +83,14 @@ func (b *backend) pathConnectionUpdate(ctx context.Context, req *logical.Request
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Store it
 | 
			
		||||
	entry, err := logical.StorageEntryJSON("config/connection", connectionConfig{
 | 
			
		||||
	config := connectionConfig{
 | 
			
		||||
		URI:            uri,
 | 
			
		||||
		Username:       username,
 | 
			
		||||
		Password:       password,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		PasswordPolicy: passwordPolicy,
 | 
			
		||||
	}
 | 
			
		||||
	if err := req.Storage.Put(ctx, entry); err != nil {
 | 
			
		||||
	err := writeConfig(ctx, req.Storage, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -91,6 +100,33 @@ func (b *backend) pathConnectionUpdate(ctx context.Context, req *logical.Request
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func readConfig(ctx context.Context, storage logical.Storage) (connectionConfig, error) {
 | 
			
		||||
	entry, err := storage.Get(ctx, storageKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return connectionConfig{}, err
 | 
			
		||||
	}
 | 
			
		||||
	if entry == nil {
 | 
			
		||||
		return connectionConfig{}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var connConfig connectionConfig
 | 
			
		||||
	if err := entry.DecodeJSON(&connConfig); err != nil {
 | 
			
		||||
		return connectionConfig{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return connConfig, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeConfig(ctx context.Context, storage logical.Storage, config connectionConfig) error {
 | 
			
		||||
	entry, err := logical.StorageEntryJSON(storageKey, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := storage.Put(ctx, entry); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// connectionConfig contains the information required to make a connection to a RabbitMQ node
 | 
			
		||||
type connectionConfig struct {
 | 
			
		||||
	// URI of the RabbitMQ server
 | 
			
		||||
@@ -101,6 +137,9 @@ type connectionConfig struct {
 | 
			
		||||
 | 
			
		||||
	// Password for the Username
 | 
			
		||||
	Password string `json:"password"`
 | 
			
		||||
 | 
			
		||||
	// PasswordPolicy for generating passwords for dynamic credentials
 | 
			
		||||
	PasswordPolicy string `json:"password_policy"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pathConfigConnectionHelpSyn = `
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,12 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr
 | 
			
		||||
	}
 | 
			
		||||
	username := fmt.Sprintf("%s-%s", req.DisplayName, uuidVal)
 | 
			
		||||
 | 
			
		||||
	password, err := uuid.GenerateUUID()
 | 
			
		||||
	config, err := readConfig(ctx, req.Storage)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("unable to read configuration: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	password, err := b.generatePassword(ctx, config.PasswordPolicy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ var (
 | 
			
		||||
	AlphaNumericFullSymbolRuneset  = []rune(AlphaNumericFullSymbolCharset)
 | 
			
		||||
 | 
			
		||||
	// DefaultStringGenerator has reasonable default rules for generating strings
 | 
			
		||||
	DefaultStringGenerator = StringGenerator{
 | 
			
		||||
	DefaultStringGenerator = &StringGenerator{
 | 
			
		||||
		Length: 20,
 | 
			
		||||
		Rules: []Rule{
 | 
			
		||||
			CharsetRule{
 | 
			
		||||
 
 | 
			
		||||
@@ -372,22 +372,24 @@ func BenchmarkStringGenerator_Generate(b *testing.B) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type testCase struct {
 | 
			
		||||
		generator StringGenerator
 | 
			
		||||
		generator *StringGenerator
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	benches := map[string]testCase{
 | 
			
		||||
		"no rules": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
				charset: AlphaNumericFullSymbolRuneset,
 | 
			
		||||
				Rules:   []Rule{},
 | 
			
		||||
		"no restrictions": {
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset: AlphaNumericFullSymbolRuneset,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		"default generator": {
 | 
			
		||||
			generator: DefaultStringGenerator,
 | 
			
		||||
		},
 | 
			
		||||
		"large symbol set": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
				charset: AlphaNumericFullSymbolRuneset,
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset:  LowercaseRuneset,
 | 
			
		||||
@@ -409,13 +411,14 @@ func BenchmarkStringGenerator_Generate(b *testing.B) {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		"max symbol set": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
				charset: []rune(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset: []rune(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
 | 
			
		||||
							"`abcdefghijklmnopqrstuvwxyz{|}~ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠ" +
 | 
			
		||||
							"ġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠ" +
 | 
			
		||||
					"šŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠",
 | 
			
		||||
				),
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
							"šŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠"),
 | 
			
		||||
					},
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset:  LowercaseRuneset,
 | 
			
		||||
						MinChars: 1,
 | 
			
		||||
@@ -432,9 +435,11 @@ func BenchmarkStringGenerator_Generate(b *testing.B) {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		"restrictive charset rules": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
				charset: AlphaNumericShortSymbolRuneset,
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset: AlphaNumericShortSymbolRuneset,
 | 
			
		||||
					},
 | 
			
		||||
					CharsetRule{
 | 
			
		||||
						Charset:  []rune("A"),
 | 
			
		||||
						MinChars: 1,
 | 
			
		||||
@@ -551,7 +556,7 @@ func (badReader) Read([]byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
func TestValidate(t *testing.T) {
 | 
			
		||||
	type testCase struct {
 | 
			
		||||
		generator StringGenerator
 | 
			
		||||
		generator *StringGenerator
 | 
			
		||||
		expectErr bool
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -561,33 +566,33 @@ func TestValidate(t *testing.T) {
 | 
			
		||||
			expectErr: false,
 | 
			
		||||
		},
 | 
			
		||||
		"length is 0": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length: 0,
 | 
			
		||||
			},
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		"length is negative": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length: -2,
 | 
			
		||||
			},
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		"nil charset, no rules": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length:  5,
 | 
			
		||||
				charset: nil,
 | 
			
		||||
			},
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		"zero length charset, no rules": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length:  5,
 | 
			
		||||
				charset: []rune{},
 | 
			
		||||
			},
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		"rules require password longer than length": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length:  5,
 | 
			
		||||
				charset: []rune("abcde"),
 | 
			
		||||
				Rules: []Rule{
 | 
			
		||||
@@ -600,7 +605,7 @@ func TestValidate(t *testing.T) {
 | 
			
		||||
			expectErr: true,
 | 
			
		||||
		},
 | 
			
		||||
		"charset has non-printable characters": {
 | 
			
		||||
			generator: StringGenerator{
 | 
			
		||||
			generator: &StringGenerator{
 | 
			
		||||
				Length: 0,
 | 
			
		||||
				charset: []rune{
 | 
			
		||||
					'a',
 | 
			
		||||
 
 | 
			
		||||
@@ -194,3 +194,16 @@ func (d StaticSystemView) GeneratePasswordFromPolicy(ctx context.Context, policy
 | 
			
		||||
	}
 | 
			
		||||
	return policy.Generate(ctx, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *StaticSystemView) SetPasswordPolicy(name string, policy PasswordPolicy) {
 | 
			
		||||
	if d.PasswordPolicies == nil {
 | 
			
		||||
		d.PasswordPolicies = map[string]PasswordPolicy{}
 | 
			
		||||
	}
 | 
			
		||||
	d.PasswordPolicies[name] = policy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *StaticSystemView) DeletePasswordPolicy(name string) (existed bool) {
 | 
			
		||||
	_, existed = d.PasswordPolicies[name]
 | 
			
		||||
	delete(d.PasswordPolicies, name)
 | 
			
		||||
	return existed
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3188,7 +3188,7 @@ func TestHandlePoliciesPasswordGenerate(t *testing.T) {
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("success", func(t *testing.T) {
 | 
			
		||||
		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
 | 
			
		||||
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
			
		||||
		defer cancel()
 | 
			
		||||
 | 
			
		||||
		policyEntry := storageEntry(t, "testpolicy",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/hashicorp/vault/sdk/helper/random/string_generator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/hashicorp/vault/sdk/helper/random/string_generator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -37,7 +37,7 @@ var (
 | 
			
		||||
	AlphaNumericFullSymbolRuneset  = []rune(AlphaNumericFullSymbolCharset)
 | 
			
		||||
 | 
			
		||||
	// DefaultStringGenerator has reasonable default rules for generating strings
 | 
			
		||||
	DefaultStringGenerator = StringGenerator{
 | 
			
		||||
	DefaultStringGenerator = &StringGenerator{
 | 
			
		||||
		Length: 20,
 | 
			
		||||
		Rules: []Rule{
 | 
			
		||||
			CharsetRule{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/hashicorp/vault/sdk/logical/system_view.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/hashicorp/vault/sdk/logical/system_view.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -194,3 +194,16 @@ func (d StaticSystemView) GeneratePasswordFromPolicy(ctx context.Context, policy
 | 
			
		||||
	}
 | 
			
		||||
	return policy.Generate(ctx, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *StaticSystemView) SetPasswordPolicy(name string, policy PasswordPolicy) {
 | 
			
		||||
	if d.PasswordPolicies == nil {
 | 
			
		||||
		d.PasswordPolicies = map[string]PasswordPolicy{}
 | 
			
		||||
	}
 | 
			
		||||
	d.PasswordPolicies[name] = policy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *StaticSystemView) DeletePasswordPolicy(name string) (existed bool) {
 | 
			
		||||
	_, existed = d.PasswordPolicies[name]
 | 
			
		||||
	delete(d.PasswordPolicies, name)
 | 
			
		||||
	return existed
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,17 +26,16 @@ RabbitMQ.
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
- `connection_uri` `(string: <required>)` – Specifies the RabbitMQ connection
 | 
			
		||||
  URI.
 | 
			
		||||
- `connection_uri` `(string: <required>)` – Specifies the RabbitMQ connection URI.
 | 
			
		||||
 | 
			
		||||
- `username` `(string: <required>)` – Specifies the RabbitMQ management
 | 
			
		||||
  administrator username.
 | 
			
		||||
- `username` `(string: <required>)` – Specifies the RabbitMQ management administrator username.
 | 
			
		||||
 | 
			
		||||
- `password` `(string: <required>)` – Specifies the RabbitMQ management
 | 
			
		||||
  administrator password.
 | 
			
		||||
- `password` `(string: <required>)` – Specifies the RabbitMQ management administrator password.
 | 
			
		||||
 | 
			
		||||
- `verify_connection` `(bool: true)` – Specifies whether to verify connection
 | 
			
		||||
  URI, username, and password.
 | 
			
		||||
- `verify_connection` `(bool: true)` – Specifies whether to verify connection URI, username, and password.
 | 
			
		||||
 | 
			
		||||
- `password_policy` `(string: "")` - Specifies a [password policy](/docs/concepts/password-policies) to
 | 
			
		||||
  use when creating dynamic credentials. Defaults to generating an alphanumeric password if not set.
 | 
			
		||||
 | 
			
		||||
### Sample Payload
 | 
			
		||||
 | 
			
		||||
@@ -44,12 +43,16 @@ RabbitMQ.
 | 
			
		||||
{
 | 
			
		||||
  "connection_uri": "https://...",
 | 
			
		||||
  "username": "user",
 | 
			
		||||
  "password": "password"
 | 
			
		||||
  "password": "password",
 | 
			
		||||
  "password_policy": "rabbitmq_policy"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
@@ -57,6 +60,18 @@ $ curl \
 | 
			
		||||
    --data @payload.json \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/config/connection
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ vault write rabbitmq/config/connection \
 | 
			
		||||
    connection_uri="http://localhost:8080" \
 | 
			
		||||
    username="user" \
 | 
			
		||||
    password="password" \
 | 
			
		||||
    password_policy="rabbitmq_policy"
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## Configure Lease
 | 
			
		||||
 | 
			
		||||
@@ -83,6 +98,9 @@ This endpoint configures the lease settings for generated credentials.
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
@@ -90,6 +108,16 @@ $ curl \
 | 
			
		||||
    --data @payload.json \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/config/lease
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ vault write rabbitmq/config/lease \
 | 
			
		||||
    ttl=1800 \
 | 
			
		||||
    max_ttl=3600
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## Create Role
 | 
			
		||||
 | 
			
		||||
@@ -124,6 +152,9 @@ This endpoint creates or updates the role definition.
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
@@ -131,6 +162,17 @@ $ curl \
 | 
			
		||||
    --data @payload.json \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/roles/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ vault write rabbitmq/roles/my-role \
 | 
			
		||||
    tags="tag1,tag2" \
 | 
			
		||||
    vhosts="..." \
 | 
			
		||||
    vhost_topics="..."
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## Read Role
 | 
			
		||||
 | 
			
		||||
@@ -147,11 +189,22 @@ This endpoint queries the role definition.
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/roles/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ vault read rabbitmq/roles/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
### Sample Response
 | 
			
		||||
 | 
			
		||||
@@ -180,12 +233,23 @@ This endpoint deletes the role definition.
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
    --request DELETE \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/roles/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
vault delete rabbitmq/roles/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## Generate Credentials
 | 
			
		||||
 | 
			
		||||
@@ -203,11 +267,22 @@ role.
 | 
			
		||||
 | 
			
		||||
### Sample Request
 | 
			
		||||
 | 
			
		||||
<Tabs>
 | 
			
		||||
<Tab heading="cURL">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ curl \
 | 
			
		||||
    --header "X-Vault-Token: ..." \
 | 
			
		||||
    http://127.0.0.1:8200/v1/rabbitmq/creds/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
<Tab heading="CLI">
 | 
			
		||||
 | 
			
		||||
```shell-session
 | 
			
		||||
$ vault read rabbitmq/creds/my-role
 | 
			
		||||
```
 | 
			
		||||
</Tab>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
### Sample Response
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -81,11 +81,11 @@ the proper permission, it can generate credentials.
 | 
			
		||||
    $ vault read rabbitmq/creds/my-role
 | 
			
		||||
    Key                Value
 | 
			
		||||
    ---                -----
 | 
			
		||||
    lease_id           rabbitmq/creds/my-role/37d70d04-f24d-760a-e06e-b9b21087f0f4
 | 
			
		||||
    lease_id           rabbitmq/creds/my-role/I39Hu8XXOombof4wiK5bKMn9
 | 
			
		||||
    lease_duration     768h
 | 
			
		||||
    lease_renewable    true
 | 
			
		||||
    password           a98af72b-b6c9-b4b1-fe37-c73a572befed
 | 
			
		||||
    username           token-590f1fe2-1094-a4d6-01a7-9d4ff756a085
 | 
			
		||||
    password           3yNDBikgQvrkx2VA2zhq5IdSM7IWk1RyMYJr
 | 
			
		||||
    username           root-39669250-3894-8032-c420-3d58483ebfc4
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
    Using ACLs, it is possible to restrict using the rabbitmq secrets engine
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user