1---
2layout: "guides"
3page_title: "Cubbyhole Response Wrapping - Guides"
4sidebar_title: "Cubbyhole Response Wrapping"
5sidebar_current: "guides-secret-mgmt-cubbyhole"
6description: |-
7  Vault provides a capability to wrap Vault response and store it in a
8  "cubbyhole" where the holder of the one-time use wrapping token can unwrap to
9  uncover the secret.
10---
11
12# Cubbyhole
13
14The term _cubbyhole_ comes from an Americanism where you get a "locker" or "safe
15place" to store your belongings or valuables. In Vault, cubbyhole is your
16"locker".  All secrets are namespaced under **your token**. If that token
17expires or is revoked, all the secrets in its cubbyhole are revoked as well.
18
19It is not possible to reach into another token's cubbyhole even as the root
20user. This is the key difference between the cubbyhole and the key/value secret
21engine. The secrets in the key/value secret engine are accessible to any token for as
22long as its policy allows it.
23
24
25## Reference Material
26
27- [Cubbyhole](/docs/secrets/cubbyhole/index.html)
28- [Response Wrapping](/docs/concepts/response-wrapping.html)
29
30~> **NOTE:** An [interactive
31tutorial](https://www.katacoda.com/hashicorp/scenarios/vault-cubbyhole) is
32also available if you do not have a Vault environment to perform the steps
33described in this guide.
34
35## Estimated Time to Complete
36
3710 minutes
38
39## Personas
40
41The end-to-end scenario described in this guide involves two personas:
42
43- **`admin`** with privileged permissions to create tokens
44- **`apps`** trusted entity retrieving secrets from Vault
45
46## Challenge
47
48In order to tightly manage the secrets, you set the scope of who can do what
49using the [Vault policy](/docs/concepts/policies.html) and attach that to
50tokens, roles, entities, etc.
51
52Think of a case where you have a trusted entity (Chef, Jenkins, etc.) which
53reads secrets from Vault. This trusted entity must obtain a token. If the
54trusted entity or its host machine was rebooted, it must re-authenticate with
55Vault using a valid token.
56
57How can you securely distribute the initial token to the trusted entity?
58
59## Solution
60
61Use Vault's **cubbyhole response wrapping** where the initial token is stored in
62the cubbyhole secret engine. The wrapped secret can be unwrapped using the
63single-use wrapping token. Even the user or the system created the initial token
64won't see the original value. The wrapping token is short-lived and can be
65revoked just like any other tokens so that the risk of unauthorized access can
66be minimized.
67
68## Prerequisites
69
70To perform the tasks described in this guide, you need to have a Vault
71environment.  Refer to the [Getting
72Started](/intro/getting-started/install.html) guide to install Vault. Make sure
73that your Vault server has been [initialized and
74unsealed](/intro/getting-started/deploy.html).
75
76### <a name="policy"></a>Policy requirements
77
78-> **NOTE:** For the purpose of this guide, you can use **`root`** token to work
79with Vault. However, it is recommended that root tokens are only used for just
80enough initial setup or in emergencies. As a best practice, use tokens with
81appropriate set of policies based on your role in the organization.
82
83To perform all tasks demonstrated in this guide, your policy must include the
84following permissions:
85
86```shell
87# Manage tokens
88path "auth/token/*" {
89  capabilities = [ "create", "read", "update", "delete", "sudo" ]
90}
91
92# Write ACL policies
93path "sys/policy/*" {
94  capabilities = [ "create", "read", "update", "delete", "list" ]
95}
96
97# Manage secret/dev secret engine - for Verification test
98path "secret/dev" {
99  capabilities = [ "create", "read", "update", "delete", "list" ]
100}
101```
102
103If you are not familiar with policies, complete the
104[policies](/guides/identity/policies.html) guide.
105
106## Steps
107
108Think of a scenario where apps read secrets from Vault. The `apps` need:
109
110- Policy granting "read" permission on the specific path (`secret/dev`)
111- Valid tokens to interact with Vault
112
113![Response Wrapping Scenario](/img/vault-cubbyhole.png)
114
115Setting the appropriate policies and token generation are done by the `admin`
116persona. For the `admin` to distribute the initial token to the app securely, it
117uses cubbyhole response wrapping. In this guide, you perform the following:
118
1191. [Create and wrap a token](#step1)
1202. [Unwrap the secret](#step2)
121
122**NOTE:** This guide demonstrates how the response wrapping works. To learn more
123about reading and writing secrets in Vault, refer to the [Static
124Secret](/guides/secret-mgmt/static-secrets.html) guide.
125
126### <a name="step1"></a>Step 1: Create and wrap a token
127(**Persona:** admin)
128
129To solve the [challenge](#challenge) addressed in this guide:
130
1311. More privileged token (`admin`) wraps a secret only the expecting client can
132read
1332. The receiving client (`app`) unwraps the secret to obtain the token
134
135When the response to `vault token create` request is wrapped, Vault inserts the
136generated token into the cubbyhole of a single-use token, returning that
137single-use wrapping token. Retrieving the secret requires an unwrap operation
138against this wrapping token.
139
140In this scenario, an [admin user](#personas) creates a token using response
141wrapping. To perform the steps in this guide, first create a policy for the app.
142
143`apps-policy.hcl`:
144
145```shell
146# For testing, read-only on secret/dev path
147path "secret/dev" {
148  capabilities = [ "read" ]
149}
150```
151
152#### CLI command
153
154First create an `apps` policy:
155
156```shell
157$ vault policy write apps apps-policy.hcl
158Policy 'apps' written.
159```
160
161To create a token using response wrapping:
162
163```shell
164$ vault token create -policy=<POLICY_NAME> -wrap-ttl=<WRAP_TTL>
165```
166
167Where the `<WRAP_TTL>` can be either an integer number of seconds or a string
168duration of seconds (15s), minutes (20m), or hours (25h).
169
170**Example:**
171
172Generate a token for `apps` persona using response wrapping with TTL of 120
173seconds.
174
175```shell
176$ vault token create -policy=apps -wrap-ttl=120
177
178Key                          	Value
179---                          	-----
180wrapping_token:              	9ac59985-094f-a2de-aed8-bf688e436fbc
181wrapping_token_ttl:          	2m0s
182wrapping_token_creation_time:	2018-01-10 00:47:54.970185208 +0000 UTC
183wrapping_token_creation_path:	auth/token/create
184wrapped_accessor:            	195763a9-3f26-1fcf-6a1a-ee0a11e76cb1
185```
186
187The response is the wrapping token; therefore, the admin user does not even see
188the generated token from the `token create` command.
189
190
191#### API call using cURL
192
193First create an `apps` policy using `sys/policy` endpoint:
194
195```shell
196$ curl --header "X-Vault-Token: <TOKEN>" \
197       --request PUT \
198       --data <PAYLOAD> \
199       <VAULT_ADDRESS>/v1/sys/policy/<POLICY_NAME>
200```
201
202Where `<TOKEN>` is your valid token, and `<PAYLOAD>` includes policy name and
203stringified policy.
204
205**Example:**
206
207```shell
208# Request payload
209$ cat payload.json
210{
211  "policy": "path \"secret/dev\" { capabilities = [ \"read\" ] }"
212}
213
214# API call to create a policy named, "apps"
215$ curl --header "X-Vault-Token: ..." --request PUT --data @payload.json \
216       http://127.0.0.1:8200/v1/sys/policy/apps
217```
218
219Response wrapping is per-request and is triggered by providing to Vault the
220desired TTL for a response-wrapping token for that request. This is set using
221the **`X-Vault-Wrap-TTL`** header in the request and can be either an integer
222number of seconds or a string duration.
223
224```shell
225$ curl --header "X-Vault-Wrap-TTL: <TTL>" \
226       --header "X-Vault-Token: <TOKEN>" \
227       --request <HTTP_VERB> \
228       --data '<PARAMETERS>' \
229       <VAULT_ADDRESS>/v1/<ENDPOINT>
230```
231
232Where `<TTL>` can be either an integer number of seconds or a string duration of
233seconds (15s), minutes (20m), or hours (25h).
234
235**Example:**
236
237To wrap the response of token create request:
238
239```shell
240$ curl --header "X-Vault-Wrap-TTL: 120" \
241       --header "X-Vault-Token: ..." \
242       --request POST \
243       --data '{"policies":["apps"]}' \
244       http://127.0.0.1:8200/v1/auth/token/create | jq
245{
246  "request_id": "",
247  "lease_id": "",
248  "renewable": false,
249  "lease_duration": 0,
250  "data": null,
251  "wrap_info": {
252    "token": "e095129f-123a-4fef-c007-1f6a487cfa78",
253    "ttl": 120,
254    "creation_time": "2018-01-10T01:43:38.025351336Z",
255    "creation_path": "auth/token/create",
256    "wrapped_accessor": "44e8253c-65b4-1690-1bf1-7902a7a6b2aa"
257  },
258  "warnings": null,
259  "auth": null
260}
261```
262
263This API call generates a token for `apps` persona using response wrapping with
264TTL of 60 seconds. The admin user does not even see the generated token.
265
266
267### <a name="step2"></a>Step 2: Unwrap the secret
268(**Persona:** apps)
269
270The `apps` persona receives a wrapping token from the `admin`.  In order for the
271`apps` to acquire a valid token to read secrets from `secret/dev` path, it must
272run the unwrap operation using this token.
273
274-> **NOTE:** If a client has been expecting delivery of a response-wrapping
275token and none arrives, this may be due to an attacker intercepting the token
276and then preventing it from traveling further. This should cause an alert to
277trigger an immediate investigation.
278
279The following tasks will be performed to demonstrate the client operations:
280
2811. Create a token with **`default`** policy
2822. Authenticate with Vault using this `default` token (less privileged token)
2833. Unwrap the secret to obtain more privileged token (**`apps`** persona token)
2844. Verify that you can read `secret/dev` using the `apps`token
285
286
287#### CLI command
288
289First, create a token with `default` policy:
290
291```shell
292# Create a token with `default` policy
293$ vault token create -policy=default
294Key            	Value
295---            	-----
296token          	4522b2e8-27fe-bdc5-b932-d982f3166c6c
297token_accessor 	96108f48-7475-6190-b058-769a2e5ebc8e
298token_duration 	768h0m0s
299token_renewable	true
300token_policies 	[default]
301
302# Authenticate using the generated token
303$ vault login 4522b2e8-27fe-bdc5-b932-d982f3166c6c
304Successfully authenticated! You are now logged in.
305token: 4522b2e8-27fe-bdc5-b932-d982f3166c6c
306token_duration: 2764729
307token_policies: [default]
308
309# Verify that you do NOT have a permission to read secret/dev
310$ vault read secret/dev
311Error reading secret/dev: Error making API request.
312
313URL: GET http://<VAULT_ADDRESS>/v1/secret/dev
314Code: 403. Errors:
315
316* permission denied
317```
318
319The command to unwrap the wrapped secret is:
320
321```shell
322$ vault unwrap <WRAPPING_TOKEN>
323```
324Or
325
326```shell
327$ VAULT_TOKEN=<WRAPPING_TOKEN> vault unwrap
328```
329
330**Example:**
331
332```shell
333$ VAULT_TOKEN=9ac59985-094f-a2de-aed8-bf688e436fbc vault unwrap
334
335Key            	Value
336---            	-----
337token          	7bb915b2-8a44-48b0-a71d-72b590252016
338token_accessor 	195763a9-3f26-1fcf-6a1a-ee0a11e76cb1
339token_duration 	768h0m0s
340token_renewable	true
341token_policies 	[apps default]
342```
343
344Verify that this token has `apps` policy attached.
345
346Once the client acquired the token, future requests can be made using this
347token.
348
349```shell
350$ vault login 7bb915b2-8a44-48b0-a71d-72b590252016
351
352$ vault read secret/dev
353No value found at secret/dev
354```
355
356#### API call using cURL
357
358First, create a token with `default` policy:
359
360```shell
361# Create a new token default policy
362$ curl --header "X-Vault-Token: ..." --request POST \
363     --data '{"policies": "default"}' \
364     http://127.0.0.1:8200/v1/auth/token/create | jq
365{
366  ...
367  "auth": {
368    "client_token": "5fe14760-b0fd-22dc-403c-14a05003b67f",
369    "accessor": "e709610e-916e-f7e3-b93b-41f4dfdca7a0",
370    "policies": [
371      "default"
372    ],
373    ...
374 }
375}
376
377# Verify that you can NOT read secret/dev using default token
378$ curl --header "X-Vault-Token: 5fe14760-b0fd-22dc-403c-14a05003b67f" \
379       --request GET \
380       http://127.0.0.1:8200/v1/secret/dev | jq
381{
382 "errors": [
383   "permission denied"
384 ]
385}
386```
387
388Now, unwrap the secret using `/sys/wrapping/unwrap` endpoint:
389
390```shell
391$ curl --header "X-Vault-Token: <WRAPPING_TOKEN>" \
392       --request POST \
393       <VAULT_ADDRESS>/v1/sys/wrapping/unwrap
394```
395
396**Example:**
397
398```shell
399$ curl --header "X-Vault-Token: e095129f-123a-4fef-c007-1f6a487cfa78" \
400       --request POST \
401       http://127.0.0.1:8200/v1/sys/wrapping/unwrap | jq
402{
403  "request_id": "d704435d-c1cf-b8a3-52f6-ec50bc8246c4",
404  "lease_id": "",
405  "renewable": false,
406  "lease_duration": 0,
407  "data": null,
408  "wrap_info": null,
409  "warnings": null,
410  "auth": {
411    "client_token": "af5f7682-aa55-fa37-5039-ee116df56600",
412    "accessor": "19b5407e-b304-7cde-e946-54942325d3c1",
413    "policies": [
414      "apps",
415      "default"
416    ],
417    "metadata": null,
418    "lease_duration": 2764800,
419    "renewable": true
420  }
421}
422```
423
424Once the client acquired the token, future requests can be made using this
425token.
426
427```plaintext
428$ curl --header "X-Vault-Token: af5f7682-aa55-fa37-5039-ee116df56600" \
429       --request GET \
430       http://127.0.0.1:8200/v1/secret/dev | jq
431{
432  "errors": []
433}
434```
435
436Since there is no data in `secret/dev`, it returns an empty array.
437
438## Additional Discussion
439
440The `cubbyhole` secret engine provides your own private secret storage space
441where no one else can read (including `root`). This comes handy when you want to
442store a password tied to your username that should not be shared with anyone.
443
444The cubbyhole secret engine is mounted at the **`cubbyhole/`** prefix by
445default. The secrets you store in the `cubbyhole/` path are tied to your token
446and all tokens are permitted to read and write to the `cubbyhole` secret engine
447by the [`default`](/docs/concepts/policies.html#default-policy) policy.
448
449```shell
450...
451# Allow a token to manage its own cubbyhole
452path "cubbyhole/*" {
453    capabilities = ["create", "read", "update", "delete", "list"]
454}
455...
456```
457
458To test the cubbyhole secret engine, perform the following steps. (NOTE: Keep
459using the `apps` token from [Step 2](#step2) to ensure that you are logged in with
460non-root token.)
461
462#### CLI command
463
464Commands to write and read secrets to the `cubbyhole` secret engine:
465
466```shell
467# Write key-value pair(s) in your cubbyhole
468$ vault write cubbyhole/<PATH> <KEY>=<VALUE>
469
470# Read values from your cubbyhole
471$ vault write cubbyhole/<PATH>
472```
473
474**Example:**
475
476Write secrets under `cubbyhole/private/` path, and read it back.
477
478```shell
479# Write "token" to cubbyhole/private/access-token path
480$ vault write cubbyhole/private/access-token token="123456789abcdefg87654321"
481Success! Data written to: cubbyhole/private/access-token
482
483# Read value from cubbyhole/private/access-token path
484$ vault read cubbyhole/private/access-token
485Key  	Value
486---  	-----
487token	123456789abcdefg87654321
488```
489
490Now, try to access the secret using the `root` token. It should NOT return the
491secret.
492
493```shell
494$ VAULT_TOKEN=<ROOT_TOKEN> vault read cubbyhole/private/access-token
495
496No value found at cubbyhole/private/access-token
497```
498
499#### API call using cURL
500
501The API to work with the `cubbyhole` secret engine is very similar to `secret` secret engine:
502
503```shell
504$ curl --header "X-Vault-Token: <TOKEN>" \
505       --request POST \
506       --data <SECRETS> \
507       <VAULT_ADDRESS>/v1/cubbyhole/<PATH>
508```
509
510**Example:**
511
512Write secrets under `cubbyhole/private/` path, and read it back.
513
514```shell
515# Write "token" to cubbyhole/private/access-token path
516$ curl --header "X-Vault-Token: e095129f-123a-4fef-c007-1f6a487cfa78" --request POST \
517       --data '{"token": "123456789abcdefg87654321"}' \
518       http://127.0.0.1:8200/v1/cubbyhole/private/access-token
519
520# Read value from cubbyhole/private/access-token path
521$ curl --header "X-Vault-Token: e095129f-123a-4fef-c007-1f6a487cfa78" --request GET \
522       http://127.0.0.1:8200/v1/cubbyhole/private/access-token  | jq
523{
524 "request_id": "b2ff9f04-7a72-7eb0-672f-225b5eb652df",
525 "lease_id": "",
526 "renewable": false,
527 "lease_duration": 0,
528 "data": {
529   "token": "123456789abcdefg87654321"
530 },
531 "wrap_info": null,
532 "warnings": null,
533 "auth": null
534}
535```
536
537Now, try to access the secret using the `root` token. It should NOT return the
538secret.
539
540```shell
541$ curl --header "X-Vault-Token: root" --request GET \
542       http://127.0.0.1:8200/v1/cubbyhole/private/access-token  | jq
543{
544 "errors": []
545}
546```
547
548Also, refer to [Cubbyhole Secret Engine (API)](/api/secret/cubbyhole/index.html).
549
550
551## Next steps
552
553The use of [AppRole Pull Authentication](/guides/identity/authentication.html) is a good
554use case to leverage the response wrapping. Go through the guide if you have not
555done so.  To better understand the lifecycle of Vault tokens, proceed to [Tokens
556and Leases](/guides/identity/lease.html) guide.
557