diff --git a/go.mod b/go.mod
index a418c691f..9b315839c 100644
--- a/go.mod
+++ b/go.mod
@@ -83,7 +83,7 @@ require (
github.com/hashicorp/vault-plugin-auth-oci v0.5.4
github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4
github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0-beta1.0.20200521152755-9cf156a44f9c
- github.com/hashicorp/vault-plugin-secrets-ad v0.6.4-beta1.0.20200518124111-3dceeb3ce90e
+ github.com/hashicorp/vault-plugin-secrets-ad v0.6.6
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5
github.com/hashicorp/vault-plugin-secrets-azure v0.5.6
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2
@@ -92,7 +92,7 @@ require (
github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2
github.com/hashicorp/vault-plugin-secrets-openldap v0.1.3
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f
- github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267
+ github.com/hashicorp/vault/sdk v0.1.14-0.20200527182800-ad90e0b39d2f
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
github.com/jcmturner/gokrb5/v8 v8.0.0
github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f
diff --git a/go.sum b/go.sum
index a77b4318b..497135683 100644
--- a/go.sum
+++ b/go.sum
@@ -471,8 +471,6 @@ github.com/hashicorp/nomad/api v0.0.0-20191220223628-edc62acd919d/go.mod h1:WKCL
github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI=
github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17 h1:p+2EISNdFCnD9R+B4xCiqSn429MCFtvM41aHJDJ6qW4=
github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
-github.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c=
-github.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
github.com/hashicorp/raft v1.1.3-0.20200501224250-c95aa91e604e h1:hMRRBhY9cayPJzEgNGNAl74TJ0rwY3Csbr43ogjKh1I=
github.com/hashicorp/raft v1.1.3-0.20200501224250-c95aa91e604e/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
@@ -504,8 +502,8 @@ github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4 h1:YE4qndazWmYGp
github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4/go.mod h1:QjGrrxcRXv/4XkEZAlM0VMZEa3uxKAICFqDj27FP/48=
github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0-beta1.0.20200521152755-9cf156a44f9c h1:9pXwe7sEVhZ5C3U6egIrKaZBb5lD0FvLIjISEvpbQQA=
github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0-beta1.0.20200521152755-9cf156a44f9c/go.mod h1:HTXNzFr/SAVtJOs7jz0XxZ69jlKtaceEwp37l86UAQ0=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.4-beta1.0.20200518124111-3dceeb3ce90e h1:0GK1BNBfglD2sydZ4XXMjJElhY8bC2TDdc0vk1Q9zbA=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.4-beta1.0.20200518124111-3dceeb3ce90e/go.mod h1:SCsKcChP8yrtOHXOeTD7oRk0oflj3IxA9y9zTOGtQ8s=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.6 h1:GskxrCCL2flrBtnAeOsBV+whCaqnnM/+t/h1IyqukNo=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.6/go.mod h1:L5L6NoJFxRvgxhuA2sWhloc3sbgmE7KxhNcoRxcaH9U=
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5 h1:BOOtSls+BQ1EtPmpE9LoqZztsEZ1fRWVSkHWtRIrCB4=
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5/go.mod h1:gAoReoUpBHaBwkxQqTK7FY8nQC0MuaZHLiW5WOSny5g=
github.com/hashicorp/vault-plugin-secrets-azure v0.5.6 h1:4PgQ5rCT29wW5PMyebEhPkEYuR5s+SnInuZz3x2cP50=
diff --git a/vendor/github.com/hashicorp/raft/.golangci-lint.yml b/vendor/github.com/hashicorp/raft/.golangci-lint.yml
new file mode 100644
index 000000000..a021e196e
--- /dev/null
+++ b/vendor/github.com/hashicorp/raft/.golangci-lint.yml
@@ -0,0 +1,49 @@
+run:
+ deadline: 5m
+
+linters-settings:
+ govet:
+ check-shadowing: true
+ golint:
+ min-confidence: 0
+
+linters:
+ disable-all: true
+ enable:
+ - gofmt
+ #- golint
+ - govet
+ #- varcheck
+ #- typecheck
+ #- gosimple
+
+issues:
+ exclude-use-default: false
+ exclude:
+ # ignore the false positive erros resulting from not including a comment above every `package` keyword
+ - should have a package comment, unless it's in another file for this package (golint)
+ # golint: Annoying issue about not having a comment. The rare codebase has such comments
+ # - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)
+ # errcheck: Almost all programs ignore errors on these functions and in most cases it's ok
+ - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked
+
+ # golint: False positive when tests are defined in package 'test'
+ - func name will be used as test\.Test.* by other packages, and that stutters; consider calling this
+
+ # staticcheck: Developers tend to write in C-style with an
+ # explicit 'break' in a 'switch', so it's ok to ignore
+ - ineffective break statement. Did you mean to break out of the outer loop
+ # gosec: Too many false-positives on 'unsafe' usage
+ - Use of unsafe calls should be audited
+
+ # gosec: Too many false-positives for parametrized shell calls
+ - Subprocess launch(ed with variable|ing should be audited)
+
+ # gosec: Duplicated errcheck checks
+ - G104
+
+ # gosec: Too many issues in popular repos
+ - (Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)
+
+ # gosec: False positive is triggered by 'src, err := ioutil.ReadFile(filename)'
+ - Potential file inclusion via variable
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/backend.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/backend.go
index 6174e159f..f1ddbb3cc 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/backend.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/backend.go
@@ -14,21 +14,22 @@ import (
)
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
- backend := newBackend(util.NewSecretsClient(conf.Logger))
+ backend := newBackend(util.NewSecretsClient(conf.Logger), conf.System)
if err := backend.Setup(ctx, conf); err != nil {
return nil, err
}
return backend, nil
}
-func newBackend(client secretsClient) *backend {
+func newBackend(client secretsClient, passwordGenerator passwordGenerator) *backend {
adBackend := &backend{
client: client,
roleCache: cache.New(roleCacheExpiration, roleCacheCleanup),
credCache: cache.New(credCacheExpiration, credCacheCleanup),
rotateRootLock: new(int32),
checkOutHandler: &checkOutHandler{
- client: client,
+ client: client,
+ passwordGenerator: passwordGenerator,
},
checkOutLocks: locksutil.CreateLocks(),
}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/checkout_handler.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/checkout_handler.go
index 5b4c729aa..61d021446 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/checkout_handler.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/checkout_handler.go
@@ -3,7 +3,7 @@ package plugin
import (
"context"
"errors"
- "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util"
+
"github.com/hashicorp/vault/sdk/logical"
)
@@ -32,7 +32,8 @@ type CheckOut struct {
// checkOutHandler manages checkouts. It's not thread-safe and expects the caller to handle locking because
// locking may span multiple calls.
type checkOutHandler struct {
- client secretsClient
+ client secretsClient
+ passwordGenerator passwordGenerator
}
// CheckOut attempts to check out a service account. If the account is unavailable, it returns
@@ -98,7 +99,7 @@ func (h *checkOutHandler) CheckIn(ctx context.Context, storage logical.Storage,
if engineConf == nil {
return errors.New("the config is currently unset")
}
- newPassword, err := util.GeneratePassword(engineConf.PasswordConf.Formatter, engineConf.PasswordConf.Length)
+ newPassword, err := GeneratePassword(ctx, engineConf.PasswordConf, h.passwordGenerator)
if err != nil {
return err
}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/config.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/config.go
new file mode 100644
index 000000000..90de64e91
--- /dev/null
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/config.go
@@ -0,0 +1,76 @@
+package plugin
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/vault-plugin-secrets-ad/plugin/client"
+)
+
+type configuration struct {
+ PasswordConf passwordConf
+ ADConf *client.ADConf
+ LastRotationTolerance int
+}
+
+type passwordConf struct {
+ TTL int `json:"ttl"`
+ MaxTTL int `json:"max_ttl"`
+
+ // Mutually exclusive with Length and Formatter
+ PolicyName string `json:"password_policy"`
+
+ // Length of the password to generate. Mutually exclusive with PolicyName.
+ // Deprecated
+ Length int `json:"length"`
+
+ // Formatter describes how to format a password. This allows for prefixes and suffixes on the password.
+ // Mutually exclusive with PolicyName.
+ // Deprecated
+ Formatter string `json:"formatter"`
+}
+
+func (c passwordConf) Map() map[string]interface{} {
+ return map[string]interface{}{
+ "ttl": c.TTL,
+ "max_ttl": c.MaxTTL,
+ "length": c.Length,
+ "formatter": c.Formatter,
+ "policy_name": c.PolicyName,
+ }
+}
+
+// validate returns an error if the configuration is invalid/unable to process for whatever reason.
+func (c passwordConf) validate() error {
+ if c.PolicyName != "" &&
+ (c.Length != 0 || c.Formatter != "") {
+ return fmt.Errorf("cannot set password_policy and either length or formatter")
+ }
+
+ // Don't validate the length and formatter fields if a policy is set
+ if c.PolicyName != "" {
+ return nil
+ }
+
+ // Check for if there's no formatter.
+ if c.Formatter == "" {
+ if c.Length < len(passwordComplexityPrefix)+minimumLengthOfComplexString {
+ return fmt.Errorf("it's not possible to generate a _secure_ password of length %d, please boost length to %d, though Vault recommends higher",
+ c.Length, minimumLengthOfComplexString+len(passwordComplexityPrefix))
+ }
+ return nil
+ }
+
+ // Check for if there is a formatter.
+ if lengthOfPassword(c.Formatter, c.Length) < minimumLengthOfComplexString {
+ return fmt.Errorf("since the desired length is %d, it isn't possible to generate a sufficiently complex password - please increase desired length or remove characters from the formatter", c.Length)
+ }
+ numPwdFields := strings.Count(c.Formatter, pwdFieldTmpl)
+ if numPwdFields == 0 {
+ return fmt.Errorf("%s must contain password replacement field of %s", c.Formatter, pwdFieldTmpl)
+ }
+ if numPwdFields > 1 {
+ return fmt.Errorf("%s must contain ONE password replacement field of %s", c.Formatter, pwdFieldTmpl)
+ }
+ return nil
+}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/engineconf.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/engineconf.go
deleted file mode 100644
index b2f4837cc..000000000
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/engineconf.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package plugin
-
-import (
- "github.com/hashicorp/vault-plugin-secrets-ad/plugin/client"
-)
-
-type configuration struct {
- PasswordConf *passwordConf
- ADConf *client.ADConf
- LastRotationTolerance int
-}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwordconf.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwordconf.go
deleted file mode 100644
index b43d4e12f..000000000
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwordconf.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package plugin
-
-type passwordConf struct {
- TTL int `json:"ttl"`
- MaxTTL int `json:"max_ttl"`
- Length int `json:"length"`
- Formatter string `json:"formatter"`
-}
-
-func (c *passwordConf) Map() map[string]interface{} {
- return map[string]interface{}{
- "ttl": c.TTL,
- "max_ttl": c.MaxTTL,
- "length": c.Length,
- "formatter": c.Formatter,
- }
-}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwords.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwords.go
new file mode 100644
index 000000000..c349f7229
--- /dev/null
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/passwords.go
@@ -0,0 +1,58 @@
+package plugin
+
+import (
+ "context"
+ "strings"
+
+ "github.com/hashicorp/vault/sdk/helper/base62"
+)
+
+var (
+ // Per https://en.wikipedia.org/wiki/Password_strength#Guidelines_for_strong_passwords
+ minimumLengthOfComplexString = 8
+
+ passwordComplexityPrefix = "?@09AZ"
+ pwdFieldTmpl = "{{PASSWORD}}"
+)
+
+type passwordGenerator interface {
+ GeneratePasswordFromPolicy(ctx context.Context, policyName string) (password string, err error)
+}
+
+// GeneratePassword from the password configuration. This will either generate based on a password policy
+// or from the provided formatter. The formatter/length options are deprecated.
+func GeneratePassword(ctx context.Context, passConf passwordConf, generator passwordGenerator) (password string, err error) {
+ err = passConf.validate()
+ if err != nil {
+ return "", err
+ }
+
+ if passConf.PolicyName != "" {
+ return generator.GeneratePasswordFromPolicy(ctx, passConf.PolicyName)
+ }
+ return generateDeprecatedPassword(passConf.Formatter, passConf.Length)
+}
+
+func generateDeprecatedPassword(formatter string, totalLength int) (string, error) {
+ // Has formatter
+ if formatter != "" {
+ passLen := lengthOfPassword(formatter, totalLength)
+ pwd, err := base62.Random(passLen)
+ if err != nil {
+ return "", err
+ }
+ return strings.Replace(formatter, pwdFieldTmpl, pwd, 1), nil
+ }
+
+ // Doesn't have formatter
+ pwd, err := base62.Random(totalLength - len(passwordComplexityPrefix))
+ if err != nil {
+ return "", err
+ }
+ return passwordComplexityPrefix + pwd, nil
+}
+
+func lengthOfPassword(formatter string, totalLength int) int {
+ lengthOfText := len(formatter) - len(pwdFieldTmpl)
+ return totalLength - lengthOfText
+}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_config.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_config.go
index a5345a890..ed8698ba7 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_config.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_config.go
@@ -3,10 +3,10 @@ package plugin
import (
"context"
"errors"
+ "fmt"
"time"
"github.com/hashicorp/vault-plugin-secrets-ad/plugin/client"
- "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/ldaputil"
"github.com/hashicorp/vault/sdk/logical"
@@ -32,13 +32,24 @@ func readConfig(ctx context.Context, storage logical.Storage) (*configuration, e
if entry == nil {
return nil, nil
}
- config := &configuration{&passwordConf{}, &client.ADConf{}, 0}
+ config := &configuration{}
if err := entry.DecodeJSON(config); err != nil {
return nil, err
}
return config, nil
}
+func writeConfig(ctx context.Context, storage logical.Storage, config *configuration) (err error) {
+ entry, err := logical.StorageEntryJSON(configStorageKey, config)
+ if err != nil {
+ return fmt.Errorf("unable to marshal config to JSON: %w", err)
+ }
+ if err := storage.Put(ctx, entry); err != nil {
+ return fmt.Errorf("unable to store config: %w", err)
+ }
+ return nil
+}
+
func (b *backend) pathConfig() *framework.Path {
return &framework.Path{
Pattern: configPath,
@@ -63,20 +74,28 @@ func (b *backend) configFields() map[string]*framework.FieldSchema {
Type: framework.TypeDurationSecond,
Description: "In seconds, the maximum password time-to-live.",
}
- fields["length"] = &framework.FieldSchema{
- Type: framework.TypeInt,
- Default: defaultPasswordLength,
- Description: "The desired length of passwords that Vault generates.",
- }
- fields["formatter"] = &framework.FieldSchema{
- Type: framework.TypeString,
- Description: `Text to insert the password into, ex. "customPrefix{{PASSWORD}}customSuffix".`,
- }
fields["last_rotation_tolerance"] = &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Description: "The number of seconds after a Vault rotation where, if Active Directory shows a later rotation, it should be considered out-of-band.",
Default: 5,
}
+ fields["password_policy"] = &framework.FieldSchema{
+ Type: framework.TypeString,
+ Description: "Name of the password policy to use to generate passwords.",
+ }
+
+ // Deprecated fields
+ fields["length"] = &framework.FieldSchema{
+ Type: framework.TypeInt,
+ Default: defaultPasswordLength,
+ Description: "The desired length of passwords that Vault generates.",
+ Deprecated: true,
+ }
+ fields["formatter"] = &framework.FieldSchema{
+ Type: framework.TypeString,
+ Description: `Text to insert the password into, ex. "customPrefix{{PASSWORD}}customSuffix".`,
+ Deprecated: true,
+ }
return fields
}
@@ -93,9 +112,11 @@ func (b *backend) configUpdateOperation(ctx context.Context, req *logical.Reques
// Build the password conf.
ttl := fieldData.Get("ttl").(int)
maxTTL := fieldData.Get("max_ttl").(int)
+ lastRotationTolerance := fieldData.Get("last_rotation_tolerance").(int)
+
length := fieldData.Get("length").(int)
formatter := fieldData.Get("formatter").(string)
- lastRotationTolerance := fieldData.Get("last_rotation_tolerance").(int)
+ passwordPolicy := fieldData.Get("password_policy").(string)
if pre111Val, ok := fieldData.GetOk("use_pre111_group_cn_behavior"); ok {
activeDirectoryConf.UsePre111GroupCNBehavior = new(bool)
@@ -120,23 +141,28 @@ func (b *backend) configUpdateOperation(ctx context.Context, req *logical.Reques
if maxTTL < 1 {
return nil, errors.New("max_ttl must be positive")
}
- if err := util.ValidatePwdSettings(formatter, length); err != nil {
- return nil, err
- }
- passwordConf := &passwordConf{
- TTL: ttl,
- MaxTTL: maxTTL,
- Length: length,
- Formatter: formatter,
+ passwordConf := passwordConf{
+ TTL: ttl,
+ MaxTTL: maxTTL,
+ Length: length,
+ Formatter: formatter,
+ PolicyName: passwordPolicy,
}
-
- config := &configuration{passwordConf, &client.ADConf{ConfigEntry: activeDirectoryConf}, lastRotationTolerance}
- entry, err := logical.StorageEntryJSON(configStorageKey, config)
+ err = passwordConf.validate()
if err != nil {
return nil, err
}
- if err := req.Storage.Put(ctx, entry); err != nil {
+
+ config := configuration{
+ PasswordConf: passwordConf,
+ ADConf: &client.ADConf{
+ ConfigEntry: activeDirectoryConf,
+ },
+ LastRotationTolerance: lastRotationTolerance,
+ }
+ err = writeConfig(ctx, req.Storage, &config)
+ if err != nil {
return nil, err
}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_creds.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_creds.go
index c2a192b9a..9e88ba342 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_creds.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_creds.go
@@ -7,7 +7,6 @@ import (
"time"
"github.com/go-errors/errors"
- "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
@@ -150,7 +149,7 @@ func (b *backend) credReadOperation(ctx context.Context, req *logical.Request, f
}
func (b *backend) generateAndReturnCreds(ctx context.Context, engineConf *configuration, storage logical.Storage, roleName string, role *backendRole, previousCred map[string]interface{}) (*logical.Response, error) {
- newPassword, err := util.GeneratePassword(engineConf.PasswordConf.Formatter, engineConf.PasswordConf.Length)
+ newPassword, err := GeneratePassword(ctx, engineConf.PasswordConf, b.System())
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_roles.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_roles.go
index 2f92f0bf1..1c4b864e0 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_roles.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_roles.go
@@ -221,7 +221,7 @@ func getServiceAccountName(fieldData *framework.FieldData) (string, error) {
return serviceAccountName, nil
}
-func getValidatedTTL(passwordConf *passwordConf, fieldData *framework.FieldData) (int, error) {
+func getValidatedTTL(passwordConf passwordConf, fieldData *framework.FieldData) (int, error) {
ttl := fieldData.Get("ttl").(int)
if ttl == 0 {
ttl = passwordConf.TTL
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_rotate_root_creds.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_rotate_root_creds.go
index 402a0aa79..d911eef9f 100644
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_rotate_root_creds.go
+++ b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/path_rotate_root_creds.go
@@ -8,7 +8,6 @@ import (
"sync/atomic"
"time"
- "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
@@ -38,7 +37,7 @@ func (b *backend) pathRotateCredentialsUpdate(ctx context.Context, req *logical.
return nil, errors.New("the config is currently unset")
}
- newPassword, err := util.GeneratePassword(engineConf.PasswordConf.Formatter, engineConf.PasswordConf.Length)
+ newPassword, err := GeneratePassword(ctx, engineConf.PasswordConf, b.System())
if err != nil {
return nil, err
}
@@ -58,7 +57,7 @@ func (b *backend) pathRotateCredentialsUpdate(ctx context.Context, req *logical.
engineConf.ADConf.BindPassword = newPassword
// Update the password locally.
- if pwdStoringErr := storePassword(ctx, req, engineConf); pwdStoringErr != nil {
+ if pwdStoringErr := writeConfig(ctx, req.Storage, engineConf); pwdStoringErr != nil {
// We were unable to store the new password locally. We can't continue in this state because we won't be able
// to roll any passwords, including our own to get back into a state of working. So, we need to roll back to
// the last password we successfully got into storage.
@@ -93,17 +92,6 @@ func (b *backend) rollBackPassword(ctx context.Context, engineConf *configuratio
return err
}
-func storePassword(ctx context.Context, req *logical.Request, engineConf *configuration) error {
- entry, err := logical.StorageEntryJSON(configStorageKey, engineConf)
- if err != nil {
- return err
- }
- if err := req.Storage.Put(ctx, entry); err != nil {
- return err
- }
- return nil
-}
-
const pathRotateCredentialsUpdateHelpSyn = `
Request to rotate the root credentials.
`
diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/util/passwords.go b/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/util/passwords.go
deleted file mode 100644
index a0c7cb013..000000000
--- a/vendor/github.com/hashicorp/vault-plugin-secrets-ad/plugin/util/passwords.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package util
-
-import (
- "encoding/base64"
- "fmt"
- "strings"
-
- "github.com/hashicorp/go-uuid"
-)
-
-var (
- // Per https://en.wikipedia.org/wiki/Password_strength#Guidelines_for_strong_passwords
- minimumLengthOfComplexString = 8
-
- PasswordComplexityPrefix = "?@09AZ"
- PwdFieldTmpl = "{{PASSWORD}}"
-)
-
-func GeneratePassword(formatter string, totalLength int) (string, error) {
- if err := ValidatePwdSettings(formatter, totalLength); err != nil {
- return "", err
- }
- pwd, err := generatePassword(totalLength)
- if err != nil {
- return "", err
- }
- if formatter == "" {
- pwd = PasswordComplexityPrefix + pwd
- return pwd[:totalLength], nil
- }
- return strings.Replace(formatter, PwdFieldTmpl, pwd[:lengthOfPassword(formatter, totalLength)], 1), nil
-}
-
-func ValidatePwdSettings(formatter string, totalLength int) error {
- // Check for if there's no formatter.
- if formatter == "" {
- if totalLength < len(PasswordComplexityPrefix)+minimumLengthOfComplexString {
- return fmt.Errorf("it's not possible to generate a _secure_ password of length %d, please boost length to %d, though Vault recommends higher", totalLength, minimumLengthOfComplexString+len(PasswordComplexityPrefix))
- }
- return nil
- }
-
- // Check for if there is a formatter.
- if lengthOfPassword(formatter, totalLength) < minimumLengthOfComplexString {
- return fmt.Errorf("since the desired length is %d, it isn't possible to generate a sufficiently complex password - please increase desired length or remove characters from the formatter", totalLength)
- }
- numPwdFields := strings.Count(formatter, PwdFieldTmpl)
- if numPwdFields == 0 {
- return fmt.Errorf("%s must contain password replacement field of %s", formatter, PwdFieldTmpl)
- }
- if numPwdFields > 1 {
- return fmt.Errorf("%s must contain ONE password replacement field of %s", formatter, PwdFieldTmpl)
- }
- return nil
-}
-
-func lengthOfPassword(formatter string, totalLength int) int {
- lengthOfText := len(formatter) - len(PwdFieldTmpl)
- return totalLength - lengthOfText
-}
-
-// generatePassword returns a password of a length AT LEAST as long as the desired length,
-// it may be longer.
-func generatePassword(desiredLength int) (string, error) {
- b, err := uuid.GenerateRandomBytes(desiredLength)
- if err != nil {
- return "", err
- }
- result := ""
- // Though the result should immediately be longer than the desiredLength,
- // do this in a loop to ensure there's absolutely no risk of a panic when slicing it down later.
- for len(result) <= desiredLength {
- // Encode to base64 because it's more complex.
- result += base64.StdEncoding.EncodeToString(b)
- }
- return result, nil
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 170003e27..b6922fd84 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -433,7 +433,7 @@ github.com/hashicorp/vault-plugin-auth-oci
github.com/hashicorp/vault-plugin-database-elasticsearch
# github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0-beta1.0.20200521152755-9cf156a44f9c
github.com/hashicorp/vault-plugin-database-mongodbatlas
-# github.com/hashicorp/vault-plugin-secrets-ad v0.6.4-beta1.0.20200518124111-3dceeb3ce90e
+# github.com/hashicorp/vault-plugin-secrets-ad v0.6.6
github.com/hashicorp/vault-plugin-secrets-ad/plugin
github.com/hashicorp/vault-plugin-secrets-ad/plugin/client
github.com/hashicorp/vault-plugin-secrets-ad/plugin/util
@@ -457,7 +457,7 @@ github.com/hashicorp/vault-plugin-secrets-openldap
github.com/hashicorp/vault-plugin-secrets-openldap/client
# github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f => ./api
github.com/hashicorp/vault/api
-# github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 => ./sdk
+# github.com/hashicorp/vault/sdk v0.1.14-0.20200527182800-ad90e0b39d2f => ./sdk
github.com/hashicorp/vault/sdk/database/dbplugin
github.com/hashicorp/vault/sdk/database/helper/connutil
github.com/hashicorp/vault/sdk/database/helper/credsutil
diff --git a/website/pages/api-docs/secret/ad/index.mdx b/website/pages/api-docs/secret/ad/index.mdx
index 12e6879bd..0e5157aad 100644
--- a/website/pages/api-docs/secret/ad/index.mdx
+++ b/website/pages/api-docs/secret/ad/index.mdx
@@ -21,10 +21,20 @@ The `config` endpoint configures the LDAP connection and binding parameters, as
### Password parameters
-- `ttl` (string, optional) - The default password time-to-live in seconds. Once the ttl has passed, a password will be rotated the next time it's requested.
-- `max_ttl` (string, optional) - The maximum password time-to-live in seconds. No role will be allowed to set a custom ttl greater than the `max_ttl`.
-- `length` (string, optional) - The desired password length. Defaults to 64. Minimum is 14.
-- `formatter` (string, optional) - Text into which the base64 password should be inserted, formatted like so: `mycustom{{PASSWORD}}`.
+- `ttl` `(int: "")` - The default password time-to-live in seconds. Once the ttl has passed, a password will
+ be rotated the next time it's requested.
+- `max_ttl` `(int: "")` - The maximum password time-to-live in seconds. No role will be allowed to set a
+ custom ttl greater than the `max_ttl`.
+- `password_policy` `(string: "")` - Name of the [password policy](/docs/concepts/password-policies) to use to
+ generate passwords from. Mutually exclusive with `length` and `formatter`.
+
+**Deprecated parameters**:
+- `length` (string, optional) - The desired password length. Defaults to 64. Minimum is 14. Mutually exclusive
+ with `password_policy`.
+- `formatter` (string, optional) - Text into which the base64 password should be inserted, formatted like so:
+ `mycustom{{PASSWORD}}`. Mutually exclusive with `password_policy`.
+
+The following statement is applicable when using `length` and/or `formatter`, but not `password_policy`:
To meet Microsoft's password complexity requirements, all passwords begin with "?@09AZ" unless a `formatter` is provided.
The `formatter` is for organizations with different, custom password requirements. It allows an organization to supply
@@ -68,6 +78,9 @@ valid AD credentials with proper permissions.
### Sample Post Request
+
+
+
```shell-session
$ curl \
--header "X-Vault-Token: ..." \
@@ -75,6 +88,18 @@ $ curl \
--data @payload.json \
http://127.0.0.1:8200/v1/ad/config
```
+
+
+
+```shell-session
+$ vault write ad/config \
+ binddn="domain-admin" \
+ bindpass="pa$$w0rd" \
+ url="ldaps://127.0.0.1" \
+ userdn="dc=example,dc=com"
+```
+
+
### Sample Post Payload
@@ -126,6 +151,9 @@ When adding a role, Vault verifies its associated service account exists.
### Sample Post Request
+
+
+
```shell-session
$ curl \
--header "X-Vault-Token: ..." \
@@ -133,6 +161,16 @@ $ curl \
--data @payload.json \
http://127.0.0.1:8200/v1/ad/roles/my-application
```
+
+
+
+```shell-session
+$ vault write ad/roles/my-application \
+ service_account_name="my-application@example.com" \
+ ttl=100
+```
+
+
### Sample Post Payload
@@ -172,12 +210,23 @@ The `creds` endpoint offers the credential information for a given role.
### Sample Get Request
+
+
+
```shell-session
$ curl \
--header "X-Vault-Token: ..." \
--request GET \
http://127.0.0.1:8200/v1/ad/creds/my-application
```
+
+
+
+```shell-session
+$ vault read ad/creds/my-application
+```
+
+
### Sample Get Response
diff --git a/website/pages/docs/secrets/ad/index.mdx b/website/pages/docs/secrets/ad/index.mdx
index c5cc41c3d..13123c568 100644
--- a/website/pages/docs/secrets/ad/index.mdx
+++ b/website/pages/docs/secrets/ad/index.mdx
@@ -3,10 +3,7 @@ layout: docs
page_title: Active Directory - Secrets Engines
sidebar_title: Active Directory
description: >-
- The Active Directory secrets engine for Vault generates passwords dynamically
- based on
-
- roles.
+ The Active Directory secrets engine allowing Vault to generate dynamic credentials.
---
# Active Directory Secrets Engine
@@ -29,6 +26,17 @@ will check them in when their lending period (or, "ttl", in Vault's language) en
## Password Rotation
+### Customizing Password Generation
+
+There are two ways of customizing how passwords are generated in the Active Directory secret engine:
+
+1. [Password Policies](/docs/concepts/password-policies)
+2. `length` and `formatter` fields within the [configuration](api-docs/secret/ad#password-parameters)
+
+Utilizing password policies is the recommended path as the `length` and `formatter` fields have
+been deprecated in favor of password policies. The `password_policy` field within the configuration
+cannot be specified alongside either `length` or `formatter` to prevent a confusing configuration.
+
### A Note on Lazy Rotation
To drive home the point that passwords are rotated "lazily", consider this scenario: