Vault 0.5

Feb 10 2016 Jeff Mitchell vault

We are proud to announce the release of Vault 0.5. This release focuses on Vault's core capabilities. Significant effort has been put into making the permissions model more flexible and granular; adding disaster recovery capabilities; enhancing the security and UX of rekeying; improving consistency around lease durations across backends; and more.

In addition, two of the most-requested features have arrived: list support and split data/HA physical backend support!

Please see the full Vault 0.5 CHANGELOG for more details and the huge list of improvements. There are more breaking changes than usual in this version, so please be sure to read the upgrade information at the end of this post.

As always, a big thanks to our community for their ideas, bug reports, and pull requests.

Read on to learn more about the major new features in Vault 0.5.

Fine-Grained Access Control

In past releases of Vault, policies consisted of paths mapped to one of a set of four values (somewhat confusingly also called the "policy" of each path statement): deny (the default), read, write, and sudo. In this system, write included read and sudo included read and write.

The common problem encountered was users having too much privilege. For example, imagine that you have an application ingressing customer data and writing it to a location in a generic backend mount. In order to write the data to the appropriate path, the application would need write permission:

path "custdata/*" {
    policy = "write"
}

However, this also implied read permission, so a hijack of this Internet-facing application and access to its Vault token could allow extraction of customer data.

In Vault 0.5, these four values are replaced by a set of capabilities that are distinct and can be assigned independently: create, read, update, delete, list, sudo, and deny (as before, deny is the default, and takes precedence over any other capability defined at the same path). These strictly control what action is allowed at any given path within Vault and do not imply each other. The application in the previous example can be assigned a policy giving create and update capabilities:

path "custdata/*" {
    capabilities = ["create", "update"]
}

This allows the application to write customer data into Vault; however, without read capability, an attacker that can hijack the application and gain access to its Vault token cannot actually read the data back out.

As another example application, previously, having a token with sudo policy granted on a root-protected path (which are paths within Vault that are generally extremely sensitive and require a special permission -- either a root token or sudo policy -- to access) meant that all actions on that path were allowed -- reading, writing, deleting. However, an organization could want to allow read access to root-protected paths within Vault to a subset of operators without them actually being allowed to modify values, which was impossible. In Vault 0.5, the sudo capability is distinct from the other capabilities making up the permission set of a path, so this subset of operators could be given the set of capabilities capabilities = ["read", "list", "sudo"] to allow them to read and list the values at the root-protected path but prevent modification.

One important note: not all backends support the distinction between create and update (although generic and cubbyhole do). When a backend (or a particular backend path) supports this distinction, it is noted in the documentation; otherwise these capabilities are treated as synonyms.

For backwards compatibility, the previous assignable policies now each map to a set of capabilities, allowing you to continue using Vault without requiring each policy to be upgraded. See the access control policies page for more information.

Listing

Vault now supports list operations via the API and the new vault list command. This is implemented in generic and cubbyhole and a few other places (noted in the API documentation where supported).

For generic and cubbyhole, listing is available for directories only, e.g. vault list secret/ (when using the CLI, a trailing slash will be automatically appended for you, but users of the API will need to ensure that they are formatting their paths correctly.) A successful list command will display both keys and directories under the given path; directories will end with /.

API users can trigger a list operation either by using LIST as the HTTP verb or by appending the query parameter list=true to your request.

All HashiCorp-maintained API libraries have already added support for listing.

Split Data/High Availability Physical Backends

Many companies implement data storage policies that require data to live in specific stores. While these stores may be supported as Vault physical backends, they may not support HA. Vault 0.5 adds support for specifying two physical backends in its configuration file: one for normal data storage, and the other for HA coordiantion.

backend "s3" {
    ...
}

ha_backend "consul" {
    ...
}

In this scenario, encrypted Vault data will be stored in S3, but the HA features required for active/standby coordination will make use of Consul's native lock support.

Rekey Nonces, Unseal Key Archiving, and Keybase Support

Rekey attempts now generate nonces when initiated. The value of the nonce is chosen by Vault and communicated to the initiator of the rekey attempt, who then shares the nonce value with the other unseal key holders to provide along with their unseal key. This ensures that the attempt cannot be reset by a third party without knowledge of the unseal key holders; although the utility of such an attack is minimal, it could lead to a denial of service. (Our thanks to Josh Snyder for bringing this to our attention!)

Additionally, you can now have the generated keys archived in your backend storage for disaster recovery purposes. This archive value is outside Vault's cryptographic barrier; as such, this option is only available when the generated keys themselves are covered via PGP.

Since we believe all users should use PGP to protect the rekey process, PGP keys themselves just got a lot easier to use: instead of a file name in the list of PGP keys, you can now pass in keybase:<user> to have the user's public PGP key fetched from Keybase on-the-fly.

A demonstration of all of these features follows.

First, we initiate the rekey attempt. The backup flag is added to enable the archiving feature:

$ vault rekey -init -backup -key-shares=1 -key-threshold=1 -pgp-keys="keybase:jefferai"
Nonce: fb2b9109-6d1f-f115-db66-39c3a4dcc705
Started: true
Key Shares: 1
Key Threshold: 1
Rekey Progress: 0
Required Keys: 1
PGP Key Fingerprints: [0f801f518ec853daff611e836528efcac6caa3db]
Backup Storage: true

Next, we provide the needed unseal key. Note that when using the CLI to enter the unseal key interactively, the value of the nonce is displayed, but as a convenience it does not need to be entered. Otherwise, the -nonce flag to the command can be used to specify the nonce:

$ vault rekey
Rekey operation nonce: fb2b9109-6d1f-f115-db66-39c3a4dcc705
Key (will be hidden): 


Key 1 fingerprint: 0f801f518ec853daff611e836528efcac6caa3db; value: c1c04c037eebc06b7a152d5501080092361a5396cfb4f7463dcb4a8322b4ff07dc50d1c81b4b587e71a2165d8d2124cc38ac63a80b9e5502c050df352c04981ca7dc47210150815a27ef3ea37c456375d6a4df78e6a4596e1e9f12abed52897555c1f9f3799cee85163a7f421c5899a4d6f772c9f990b86dc67e031de7192e7f4446dc5b05690b7630d98dd5d4b340d5efd9a202426c53460df677cf1507f662c785b2736d09942aebe507218d249e6a5bec2030ecd28b57103b101c883089f87f19fc8ee14d549eb5be5cbfc5217ebfaa671a096fee9110b7a67b298c310c88642e4d74e7a28fc0e3fd8685f5fe1d55f04339cdd7a33458442d0257557dcd99753a1b711b11b97dce0042b73a4e3ad2e001e4619bbb943b1f51b3e38248a92aec1a96e1c5fee0cce056e1663ae0e5e2dfbb4160e068e6fee01ca6301975d04c453657587d51e262ac18142fabb3eec73b1439f742e12f471a66b8cfceb04363fbba5ecc699e1030ad34cb761b567bba781802e6da111de096e4187cd3cf89cb95c2deeb3490916262c0e28f4cacf3e1859400

Operation nonce: fb2b9109-6d1f-f115-db66-39c3a4dcc705

The encrypted unseal keys have been backed up to "core/unseal-keys-backup"
in your physical backend. It is your responsibility to remove these if and
when desired.

At this point the encrypted key is displayed for us (along with the key fingerprint, for identification), but the command also notes that the encrypted unseal key has been stored in the physical backend at core/unseal-keys-backup. This can serve as a break-glass method of retrieving the key if it is lost, and even with the PGP encryption, you should ensure that you have proper protections in place around your data store.

For those with correct permissions within Vault, the value can be retrieved and deleted via the API:

$ vault rekey -retrieve
Key     Value
Keys    map[0f801f518ec853daff611e836528efcac6caa3db:[c1c04c037eebc06b7a152d5501080092361a5396cfb4f7463dcb4a8322b4ff07dc50d1c81b4b587e71a2165d8d2124cc38ac63a80b9e5502c050df352c04981ca7dc47210150815a27ef3ea37c456375d6a4df78e6a4596e1e9f12abed52897555c1f9f3799cee85163a7f421c5899a4d6f772c9f990b86dc67e031de7192e7f4446dc5b05690b7630d98dd5d4b340d5efd9a202426c53460df677cf1507f662c785b2736d09942aebe507218d249e6a5bec2030ecd28b57103b101c883089f87f19fc8ee14d549eb5be5cbfc5217ebfaa671a096fee9110b7a67b298c310c88642e4d74e7a28fc0e3fd8685f5fe1d55f04339cdd7a33458442d0257557dcd99753a1b711b11b97dce0042b73a4e3ad2e001e4619bbb943b1f51b3e38248a92aec1a96e1c5fee0cce056e1663ae0e5e2dfbb4160e068e6fee01ca6301975d04c453657587d51e262ac18142fabb3eec73b1439f742e12f471a66b8cfceb04363fbba5ecc699e1030ad34cb761b567bba781802e6da111de096e4187cd3cf89cb95c2deeb3490916262c0e28f4cacf3e1859400]]
Nonce   fb2b9109-6d1f-f115-db66-39c3a4dcc705

$ vault rekey -delete
Stored keys deleted.

$ vault rekey -retrieve
Error retrieving stored keys: Error making API request.

URL: GET http://127.0.0.1:8200/v1/sys/rekey/backup
Code: 400. Errors:

* no backed-up keys found

Root Token Generation

Another new feature in Vault 0.5 is the ability to generate new root tokens via unseal keys. This helps with disaster recovery, for instance if the original root token was lost and other tokens do not have enough privileges to perform needed operations. It also allows existing root tokens to be revoked for security, only generating a new one as needed and with full agreement from unseal key holders.

There are two ways that the new root token value can be protected. One is using a PGP key that can encrypt to any user's identity, similar to rekeying (and also similar to rekeying, root token generation uses a nonce to ensure that unseal key holders are providing keys to the same attempt). The other, which will be demonstrated below, uses a One Time Pad (OTP) of a specific length to protect the token. In this scenario, since only the attempt initiator knows the OTP, the attempt initiator is the receiver of the root token and should be given the encoded value from the last unseal key provider.

The OTP is a set of 16 bytes encoded as base 64. Vault contains a helper method to generate a suitable, random OTP:

$ vault generate-root -genotp
OTP: o0HqCGchJ0AGL9RmIx2Fnw==

Now that we have a suitable OTP, we can initiate a root token generation attempt:

$ vault generate-root -init -otp="o0HqCGchJ0AGL9RmIx2Fnw=="
Nonce: b328e29a-9bc5-ae58-dea6-2cc8abb94d96
Started: true
Rekey Progress: 0
Required Keys: 1
Complete: false

We now provide the necessary unseal key; as with a rekey operation, when entering the unseal key interactively, there is no need to retype the nonce to verify it:

$ vault generate-root
Root generation operation nonce: b328e29a-9bc5-ae58-dea6-2cc8abb94d96
Key (will be hidden): 
Nonce: b328e29a-9bc5-ae58-dea6-2cc8abb94d96
Started: true
Rekey Progress: 1
Required Keys: 1
Complete: true

Encoded root token: 66jYpbXVwS4kKiTsa02b5g==

To get the final token back, we can use the -decode flag to generate-root:

$ vault generate-root -decode="66jYpbXVwS4kKiTsa02b5g==" -otp="o0HqCGchJ0AGL9RmIx2Fnw=="
Root token: 48e932ad-d2f4-e66e-2205-f08a48501e79

Finally, we can verify that this is a real root token:

$ VAULT_TOKEN=48e932ad-d2f4-e66e-2205-f08a48501e79 vault token-lookup
Key             Value
creation_time   1.454615413e+09
creation_ttl    0
display_name    root
id              48e932ad-d2f4-e66e-2205-f08a48501e79
meta            <nil>
num_uses        0
orphan          true
path            auth/token/root
policies        [root]
ttl             0

Other Highlights

There are too many new features and improvements in this release to describe all of them in depth, so a few more are covered below in brief:

  • Lease Duration Handling Across Backends, and Grace Periods: The various backends now honor the default/max lease TTLs set on the mount or system if not overridden by a configuration within the backend itself. This provides for much more consistent management of durations, but also introduces behavioral changes. In addition, grace periods have been removed in order to reduce confusion and remove discrepancies across backends in the true duration of a lease. Please see the upgrade details for information.
  • DynamoDB Physical Backend: a new community-supported backend that supports High Availability using Amazon's DynamoDB for storage
  • PostgreSQL Physical Backend: a new community-supported backend using PostgreSQL for storage
  • STS Support in the AWS Secret Backend: The aws secret backend can now issue STS tokens for the configured IAM role, rather than creating and deleting new IAM roles for requesting clients
  • Speedups in the Transit Backend: The transit backend has gained a cache, and now loads only the current set of keys (e.g. from the min_decryption_version to the current key version) into its working set. This provides large speedups and potential memory savings when the rotate feature of the backend is used heavily.

Important Build Note

The HashiCorp-provided binary release of Vault 0.5.0 is built against a slightly modified Go 1.5.3 that contains two commits cherry-picked from the Go 1.6 tree. These patches contain bug fixes specific to TLS certificate handling that were affecting Vault users. If you want to examine the way in which the releases were built, please look at our cross-compilation Dockerfile.

Upgrade Details

Vault 0.5 has significant changes that must be understood before upgrading. As such, we have reorganized Vault's documentation to provide both general upgrade instructions as well as a version-specific guide. Note that this guide covers upgrading from 0.4.x; if upgrading from earlier versions, please take note of the upgrade instructions in the corresponding release blog posts. In the future, we will ensure that upgrade information is posted to Vault's documentation on a version-specific page.

As always, we recommend upgrading and testing this release in an isolated environment. If you experience any issues, please report them on the Vault GitHub issue tracker or post to the Vault mailing list.

We hope you enjoy Vault 0.5!