2018-01-10 19:14:59 +00:00
|
|
|
---
|
|
|
|
layout: "guides"
|
|
|
|
page_title: "Cubbyhole Response Wrapping - Guides"
|
|
|
|
sidebar_current: "guides-cubbyhole"
|
|
|
|
description: |-
|
|
|
|
Vault provides a capability to wrap Vault response and store it in a
|
|
|
|
"cubbyhole" where the holder of the one-time use wrapping token can unwrap to
|
|
|
|
uncover the secret.
|
|
|
|
---
|
|
|
|
|
|
|
|
# Cubbyhole
|
|
|
|
|
|
|
|
The term _cubbyhole_ comes from an Americnaism where you get a "locker" or "safe
|
|
|
|
place" to store your belongings or valuables. In Vault, cubbyhole is your
|
|
|
|
"locker". All secrets are namespaced under **your token**. If that token
|
|
|
|
expires or is revoked, all the secrets in its cubbyhole are revoked as well.
|
|
|
|
|
|
|
|
It is not possible to reach into another token's cubbyhole even as the root
|
|
|
|
user. This is the key difference between the cubbyhole and the key/value secret
|
|
|
|
backend. The secrets in the key/value backends are accessible to any token for as
|
|
|
|
long as its policy allows it.
|
|
|
|
|
|
|
|
|
|
|
|
## Reference Material
|
|
|
|
|
|
|
|
- [Cubbyhole](/docs/secrets/cubbyhole/index.html)
|
|
|
|
- [Response Wrapping](/docs/concepts/response-wrapping.html)
|
|
|
|
|
|
|
|
## Estimated Time to Complete
|
|
|
|
|
|
|
|
10 minutes
|
|
|
|
|
|
|
|
## Challenge
|
|
|
|
|
|
|
|
In order to tightly manage the secrets, you set the scope of who can do what
|
|
|
|
using the [Vault policy](/docs/concepts/policies.html) and attach that to
|
|
|
|
tokens, roles, entities, etc.
|
|
|
|
|
|
|
|
How to securely distribute the initial token to a machine or app?
|
|
|
|
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
Use Vault's **cubbyhole response wrapping** where the initial token is stored in
|
|
|
|
the cubbyhole backend. The wrapped secret can be unwrap using the single use
|
|
|
|
wrapping token. Even the user or the system created the initial token won't see
|
|
|
|
the original value. The wrapping token is short-lived and can be revoked just
|
|
|
|
like any other tokens so that the risk of unauthorized access can be minimized.
|
|
|
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
To perform the tasks described in this guide, you need to have a Vault
|
2018-01-18 01:39:21 +00:00
|
|
|
environment. Refer to the [Getting
|
|
|
|
Started](/intro/getting-started/install.html) guide to install Vault.
|
2018-01-10 19:14:59 +00:00
|
|
|
|
2018-01-18 01:39:21 +00:00
|
|
|
Make sure that your Vault server has been [initialized and
|
|
|
|
unsealed](/intro/getting-started/deploy.html).
|
2018-01-10 19:14:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
## Steps
|
|
|
|
|
|
|
|
To distribute the initial token to an app using cubbyhole response wrapping, you
|
|
|
|
perform the following tasks:
|
|
|
|
|
|
|
|
1. Create and wrap a token
|
|
|
|
2. Unwrap the secret
|
|
|
|
|
|
|
|
### Step 1: Create and wrap a token
|
|
|
|
|
|
|
|
When the response to `vault token-create` request is wrapped, Vault inserts the
|
|
|
|
generated token it into the cubbyhole of a single-use token, returning that
|
|
|
|
single-use wrapping token. Retrieving the secret requires an unwrap operation
|
|
|
|
against this wrapping token.
|
|
|
|
|
|
|
|
#### CLI command
|
|
|
|
|
|
|
|
```shell
|
|
|
|
vault token-create -policy=<POLICY_NAME> -wrap-ttl=<WRAP_TTL>
|
|
|
|
```
|
|
|
|
|
|
|
|
Where the `<WRAP_TTL>` is a numeric string indicating the TTL of the response.
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
```shell
|
|
|
|
vault token-create -policy=app-policy -wrap-ttl=60s
|
|
|
|
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
wrapping_token: 9ac59985-094f-a2de-aed8-bf688e436fbc
|
|
|
|
wrapping_token_ttl: 1m0s
|
|
|
|
wrapping_token_creation_time: 2018-01-10 00:47:54.970185208 +0000 UTC
|
|
|
|
wrapping_token_creation_path: auth/token/create
|
|
|
|
wrapped_accessor: 195763a9-3f26-1fcf-6a1a-ee0a11e76cb1
|
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
2018-01-18 01:39:21 +00:00
|
|
|
Before begin, create the following environment variables for your convenience:
|
|
|
|
|
|
|
|
- **VAULT_ADDR** is set to your Vault server address
|
|
|
|
- **VAULT_TOKEN** is set to your Vault token
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
$ export VAULT_ADDR=http://127.0.0.1:8201
|
|
|
|
|
|
|
|
$ export VAULT_TOKEN=0c4d13ba-9f5b-475e-faf2-8f39b28263a5
|
|
|
|
```
|
|
|
|
|
2018-01-10 19:14:59 +00:00
|
|
|
Response wrapping is per-request and is triggered by providing to Vault the
|
|
|
|
desired TTL for a response-wrapping token for that request. This is set using
|
|
|
|
the **`X-Vault-Wrap-TTL`** header in the request and can be either an integer
|
|
|
|
number of seconds or a string duration.
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
|
|
```text
|
|
|
|
curl -X POST -H "X-Vault-Token: $VAULT_TOKEN" -H "X-Vault-Wrap-TTL: 60s" \
|
|
|
|
-d '{"policies":["app-policy"]}' $VAULT_ADDR/v1/auth/token/create | jq
|
|
|
|
|
|
|
|
{
|
|
|
|
"request_id": "",
|
|
|
|
"lease_id": "",
|
|
|
|
"renewable": false,
|
|
|
|
"lease_duration": 0,
|
|
|
|
"data": null,
|
|
|
|
"wrap_info": {
|
|
|
|
"token": "e095129f-123a-4fef-c007-1f6a487cfa78",
|
|
|
|
"ttl": 60,
|
|
|
|
"creation_time": "2018-01-10T01:43:38.025351336Z",
|
|
|
|
"creation_path": "auth/token/create",
|
|
|
|
"wrapped_accessor": "44e8253c-65b4-1690-1bf1-7902a7a6b2aa"
|
|
|
|
},
|
|
|
|
"warnings": null,
|
|
|
|
"auth": null
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Step 2: Unwrap the secret
|
|
|
|
|
|
|
|
The client uses the wrapping token to unwrap the secret.
|
|
|
|
|
|
|
|
**NOTE:**
|
|
|
|
If a client has been expecting delivery of a response-wrapping token and none
|
|
|
|
arrives, this may be due to an attacker intercepting the token and then
|
|
|
|
preventing it from traveling further. This should cause an alert to trigger an
|
|
|
|
immediate investigation.
|
|
|
|
|
|
|
|
#### CLI command
|
|
|
|
|
|
|
|
```text
|
|
|
|
vault unwrap <WRAPPING_TOKEN>
|
|
|
|
```
|
|
|
|
Or
|
|
|
|
|
|
|
|
```text
|
|
|
|
VAULT_TOKEN=<WRAPPING_TOKEN> vault unwrap
|
|
|
|
```
|
|
|
|
|
2018-01-18 01:39:21 +00:00
|
|
|
In this scenario, the wrapped secret is a Vault token. Therefore, it probably
|
|
|
|
makes better sense to use the second option.
|
|
|
|
|
2018-01-10 19:14:59 +00:00
|
|
|
**Example:**
|
|
|
|
|
|
|
|
```shell
|
2018-01-18 01:39:21 +00:00
|
|
|
$ VAULT_TOKEN=9ac59985-094f-a2de-aed8-bf688e436fbc vault unwrap
|
2018-01-10 19:14:59 +00:00
|
|
|
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
token 7bb915b2-8a44-48b0-a71d-72b590252016
|
|
|
|
token_accessor 195763a9-3f26-1fcf-6a1a-ee0a11e76cb1
|
|
|
|
token_duration 768h0m0s
|
|
|
|
token_renewable true
|
|
|
|
token_policies [app-policy default]
|
|
|
|
```
|
|
|
|
|
|
|
|
#### API call using cURL
|
|
|
|
|
|
|
|
To enable the AppRole auth backend via API:
|
|
|
|
|
|
|
|
```text
|
|
|
|
curl -X POST -H "X-Vault-Token: $WRAPPING_TOKEN" $VAULT_ADDR/v1/sys/wrapping/unwrap | jq
|
|
|
|
|
|
|
|
{
|
|
|
|
"request_id": "d704435d-c1cf-b8a3-52f6-ec50bc8246c4",
|
|
|
|
"lease_id": "",
|
|
|
|
"renewable": false,
|
|
|
|
"lease_duration": 0,
|
|
|
|
"data": null,
|
|
|
|
"wrap_info": null,
|
|
|
|
"warnings": null,
|
|
|
|
"auth": {
|
|
|
|
"client_token": "af5f7682-aa55-fa37-5039-ee116df56600",
|
|
|
|
"accessor": "19b5407e-b304-7cde-e946-54942325d3c1",
|
|
|
|
"policies": [
|
|
|
|
"app-policy",
|
|
|
|
"default"
|
|
|
|
],
|
|
|
|
"metadata": null,
|
|
|
|
"lease_duration": 2764800,
|
|
|
|
"renewable": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2018-01-18 01:39:21 +00:00
|
|
|
## Additional Discussion
|
2018-01-10 19:14:59 +00:00
|
|
|
|
|
|
|
Similar to the key/value secret backend, the cubbyhole backend is mounted at the
|
|
|
|
**`cubbyhole/`** prefix by default. The secrets you store in the `cubbyhole/` path
|
|
|
|
are tied to your token and only accessible by you.
|
|
|
|
|
|
|
|
To test the cubbyhole secret backend, perform the following steps.
|
|
|
|
|
|
|
|
First, create `tester` policy which grants permissions on the path under `cubbyhole/private/` prefix.
|
|
|
|
|
|
|
|
```text
|
|
|
|
$ vault policy-write tester tester.hcl
|
|
|
|
|
|
|
|
$ cat tester.hcl
|
|
|
|
path "cubbyhole/private/*" {
|
|
|
|
capabilities = ["create", "read", "update", "delete", "list"]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Create a token attached to the `tester` policy, and then authenticate using the
|
|
|
|
token.
|
|
|
|
|
|
|
|
```text
|
|
|
|
$ vault token-create -policy=tester
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
token 2ba26888-b531-1626-3598-01ea4aa383bb
|
|
|
|
token_accessor 28cbd05c-31a3-0aaa-4dca-838a9aafe4cb
|
|
|
|
token_duration 768h0m0s
|
|
|
|
token_renewable true
|
|
|
|
token_policies [default tester]
|
|
|
|
|
|
|
|
$ unset VAULT_TOKEN
|
|
|
|
|
|
|
|
$ vault auth 2ba26888-b531-1626-3598-01ea4aa383bb
|
|
|
|
Successfully authenticated! You are now logged in.
|
|
|
|
token: 2ba26888-b531-1626-3598-01ea4aa383bb
|
|
|
|
token_duration: 2764651
|
|
|
|
token_policies: [default tester]
|
|
|
|
```
|
|
|
|
|
|
|
|
You should be able to write secrets under `cubbyhole/private/` path, and read it
|
|
|
|
back.
|
|
|
|
|
|
|
|
```text
|
|
|
|
$ vault write cubbyhole/private/access-token token="123456789abcdefg87654321"
|
|
|
|
Success! Data written to: cubbyhole/private/access-token
|
|
|
|
|
|
|
|
$ vault read cubbyhole/private/access-token
|
|
|
|
Key Value
|
|
|
|
--- -----
|
|
|
|
token 123456789abcdefg87654321
|
|
|
|
```
|
|
|
|
|
|
|
|
Now, try to access the secret using the root token, you shouldn't be able to
|
|
|
|
read.
|
|
|
|
|
|
|
|
```text
|
|
|
|
VAULT_TOKEN=<ROOT_TOKEN> vault read cubbyhole/private/access-token
|
|
|
|
|
|
|
|
No value found at cubbyhole/private/access-token
|
|
|
|
```
|
|
|
|
|
|
|
|
Also, refer to [Cubbyhole Secret Backend HTTP API](/api/secret/cubbyhole/index.html).
|
|
|
|
|
|
|
|
|
|
|
|
## Next steps
|