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