Merge remote-tracking branch 'oss/master' into sys-tidy-leases

This commit is contained in:
Jeff Mitchell 2017-05-03 15:02:42 -04:00
commit 99884a8f13
17 changed files with 142 additions and 26 deletions

View file

@ -21,18 +21,21 @@ FEATURES:
IMPROVEMENTS: IMPROVEMENTS:
* auth/cert: Support for constraints on subject common name, DNS names and * auth/cert: Support for constraints on subject Common Name and DNS/email
Email addresses in the certificate [GH-2595] Subject Alternate Names in certificates [GH-2595]
* auth/ldap: Use the binding credentials to search group membership rather * auth/ldap: Use the binding credentials to search group membership rather
than the user credentials [GH-2534] than the user credentials [GH-2534]
* cli/revoke: Add `-self` option to allow revoking the currently active token * cli/revoke: Add `-self` option to allow revoking the currently active token
[GH-2596] [GH-2596]
* core: Randomizing x coordinate in Shamir shares [GH-2621]
* secret/pki: Add `no_store` option that allows certificates to be issued * secret/pki: Add `no_store` option that allows certificates to be issued
without being stored. This removes the ability to look up and/or add to a without being stored. This removes the ability to look up and/or add to a
CRL but helps with scaling to very large numbers of certificates. [GH-2565] CRL but helps with scaling to very large numbers of certificates. [GH-2565]
* secret/pki: If used with a role parameter, the `sign-verbatim/<role>` * secret/pki: If used with a role parameter, the `sign-verbatim/<role>`
endpoint honors the values of `generate_lease`, `no_store`, `ttl` and endpoint honors the values of `generate_lease`, `no_store`, `ttl` and
`max_ttl` from the given role [GH-2593] `max_ttl` from the given role [GH-2593]
* secret/pki: Add role parameter `allow_glob_domains` that enables defining
names in `allowed_domains` containing `*` glob patterns [GH-2517]
* storage/etcd3: Add `discovery_srv` option to query for SRV records to find * storage/etcd3: Add `discovery_srv` option to query for SRV records to find
servers [GH-2521] servers [GH-2521]
* storage/s3: Support `max_parallel` option to limit concurrent outstanding * storage/s3: Support `max_parallel` option to limit concurrent outstanding

View file

@ -104,7 +104,7 @@ func TestAppRole_RoleConstraints(t *testing.T) {
roleData["bind_secret_id"] = false roleData["bind_secret_id"] = false
resp, err = b.HandleRequest(roleReq) resp, err = b.HandleRequest(roleReq)
if resp != nil && resp.IsError() { if resp != nil && resp.IsError() {
t.Fatalf("resp:%#v", err, resp) t.Fatalf("err:%v, resp:%#v", err, resp)
} }
if err == nil { if err == nil {
t.Fatalf("expected an error") t.Fatalf("expected an error")
@ -433,7 +433,7 @@ func TestAppRole_RoleSecretIDAccessorReadDelete(t *testing.T) {
hmacReq.Operation = logical.ReadOperation hmacReq.Operation = logical.ReadOperation
resp, err = b.HandleRequest(hmacReq) resp, err = b.HandleRequest(hmacReq)
if resp != nil && resp.IsError() { if resp != nil && resp.IsError() {
t.Fatalf("error response:%#v", err, resp) t.Fatalf("err:%v resp:%#v", err, resp)
} }
if err == nil { if err == nil {
t.Fatalf("expected an error") t.Fatalf("expected an error")

View file

@ -352,7 +352,7 @@ func (b *backend) nonLockedSecretIDStorageEntry(s logical.Storage, roleNameHMAC,
if persistNeeded { if persistNeeded {
if err := b.nonLockedSetSecretIDStorageEntry(s, roleNameHMAC, secretIDHMAC, &result); err != nil { if err := b.nonLockedSetSecretIDStorageEntry(s, roleNameHMAC, secretIDHMAC, &result); err != nil {
return nil, fmt.Errorf("failed to upgrade role storage entry", err) return nil, fmt.Errorf("failed to upgrade role storage entry %s", err)
} }
} }

View file

@ -249,17 +249,18 @@ func TestBackend_pathIam(t *testing.T) {
// generate a second role, ensure we're able to list both // generate a second role, ensure we're able to list both
data["bound_ami_id"] = "ami-abcd123" data["bound_ami_id"] = "ami-abcd123"
resp, err = b.HandleRequest(&logical.Request{ secondRole := &logical.Request{
Operation: logical.CreateOperation, Operation: logical.CreateOperation,
Path: "role/MyOtherRoleName", Path: "role/MyOtherRoleName",
Data: data, Data: data,
Storage: storage, Storage: storage,
}) }
resp, err = b.HandleRequest(secondRole)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if resp != nil && resp.IsError() { if resp != nil && resp.IsError() {
t.Fatalf("failed to create additional role: %s") t.Fatalf("failed to create additional role: %v", *secondRole)
} }
resp, err = b.HandleRequest(&logical.Request{ resp, err = b.HandleRequest(&logical.Request{

View file

@ -400,7 +400,7 @@ func (c *ConfigEntry) DialLDAP() (*ldap.Conn, error) {
} }
conn, err = ldap.DialTLS("tcp", net.JoinHostPort(host, port), tlsConfig) conn, err = ldap.DialTLS("tcp", net.JoinHostPort(host, port), tlsConfig)
default: default:
retErr = multierror.Append(retErr, fmt.Errorf("invalid LDAP scheme in url %q")) retErr = multierror.Append(retErr, fmt.Errorf("invalid LDAP scheme in url %q", net.JoinHostPort(host, port)))
continue continue
} }
if err == nil { if err == nil {

View file

@ -1549,6 +1549,7 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
Wildcard bool `structs:"*.example.com"` Wildcard bool `structs:"*.example.com"`
SubSubdomain bool `structs:"foo.bar.example.com"` SubSubdomain bool `structs:"foo.bar.example.com"`
SubSubdomainWildcard bool `structs:"*.bar.example.com"` SubSubdomainWildcard bool `structs:"*.bar.example.com"`
GlobDomain bool `structs:"fooexample.com"`
NonHostname bool `structs:"daɪˈɛrɨsɨs"` NonHostname bool `structs:"daɪˈɛrɨsɨs"`
AnyHost bool `structs:"porkslap.beer"` AnyHost bool `structs:"porkslap.beer"`
} }
@ -1755,6 +1756,11 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
commonNames.BareDomain = true commonNames.BareDomain = true
addCnTests() addCnTests()
roleVals.AllowedDomains = "foobar.com,*example.com"
roleVals.AllowGlobDomains = true
commonNames.GlobDomain = true
addCnTests()
roleVals.AllowAnyName = true roleVals.AllowAnyName = true
roleVals.EnforceHostnames = true roleVals.EnforceHostnames = true
commonNames.AnyHost = true commonNames.AnyHost = true

View file

@ -22,6 +22,7 @@ import (
"github.com/hashicorp/vault/helper/strutil" "github.com/hashicorp/vault/helper/strutil"
"github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework" "github.com/hashicorp/vault/logical/framework"
"github.com/ryanuber/go-glob"
) )
type certExtKeyUsage int type certExtKeyUsage int
@ -362,6 +363,13 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) string
break break
} }
} }
if role.AllowGlobDomains &&
strings.Contains(currDomain, "*") &&
glob.Glob(currDomain, name) {
valid = true
break
}
} }
if valid { if valid {
continue continue

View file

@ -84,6 +84,14 @@ including wildcard subdomains. See the documentation for
more information.`, more information.`,
}, },
"allow_glob_domains": &framework.FieldSchema{
Type: framework.TypeBool,
Default: false,
Description: `If set, domains specified in "allowed_domains"
can include glob patterns, e.g. "ftp*.example.com". See
the documentation for more information.`,
},
"allow_any_name": &framework.FieldSchema{ "allow_any_name": &framework.FieldSchema{
Type: framework.TypeBool, Type: framework.TypeBool,
Default: false, Default: false,
@ -380,6 +388,7 @@ func (b *backend) pathRoleCreate(
AllowedDomains: data.Get("allowed_domains").(string), AllowedDomains: data.Get("allowed_domains").(string),
AllowBareDomains: data.Get("allow_bare_domains").(bool), AllowBareDomains: data.Get("allow_bare_domains").(bool),
AllowSubdomains: data.Get("allow_subdomains").(bool), AllowSubdomains: data.Get("allow_subdomains").(bool),
AllowGlobDomains: data.Get("allow_glob_domains").(bool),
AllowAnyName: data.Get("allow_any_name").(bool), AllowAnyName: data.Get("allow_any_name").(bool),
EnforceHostnames: data.Get("enforce_hostnames").(bool), EnforceHostnames: data.Get("enforce_hostnames").(bool),
AllowIPSANs: data.Get("allow_ip_sans").(bool), AllowIPSANs: data.Get("allow_ip_sans").(bool),
@ -505,6 +514,7 @@ type roleEntry struct {
AllowBareDomains bool `json:"allow_bare_domains" structs:"allow_bare_domains" mapstructure:"allow_bare_domains"` AllowBareDomains bool `json:"allow_bare_domains" structs:"allow_bare_domains" mapstructure:"allow_bare_domains"`
AllowTokenDisplayName bool `json:"allow_token_displayname" structs:"allow_token_displayname" mapstructure:"allow_token_displayname"` AllowTokenDisplayName bool `json:"allow_token_displayname" structs:"allow_token_displayname" mapstructure:"allow_token_displayname"`
AllowSubdomains bool `json:"allow_subdomains" structs:"allow_subdomains" mapstructure:"allow_subdomains"` AllowSubdomains bool `json:"allow_subdomains" structs:"allow_subdomains" mapstructure:"allow_subdomains"`
AllowGlobDomains bool `json:"allow_glob_domains" structs:"allow_glob_domains" mapstructure:"allow_glob_domains"`
AllowAnyName bool `json:"allow_any_name" structs:"allow_any_name" mapstructure:"allow_any_name"` AllowAnyName bool `json:"allow_any_name" structs:"allow_any_name" mapstructure:"allow_any_name"`
EnforceHostnames bool `json:"enforce_hostnames" structs:"enforce_hostnames" mapstructure:"enforce_hostnames"` EnforceHostnames bool `json:"enforce_hostnames" structs:"enforce_hostnames" mapstructure:"enforce_hostnames"`
AllowIPSANs bool `json:"allow_ip_sans" structs:"allow_ip_sans" mapstructure:"allow_ip_sans"` AllowIPSANs bool `json:"allow_ip_sans" structs:"allow_ip_sans" mapstructure:"allow_ip_sans"`

View file

@ -48,7 +48,7 @@ func (c *CredentialsConfig) GenerateCredentialChain() (*credentials.Credentials,
SecretAccessKey: c.SecretKey, SecretAccessKey: c.SecretKey,
SessionToken: c.SessionToken, SessionToken: c.SessionToken,
}}) }})
case c.AccessKey == "" && c.AccessKey == "": case c.AccessKey == "" && c.SecretKey == "":
// Attempt to get credentials from the IAM instance role below // Attempt to get credentials from the IAM instance role below
default: // Have one or the other but not both and not neither default: // Have one or the other but not both and not neither

View file

@ -248,7 +248,7 @@ func (lm *LockManager) getPolicyCommon(req PolicyRequest, lockType bool) (*Polic
case KeyType_ECDSA_P256: case KeyType_ECDSA_P256:
if req.Derived || req.Convergent { if req.Derived || req.Convergent {
return nil, nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %s", KeyType_ECDSA_P256) return nil, nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", KeyType_ECDSA_P256)
} }
default: default:

View file

@ -95,7 +95,7 @@ func TestRouter_Mount(t *testing.T) {
} }
if v := r.MatchingStorageView("prod/aws/foo"); v != view { if v := r.MatchingStorageView("prod/aws/foo"); v != view {
t.Fatalf("bad: %s", v) t.Fatalf("bad: %v", v)
} }
if path := r.MatchingMount("stage/aws/foo"); path != "" { if path := r.MatchingMount("stage/aws/foo"); path != "" {
@ -103,7 +103,7 @@ func TestRouter_Mount(t *testing.T) {
} }
if v := r.MatchingStorageView("stage/aws/foo"); v != nil { if v := r.MatchingStorageView("stage/aws/foo"); v != nil {
t.Fatalf("bad: %s", v) t.Fatalf("bad: %v", v)
} }
mount, prefix, ok := r.MatchingStoragePrefix("logical/foo") mount, prefix, ok := r.MatchingStoragePrefix("logical/foo")

View file

@ -2232,7 +2232,7 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(
} }
resp.AddWarning(fmt.Sprintf( resp.AddWarning(fmt.Sprintf(
"Given explicit max TTL of %d is greater than system/mount allowed value of %d seconds; until this is fixed attempting to create tokens against this role will result in an error", "Given explicit max TTL of %d is greater than system/mount allowed value of %d seconds; until this is fixed attempting to create tokens against this role will result in an error",
entry.ExplicitMaxTTL.Seconds(), sysView.MaxLeaseTTL().Seconds())) int64(entry.ExplicitMaxTTL.Seconds()), int64(sysView.MaxLeaseTTL().Seconds())))
} }
} }

View file

@ -336,7 +336,7 @@ role.
```json ```json
{ {
"ttl": "5m" "ttl": "15m"
} }
``` ```

View file

@ -490,7 +490,7 @@ based on the role named in the endpoint. The issuing CA certificate is returned
as well, so that only the root CA need be in a client's trust store. as well, so that only the root CA need be in a client's trust store.
**The private key is _not_ stored. If you do not save the private key, you will **The private key is _not_ stored. If you do not save the private key, you will
**need to request a new certificate.** need to request a new certificate.**
| Method | Path | Produces | | Method | Path | Produces |
| :------- | :--------------------------- | :--------------------- | | :------- | :--------------------------- | :--------------------- |
@ -613,12 +613,13 @@ $ curl \
## Create/Update Role ## Create/Update Role
This endpoint ceates or updates the role definition. Note that the This endpoint creates or updates the role definition. Note that the
`allowed_domains`, `allow_subdomains`, and `allow_any_name` attributes are `allowed_domains`, `allow_subdomains`, `allow_glob_domains`, and
additive; between them nearly and across multiple roles nearly any issuing `allow_any_name` attributes are additive; between them nearly and across
policy can be accommodated. `server_flag`, `client_flag`, and multiple roles nearly any issuing policy can be accommodated. `server_flag`,
`code_signing_flag` are additive as well. If a client requests a certificate `client_flag`, and `code_signing_flag` are additive as well. If a client
that is not allowed by the CN policy in the role, the request is denied. requests a certificate that is not allowed by the CN policy in the role, the
request is denied.
| Method | Path | Produces | | Method | Path | Produces |
| :------- | :--------------------------- | :--------------------- | | :------- | :--------------------------- | :--------------------- |
@ -659,6 +660,11 @@ that is not allowed by the CN policy in the role, the request is denied.
allow `foo.example.com` and `bar.example.com` as well as `*.example.com`. This allow `foo.example.com` and `bar.example.com` as well as `*.example.com`. This
is redundant when using the `allow_any_name` option. is redundant when using the `allow_any_name` option.
- `allow_glob_domains` `(bool: false)` - Allows names specified in
`allowed_domains` to contain glob patterns (e.g. `ftp*.example.com`). Clients
will be allowed to request certificates with names matching the glob
patterns.
- `allow_any_name` `(bool: false)`  Specifies if clients can request any CN. - `allow_any_name` `(bool: false)`  Specifies if clients can request any CN.
Useful in some circumstances, but make sure you understand whether it is Useful in some circumstances, but make sure you understand whether it is
appropriate for your installation before enabling it. appropriate for your installation before enabling it.

View file

@ -97,9 +97,10 @@ to specify where the configuration is.
duration for tokens and secrets. This is specified using a label duration for tokens and secrets. This is specified using a label
suffix like `"30s"` or `"1h"`. suffix like `"30s"` or `"1h"`.
- `ui` `(bool: false, Enterprise-only)` Enables the built-in web UI. Once - `ui` `(bool: false, Enterprise-only)` Enables the built-in web UI, which is
enabled, the UI will be available to browsers at the standard Vault address. available on all listeners (address + port) at the `/ui` path. Browsers accessing
This can also be provided via the environment variable `VAULT_UI`. the standard Vault API address will automatically redirect there. This can also
be provided via the environment variable `VAULT_UI`.
[storage-backend]: /docs/configuration/storage/index.html [storage-backend]: /docs/configuration/storage/index.html
[listener]: /docs/configuration/listener/index.html [listener]: /docs/configuration/listener/index.html

View file

@ -0,0 +1,78 @@
---
layout: "docs"
page_title: "Vault Enterprise UI"
sidebar_current: "docs-vault-enterprise-ui"
description: |-
Vault Enterprise features a user interface for interacting with Vault. Easily
create, read, update, and delete secrets, authenticate, unseal, and more with
the Vault Enterprise UI.
---
# Vault UI
Vault Enterprise features a user interface for interacting with Vault. Easily
create, read, update, and delete secrets, authenticate, unseal, and more with
the Vault Enterprise UI.
To use the UI, you must have an active or trial license for Vault Enterprise or
Vault Pro. To start a trial, contact [HashiCorp sales](mailto:sales@hashicorp.com).
## Activating the Vault UI
The Vault Enterprise UI is not activated by default. To activate the UI, set the
`ui` configuration option in the Vault server configuration. Vault clients do
not need to set this option, since they will not be serving the UI.
```hcl
ui = true
listener "tcp" {
address = "10.0.1.35:8200"
}
storage "consul" {
# ...
}
```
For more information, please see the
[Vault configuration options](/docs/configuration/index.html).
## Accessing the Vault UI
The UI runs on the same port as the Vault listener. As such, you must configure
at least one `listener` stanza in order to access the UI.
```hcl
listener "tcp" {
address = "10.0.1.35:8200"
# If bound to localhost, the Vault UI is only
# accessible from the local machine!
# address = "127.0.0.1:8200"
}
```
In this case, the UI is accessible the following URL from any machine on the
subnet (provided no network firewalls are in place):
```text
https://10.0.1.35:8200/ui
```
It is also accessible at any DNS entry that resolves to that IP address, such as
the Consul service address (if using Consul):
```text
https://vault.service.consul:8200/ui
```
### Note on TLS
When using TLS (recommended), the certificate must be valid for all DNS entries
you will be accessing the Vault UI on, and any IP addresses on the SAN. If you
are running Vault with a self-signed certificate, any browsers that access the
Vault UI will need to have the root CA installed. Failure to do so may result in
the browser displaying a warning that the site is "untrusted". It is highly
recommended that client browsers accessing the Vault UI install the proper CA
root for validation to reduce the chance of a MITM attack.

View file

@ -356,6 +356,9 @@
</li> </li>
</ul> </ul>
</li> </li>
<li<%= sidebar_current("docs-vault-enterprise-ui") %>>
<a href="/docs/vault-enterprise/ui/index.html">UI (Web Interface)</a>
</li>
</ul> </ul>
</li> </li>
</ul> </ul>