1---
2layout: "guides"
3page_title: "AppRole With Terraform & Chef - Guides"
4sidebar_title: "AppRole with Terraform and Chef"
5sidebar_current: "guides-identity-approle-tf-chef"
6description: |-
7  This guide discusses the concepts necessary to help users
8  understand Vault's AppRole authentication pattern and how to use it to
9  securely introduce a Vault authentication token to a target server,
10  application, container, etc.x
11---
12
13# Vault AppRole with Terraform and Chef Demo
14
15In the [AppRole Pull
16Authentication](/guides/identity/authentication.html#advanced-features) guide,
17the question of how best to deliver the Role ID and Secret ID were brought up,
18and the role of trusted entities (Terraform, Chef, Nomad, Kubernetes, etc.) was
19mentioned.
20
21![AppRole auth method workflow](/img/vault-approle-workflow2.png)
22
23This _intermediate_ Vault guide aims to provide a **simple**, **end-to-end**
24example of how to use Vault's [AppRole authentication
25method](/docs/auth/approle.html), along with Terraform and Chef, to address the
26challenge of the **_secure introduction_** of an initial token to a target
27system.
28
29The purpose of this guide is to provide the instruction to reproduce the working
30implementation demo introduced in the [Delivering Secret Zero: Vault AppRole
31with Terraform and
32Chef](https://www.hashicorp.com/resources/delivering-secret-zero-vault-approle-terraform-chef)
33webinar.
34
35[![YouTube](/img/vault-approle-youtube.png)](https://youtu.be/OIcIzFWjThM)
36
37-> **NOTE:** This is a proof of concept and **NOT SUITABLE FOR PRODUCTION USE**.
38
39
40## Reference Material
41
42- [AppRole Auth Method](/docs/auth/approle.html)
43- [Authenticating Applications with HashiCorp Vault AppRole](https://www.hashicorp.com/blog/authenticating-applications-with-vault-approle)
44- [Delivering Secret Zero: Vault AppRole with Terraform and
45Chef](https://www.hashicorp.com/resources/delivering-secret-zero-vault-approle-terraform-chef)
46
47## Estimated Time to Complete
48
4920 minutes
50
51## Challenge
52
53The goal of the AppRole authentication method is to provide a mechanism for the
54secure introduction of secrets to target systems (servers, applications,
55containers, etc.).
56
57The question becomes what systems within our environment do we trust to handle
58or deliver the `RoleID` and `SecretID` to our target systems.
59
60
61## Solution
62
63Use _Trusted Entities_ to deliver the AppRole authentication values. For
64example, use Terraform to deliver your `RoleID` or embed it into your AMI or
65Dockerfile. Then you might use Jenkins or Chef to obtain the
66[response-wrapped](/guides/secret-mgmt/cubbyhole.html) `SecretID` and deliver it
67to the target system.
68
69AppRole allows us to securely introduce the authentication token to the target
70system by preventing any single system from having full access to an
71authentication token that does not belong to. This helps us maintain the
72security principles of **least privilege** and **non-repudiation**.
73
74The important thing to note here is that regardless of what systems are
75considered as _Trusted Entities_, the same pattern applies.
76
77For example:
78
79- With Chef, you might use the [Vault Ruby Gem](https://github.com/hashicorp/vault-ruby)
80  for simplified interaction with Vault APIs
81- Terraform provides a Vault provider: [Provider: Vault - Terraform by HashiCorp](https://www.terraform.io/docs/providers/vault/index.html)
82- For Jenkins, you might use the Vault CLI or APIs directly, as described here:
83  [Reading Vault Secrets in your Jenkins pipeline](http://nicolas.corrarello.com/general/vault/security/ci/2017/04/23/Reading-Vault-Secrets-in-your-Jenkins-pipeline.html)
84
85
86## Prerequisites
87
88This guide assumes that you are proficient enough to perform basic Terraform
89tasks. If you are not familiar with Terraform, refer to the [online
90documentation](https://www.terraform.io/intro/getting-started/install.html).
91
92The following AWS resources are required to perform this demo:
93
94- An [Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html)
95- An [IAM user credential with administrator permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html)
96(to be able to create additional IAM policies and instance profiles)
97
98### Download demo assets
99
100Clone or download the demo assets from the
101[hashicorp/vault-guides](https://github.com/hashicorp/vault-guides/tree/master/identity/vault-chef-approle)
102GitHub repository to perform the steps described in this guide.
103
104The following assets can be found in the repository:
105
106- Chef cookbook (**`/chef/cookbooks`**): A sample cookbook with a recipe that installs NGINX
107and demonstrates Vault Ruby Gem functionality used to interact with Vault APIs.
108- Terraform configurations (**`/terraform-aws`**):
109    - **`/terraform-aws/mgmt-node`**: Configuration to set up a management
110    server running both Vault and Chef Server, for demo purposes.
111    - **`/terraform-aws/chef-node`**: Configuration to set up a Chef node and
112    bootstrap it with the Chef Server, passing in Vault's AppRole RoleID and the
113    appropriate Chef run-list.
114- Vault configuration (**`/scripts`**): Data scripts used to configure the
115appropriate mounts and policies in Vault for this demo.
116
117
118## Steps
119
120The scenario in this guide uses Terraform and Chef as trusted entities to
121deliver `RoleID` and `SecretID`.
122
123![AppRole auth method workflow](/img/vault-approle-tf-chef.png)
124
125For the simplicity of the demonstration, both Vault and Chef are installed on
126the same node. Terraform provisions the node which contains the `RoleID` as an
127environment variable. Chef pulls the `SecretID` from Vault.
128
129
130Provisioning for this demo happens in 2 phases:
131
132- [Phase 1 - Provision our Vault plus Chef Server](#phase1)
133    - [Step 1: Provision the Vault and Chef Server](#step-1-provision-the-vault-and-chef-server)
134    - [Step 2: Initialize and Unseal Vault](#step-2-initialize-and-unseal-vault)
135    - [Step 3: AppRole Setup](#step-3-approle-setup)
136    - [Step 4: Configure Tokens for Terraform and Chef](#step-4-configure-tokens-for-terraform-and-chef)
137    - [Step 5: Save the Token in a Chef Data Bag](#step-5-save-the-token-in-a-chef-data-bag)
138    - [Step 6: Write Secrets](#step-6-write-secrets)
139- [Phase 2 - Provision our Chef Node to Show AppRole Login](#phase2)
140
141
142## <a name="phase1"></a>Phase 1: Provision our Vault & Chef Server
143
144### Step 1: Provision the Vault and Chef Server
145
146This provides a quick and simple Vault and Chef Server configuration to help you
147get started.
148
149**NOTE:** This is done for demonstration purpose and **NOT a recommended
150practice** for production.
151
152In this phase, you use Terraform to spin up a server (and associated AWS
153resources) with both Vault and Chef Server installed. Once this server is up and
154running, you'll complete the appropriate configuration steps in Vault to set up
155our AppRole and tokens for use in the demo.
156
157~> If using _Terraform Enterprise_, [create a
158Workspace](https://www.terraform.io/docs/enterprise/getting-started/workspaces.html)
159for this repo and set the appropriate Terraform/Environment variables using the
160`terraform.tfvars.example` file as a reference. Follow the instructions in the
161documentation to perform the appropriate setup in Terraform Enterprise.
162
163#### Using Terraform Open Source:
164
165**Task 1:** Change the working directory (`cd`) to
166`identity/vault-chef-approle/terraform-aws/mgmt-node`.
167
168```shell
169.
170├── main.tf
171├── outputs.tf
172├── templates
173│   └── userdata-mgmt-node.tpl
174├── terraform.tfvars.example
175└── variables.tf
176```
177
178**Task 2:** Update the `terraform.tfvars.example` file to match your account and
179rename it to `terraform.tfvars`.
180
181At minimum, replace the following variable with appropriate values:
182
183- **`s3_bucket_name`**
184- **`vpc_id`**
185- **`subnet_id`**
186- **`key_name`**
187- **`ec2_pem`**
188
189> NOTE: If your VPC, subnet and EC2 key pair were created on a region other than
190`us-east-1`, be sure to set the **`aws_region`** value to match your chosen region.
191
192**Task 3:** Perform a `terraform init` to pull down the necessary provider resources.
193Then `terraform plan` to verify your changes and the resources that will be
194created. If all looks good, then perform a `terraform apply` to provision the
195resources. The Terraform output will display the public IP address to SSH into
196your server.
197
198```plaintext
199$ terraform init
200Initializing provider plugins...
201...
202Terraform has been successfully initialized!
203
204
205$ terraform plan
206...
207Plan: 5 to add, 0 to change, 0 to destroy.
208
209
210$ terraform apply
211...
212Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
213
214Outputs:
215vault-public-ip = 192.0.2.0
216```
217
218The Terraform output will display the public IP address to SSH into
219your server.
220
221For example:
222
223```plaintext
224$ ssh -i "/path/to/EC2/private_key.pem" ubuntu@192.0.2.0
225```
226
227**Task 4:** Initial setup of the Chef server takes several minutes. Once you can
228SSH into your mgmt server, run `tail -f /var/log/tf-user-data.log` to see when
229the initial configuration is complete.
230
231```plaintext
232$ tail -f /var/log/tf-user-data.log
233```
234
235When you see the following message, the initial setup is complete.
236
237```plaintext
238+ echo '2018/03/27 21:53:06 /var/lib/cloud/instance/scripts/part-001: Complete'
239```
240
241You can find the following subfolders in
242your home directory:
243
244- **`/home/ubuntu/vault-chef-approle-demo`**: root of our project
245- **`/home/ubuntu/vault-chef-approle-demo/chef`**: root of our Chef app; this is
246where our `knife` configuration is located (`.chef/knife.rb`)
247- **`/home/ubuntu/vault-chef-approle-demo/scripts`**: there's a
248`vault-approle-setup.sh` script located here to help automate the setup of
249Vault, or you can follow along in the rest of this README to configure Vault
250manually
251
252### Step 2: Initialize and Unseal Vault
253
254Before moving on, set your working environment variables in your mgmt server:
255
256```plaintext
257$ export VAULT_ADDR=http://127.0.0.1:8200
258$ export VAULT_SKIP_VERIFY=true
259```
260
261Before you can do anything in Vault, you need to initialize and unseal it.
262Perform ***one*** of the following:
263
264- **Option 1:** Run the `/home/ubuntu/demo_setup.sh` script to get up and running, and proceed to
265[Phase 2 - Provision our Chef Node to Show AppRole Login](#phase2).
266- **Option 2:** Continue onto [Step 3: AppRole Setup](#step-3-approle-setup) to
267set up the demo environment ***manually***.
268
269
270### Step 3: AppRole Setup
271
272First, initialize and unseal the Vault server using a shortcut.
273
274~> This is a convenient shortcut for demo. **_DO NOT DO THIS IN PRODUCTION!!!_**
275
276Refer to the [online documentation for initializing and unsealing](/intro/getting-started/deploy.html#initializing-the-vault) Vault for more details.
277
278```shell
279# Initialize the Vault server and write out the unseal keys and root token into files
280$ curl --silent
281       --request PUT \
282       --data '{"secret_shares": 1, "secret_threshold": 1}' \
283       ${VAULT_ADDR}/v1/sys/init | tee \
284       >(jq -r .root_token > /home/ubuntu/vault-chef-approle-demo/root-token) \
285       >(jq -r .keys[0] > /home/ubuntu/vault-chef-approle-demo/unseal-key)
286
287# Unseal vault
288$ vault operator unseal $(cat /home/ubuntu/vault-chef-approle-demo/unseal-key)
289
290# Set the root token to VAULT_TOKEN env var
291$ export VAULT_TOKEN=$(cat /home/ubuntu/vault-chef-approle-demo/root-token)
292```
293
294In the next few steps, you will create a number of policies and tokens within
295Vault. Below is a table that summarizes them:
296
297| Policy         | Description | Token Attachment     |
298|--------------------|-------------|------------------------|
299| `app-1-secret-read` | Sets the policy for the final token that will be delivered via the AppRole login | None. This will be delivered to the client upon AppRole login |
300| `app-1-approle-roleid-get` | Sets the policy for the token that you'll give to Terraform to deliver the RoleID (only) | `roleid-token` |
301| `terraform-token-create`   | The Terraform Vault provider doesn't use the token supplied to it directly. This is to prevent the token from being exposed in Terraform's state file. Instead, the Token given to Terraform needs to have the capability to create child tokens with short TTLs. See [here] (https://www.terraform.io/docs/providers/vault/index.html#token) for more info | `roleid-token` |
302| `app-1-approle-secretid-create` | Sets the policy for the token that you'll store in the Chef Data Bag. This will only be able to pull our AppRole's SecretID | `secretid-token` |
303
304
305
306These setups only need to be performed upon initial creation of an AppRole, and
307would typically be done by a Vault administrator.
308
309Now that you have your Vault server unsealed, you can begin to set up necessary
310policies, AppRole auth method, and tokens.
311
312#### Task 1: Set up our AppRole policy
313
314This is the policy that will be attached to _secret zero_ which you are
315delivering to our application (**app-1**).
316
317**API call using cURL**
318
319```bash
320# Policy to apply to AppRole token
321$ tee app-1-secret-read.json <<EOF
322{"policy":"path \"secret/app-1\" {capabilities = [\"read\", \"list\"]}"}
323EOF
324
325# Create the app-1-secret-read policy in Vault
326$ curl --silent \
327       --location \
328       --header "X-Vault-Token: $VAULT_TOKEN" \
329       --request PUT \
330       --data @app-1-secret-read.json \
331       $VAULT_ADDR/v1/sys/policy/app-1-secret-read
332```
333
334<br>
335**CLI command**
336
337```bash
338# Policy to apply to AppRole token
339$ tee app-1-secret-read.hcl <<EOF
340path "secret/app-1" {
341  capabilities = ["read", "list"]
342}
343EOF
344
345# Create the app-1-secret-read policy in Vault
346$ vault policy write app-1-secret-read app-1-secret-read.hcl
347```
348
349
350#### Task 2: Enable the AppRole authentication method
351
352**API call using cURL**
353
354```bash
355# Payload for invoking sys/auth API endpoint
356$ tee approle.json <<EOF
357{
358  "type": "approle",
359  "description": "Demo AppRole auth method"
360}
361EOF
362
363# Enable AppRole auth backend
364$ curl --silent \
365       --location \
366       --header "X-Vault-Token: $VAULT_TOKEN" \
367       --request POST \
368       --data @approle.json \
369       $VAULT_ADDR/v1/sys/auth/approle
370```
371<br>
372**CLI command**
373
374```plaintext
375$ vault auth enable -description="Demo AppRole auth method" approle
376```
377
378#### Task 3: Configure the AppRole
379
380Now, you are going to create an AppRole role named, **app-1**.
381
382**API call using cURL**
383
384```bash
385# Payload containing AppRole auth method configuration
386# TTL is set to 10 minutes, and Max TTL to be 30 minutes
387$ tee app-1-approle-role.json <<EOF
388{
389    "role_name": "app-1",
390    "bind_secret_id": true,
391    "secret_id_ttl": "10m",
392    "secret_id_num_uses": "1",
393    "token_ttl": "10m",
394    "token_max_ttl": "30m",
395    "period": 0,
396    "policies": [
397        "app-1-secret-read"
398    ]
399}
400EOF
401
402# AppRole backend configuration
403$ curl --silent \
404       --location \
405       --header "X-Vault-Token: $VAULT_TOKEN" \
406       --request POST \
407       --data @app-1-approle-role.json \
408       $VAULT_ADDR/v1/auth/approle/role/app-1
409```
410<br>
411**CLI command**
412
413```bash
414# TTL is set to 10 minutes, and Max TTL to be 30 minutes
415$ vault write auth/approle/role/app-1 policies="app-1-secret-read" token_ttl="10m" token_max_ttl="30m"
416```
417
418
419### Step 4: Configure Tokens for Terraform and Chef
420
421Now, you're ready to configure the policies and tokens to Terraform and Chef to
422interact with Vault. Remember, the point here is that you are giving each system
423a _limited_ token that is only able to pull either the `RoleID` or `SecretID`,
424_but not both_.
425
426![AppRole auth method workflow](/img/vault-approle-tf-chef-2.png)
427
428#### Task 1: Create a policy and token for Terraform
429Create a token with appropriate policies allowing Terraform to pull
430the `RoleID` from Vault:
431
432**API call using cURL**
433
434```bash
435# Policy file granting to retrieve RoleID from Vault
436$ tee app-1-approle-roleid-get.hcl <<EOF
437{"policy":"path \"auth/approle/role/app-1/role-id\" {capabilities = [\"read\"]}"}
438EOF
439
440# Create the app-1-approle-roleid-get policy in Vault
441$ curl --silent \
442       --location \
443       --header "X-Vault-Token: $VAULT_TOKEN" \
444       --request PUT \
445       --data @app-1-approle-roleid-get.hcl \
446       $VAULT_ADDR/v1/sys/policy/app-1-approle-roleid-get
447
448# For Terraform
449# See: https://www.terraform.io/docs/providers/vault/index.html#token
450# Policy granting to create tokens required by Terraform
451$ tee terraform-token-create.hcl <<EOF
452{"policy":"path \"/auth/token/create\" {capabilities = [\"update\"]}"}
453EOF
454
455# Create the app-1-approle-roleid-get policy in Vault
456$ curl --silent \
457       --location \
458       --header "X-Vault-Token: $VAULT_TOKEN" \
459       --request PUT \
460       --data @terraform-token-create.hcl \
461       $VAULT_ADDR/v1/sys/policy/terraform-token-create
462
463# Payload to configure token for Terraform to pull RoleID
464$ tee roleid-token-config.json <<EOF
465{
466  "policies": [
467    "app-1-approle-roleid-get",
468    "terraform-token-create"
469  ],
470  "meta": {
471    "user": "terraform-demo"
472  },
473  "ttl": "720h",
474  "renewable": true
475}
476EOF
477
478# Get token and save it in roleid-token.json
479$ curl --silent \
480       --location \
481       --header "X-Vault-Token: $VAULT_TOKEN" \
482       --request POST \
483       --data @roleid-token-config.json \
484       $VAULT_ADDR/v1/auth/token/create > roleid-token.json
485```
486
487The token and associated metadata will be written out to the file
488`roleid-token.json`. The `client_token` value is what you'll give to Terraform.
489The file should look similar to the following:
490
491```plaintext
492$ cat roleid-token.json | jq
493{
494  "request_id": "2e1d05eb-988d-4cf7-7b6a-d2668de31536",
495  "lease_id": "",
496  "renewable": false,
497  "lease_duration": 0,
498  "data": null,
499  "wrap_info": null,
500  "warnings": null,
501  "auth": {
502    "client_token": "6a7ad093-42ab-885e-3d67-6d51a5583da6",
503    "accessor": "f6170506-ee0f-5a59-8478-e0aac2d3259f",
504    "policies": [
505      "app-1-approle-roleid-get",
506      "default",
507      "terraform-token-create"
508    ],
509    "metadata": {
510      "user": "terraform-demo"
511    },
512    "lease_duration": 2592000,
513    "renewable": true,
514    "entity_id": ""
515  }
516}
517```
518<br>
519**CLI command**
520
521```bash
522# Policy file granting to retrieve RoleID from Vault
523$ tee app-1-approle-roleid-get.hcl <<EOF
524path "auth/approle/role/app-1/role-id" {
525  capabilities = [ "read" ]
526}
527EOF
528
529# Create the app-1-approle-roleid-get policy in Vault
530$ vault policy write app-1-approle-roleid-get app-1-approle-roleid-get.hcl
531
532# For Terraform
533# See: https://www.terraform.io/docs/providers/vault/index.html#token
534# Policy granting to create tokens required by Terraform
535$ tee terraform-token-create.hcl <<EOF
536path "auth/token/create" {
537  capabilities = [ "update" ]
538}
539EOF
540
541# Create the app-1-approle-roleid-get policy in Vault
542$ vault policy write terraform-token-create terraform-token-create.hcl
543
544# Get token and save it in roleid-token.txt
545$ vault token create -policy="app-1-approle-roleid-get" -policy="terraform-token-create" \
546      -metadata="user"="terraform-user" > roleid-token.txt
547```
548
549The token and associated metadata will be written out to the file
550`roleid-token.txt`. The `token` value is what you'll give to Terraform.
551The file should look similar to the following:
552
553```plaintext
554$ cat roleid-token.txt
555Key                Value
556---                -----
557token              2600aeda-6385-c163-7171-543b1e1fabcf
558token_accessor     6ef835e3-4948-8c61-1e89-3625ca31fd84
559token_duration     768h
560token_renewable    true
561token_policies     [app-1-approle-roleid-get default terraform-token-create]
562token_meta_user    terraform-demo
563```
564
565#### Task 2: Create a policy and token for Chef
566Create a token with appropriate policies allowing Chef to pull the `SecretID`
567from Vault:
568
569**API call using cURL**
570
571```bash
572# Policy file granting to retrieve SecretID
573$ tee app-1-approle-secretid-create.hcl <<EOF
574{"policy":"path \"auth/approle/role/app-1/secret-id\" {capabilities = [\"update\"]}"}
575EOF
576
577# Create the app-1-approle-secretid-create policy in Vault
578$ curl --silent \
579    --location \
580    --header "X-Vault-Token: $VAULT_TOKEN" \
581    --request PUT \
582    --data @app-1-approle-secretid-create.hcl \
583    $VAULT_ADDR/v1/sys/policy/app-1-approle-secretid-create
584
585# Payload to invoke auth/token/create endpoint
586$ tee secretid-token-config.json <<EOF
587{
588  "policies": [
589    "app-1-approle-secretid-create"
590  ],
591  "meta": {
592    "user": "chef-demo"
593  },
594  "ttl": "720h",
595  "renewable": true
596}
597EOF
598
599# Get token for Chef to get SecretID from Vault and store it in secretid-token.json
600$ curl --silent \
601       --location \
602       --header "X-Vault-Token: $VAULT_TOKEN" \
603       --request POST \
604       --data @secretid-token-config.json \
605       $VAULT_ADDR/v1/auth/token/create > secretid-token.json
606```
607
608The resulting file should look like this:
609
610```plaintext
611$ cat secretid-token.json | jq
612{
613  "request_id": "6f6ad8a1-fedb-b838-60ce-87999f01aff6",
614  "lease_id": "",
615  "renewable": false,
616  "lease_duration": 0,
617  "data": null,
618  "wrap_info": null,
619  "warnings": null,
620  "auth": {
621    "client_token": "cdfdb7a0-d7a6-3769-927d-0ace297726ea",
622    "accessor": "88e8aaca-1584-4881-3368-d9cb5cd7ddae",
623    "policies": [
624      "app-1-approle-secretid-create",
625      "default"
626    ],
627    "metadata": {
628      "user": "chef-demo"
629    },
630    "lease_duration": 2592000,
631    "renewable": true,
632    "entity_id": ""
633  }
634}
635```
636
637<br>
638**CLI command**
639
640```bash
641# Policy file granting to retrieve SecretID
642$ tee app-1-approle-secretid-create.hcl <<EOF
643path "auth/approle/role/app-1/secret-id" {
644  capabilities = [ "update" ]
645}
646EOF
647
648# Create the app-1-approle-secretid-create policy in Vault
649$ vault policy write app-1-approle-secretid-create app-1-approle-secretid-create.hcl
650
651# Get token for Chef to get SecretID from Vault and store it in secretid-token.txt
652$ vault token create -policy="app-1-approle-secretid-create" \
653      -metadata="user"="chef-demo" > secretid-token.txt
654```
655
656The resulting file should look like this:
657
658```plaintext
659$ cat secretid-token.txt
660Key                Value
661---                -----
662token              20d69183-59cb-c953-6dea-34f5f1bbe5f7
663token_accessor     a17e7a43-c14a-b96a-0014-9149d218e74a
664token_duration     768h
665token_renewable    true
666token_policies     [app-1-approle-secretid-create default]
667token_meta_user    chef-demo
668```
669
670
671
672### Step 5: Save the Token in a Chef Data Bag
673
674At this point, you have a client token generated for Terraform and another for
675Chef server to log into Vault. For the sake of simplicity, you can put the
676Chef's client token (`secretid-token.json`) in a [Data
677Bag](https://docs.chef.io/data_bags.html) which is fine because this token can
678***only*** retrieve `SecretID` from Vault which is not much of a use without a
679corresponding `RoleID`.
680
681Now, create a Chef Data Bag and put the `SecretID` token (`secretid-token.json`)
682along with the rest of its metadata.
683
684```bash
685$ cd /home/ubuntu/vault-chef-approle-demo/chef/
686
687# Use the path for where you created this file in the previous step
688# You're just adding an 'id' field to the file as that's a required field for data bags
689$ cat /home/ubuntu/secretid-token.json | jq --arg id approle-secretid-token '. + {id: $id}' > secretid-token.json
690
691$ knife data bag create secretid-token
692
693$ knife data bag from file secretid-token secretid-token.json
694
695$ knife data bag list
696
697$ knife data bag show secretid-token
698
699$ knife data bag show secretid-token approle-secretid-token
700```
701
702The last step should show the following output:
703
704```plaintext
705$ knife data bag show secretid-token approle-secretid-token
706WARNING: Unencrypted data bag detected, ignoring any provided secret options.
707auth:
708  accessor:       88e8aaca-1584-4881-3368-d9cb5cd7ddae
709  client_token:   cdfdb7a0-d7a6-3769-927d-0ace297726ea
710  entity_id:
711  lease_duration: 2592000
712  metadata:
713  policies:
714    app-1-approle-secretid-create
715    default
716  renewable:      true
717data:
718id:             approle-secretid-token
719lease_duration: 0
720lease_id:
721renewable:      false
722request_id:     6f6ad8a1-fedb-b838-60ce-87999f01aff6
723warnings:
724wrap_info:
725```
726
727### Step 6: Write Secrets
728
729Let's write some test data in the `secret/app-1` path so that the target app
730will have some secret to retrieve from Vault at a later step.
731
732**API call using cURL**
733
734```bash
735# Write some demo secrets
736$ tee demo-secrets.json <<'EOF'
737{
738  "username": "app-1-user",
739  "password": "$up3r$3cr3t!"
740}
741EOF
742
743$ curl --silent \
744       --location \
745       --header "X-Vault-Token: $VAULT_TOKEN" \
746       --request POST \
747       --data @demo-secrets.json \
748       $VAULT_ADDR/v1/secret/app-1
749
750# Verify that you can read back the data:
751$ curl --silent \
752       --location \
753       --header "X-Vault-Token: $VAULT_TOKEN" \
754       --request GET \
755       $VAULT_ADDR/v1/secret/app-1 | jq
756{
757  "request_id": "1f73c7ee-27fa-bad0-9c77-b330eef1ea88",
758  "lease_id": "",
759  "renewable": false,
760  "lease_duration": 2764800,
761  "data": {
762    "password": "$up3r$3cr3t!",
763    "username": "app-1-user"
764  },
765  "wrap_info": null,
766  "warnings": null,
767  "auth": null
768}
769```
770<br>
771**CLI command**
772
773```bash
774# Write some demo secrets
775$ vault write secret/app-1 username="app-1-user" password="\$up3r\$3cr3t!"
776
777# Verify that you can read back the data:
778$ vault read secret/app-1
779Key                 Value
780---                 -----
781refresh_interval    768h
782password            $up3r$3cr3t!
783username            app-1-user
784```
785
786
787-> At this point, just about all the pieces are in place. Remember, these setup
788steps will only need to be performed upon initial creation of an AppRole, and
789would typically be done by a Vault administrator.
790
791
792
793## <a name="phase2"></a>Phase 2: Provision our Chef Node to Show AppRole Login
794
795To complete the demo, run the **`chef-node`** Terraform configuration to see how
796everything talks to each other.
797
798#### Task 1: Change the working directory
799
800Open another terminal on your host machine (**not** the `mgmt-node`)
801and `cd` into the `identity/vault-chef-approle/terraform-aws/chef-node`
802directory:
803
804```plaintext
805$ cd identity/vault-chef-approle/terraform-aws/chef-node
806```
807
808#### Task 2: Update terraform.tfvars.example
809
810Replace the variable values in `terraform.tfvars.example` to match your
811environment and save it as `terraform.tfvars` like you have done at [Step 1](#step-1-provision-the-vault-and-chef-server).
812
813Note the following:
814
815* Update the **`vault_address`** and **`chef_server_address`** variables with
816the IP address of our `mgmt-node` from above.
817* Update the **`vault_token`** variable with the `RoleID` token from **Task 1**
818in [Step 4](#step-4-configure-tokens-for-terraform-and-chef).
819  - If you ran the `demo-setup.sh` script (_Option 1_), retrieve the
820  `client_token` in the `/home/ubuntu/vault-chef-approle-demo/roleid-token.json`
821  file:
822
823```plaintext
824$ cat ~/vault-chef-approle-demo/roleid-token.json | jq ".auth.client_token"
825```
826
827
828#### Task 3: Run Terraform
829Perform a `terraform init` to pull down the necessary provider
830resources. Then `terraform plan` to verify your changes and the resources that
831will be created. If all looks good, then perform a `terraform apply` to
832provision the resources.
833
834The Terraform output will display the public IP address to SSH into your
835server.
836
837> **NOTE:** If the `terraform apply` fails with "`io: read/write on closed pipe`"
838error, this is a [known
839issue](https://github.com/hashicorp/terraform/issues/17638) with Terraform
8400.11.4 and 0.11.5.  Please try again with another Terraform version.
841
842At this point, Terraform will perform the following actions:
843
844- Pull a `RoleID` from our Vault server
845- Provision an AWS instance
846- Write the `RoleID` to the AWS instance as an environment variable
847- Run the Chef provisioner to bootstrap the AWS instance with our Chef Server
848- Run our Chef recipe which will install NGINX, perform our AppRole login, get
849our secrets, and output them to our `index.html` file
850
851![AppRole auth method workflow](/img/vault-approle-tf-chef-3.png)
852
853The Chef recipe can be found at
854`identity/vault-chef-approle/chef/cookbooks/vault_chef_approle_demo/recipes/default.rb`.
855
856```shell
857...
858# Configure address for Vault Gem
859Vault.address = ENV['VAULT_ADDR']
860
861# Get AppRole RoleID from our environment variables (delivered via Terraform)
862var_role_id = ENV['APPROLE_ROLEID']
863
864# Get Vault token from data bag (used to retrieve the SecretID)
865vault_token_data = data_bag_item('secretid-token', 'approle-secretid-token')
866
867# Set Vault token (used to retrieve the SecretID)
868Vault.token = vault_token_data['auth']['client_token']
869
870# Get AppRole SecretID from Vault
871var_secret_id = Vault.approle.create_secret_id('app-1').data[:secret_id]
872...
873```
874
875#### Task 4: Verification
876Once Terraform completes the `apply` operation, it will output the public IP
877address of our new server. You can plug that IP address into a browser to see
878the output. It should look similar to the following:
879
880```plaintext
881Role ID:
882f6286b97-246e-9fb4-4d9f-0c9465451851
883
884Secret ID:
88572f4b60c-26d0-d947-5026-153943174831
886
887AppRole Token:
888d11d81e4-0ba1-fefc-03f8-e5f06793b60d
889
890Read Our Secrets:
891{:password=>"$up3r$3cr3t!", :username=>"app-1-user"}
892```
893
894## Additional References
895
896The following is a curated list of webinars, blogs and GitHub repositories that
897add additional context to fill out the concepts discussed in the webinar and
898demonstrated in the code:
899
900- [Managing Secrets in a Container Environment by Jeff Mitchell](https://www.youtube.com/watch?v=skENC9aXgco)
901- [Using HashiCorp's Vault with Chef written by Seth Vargo](https://www.hashicorp.com/blog/using-hashicorps-vault-with-chef)
902- [Manage Secrets with Chef and HashiCorps Vault by Seth Vargo & JJ Asghar](https://blog.chef.io/2016/12/12/manage-secrets-with-chef-and-hashicorps-vault/)
903    - [Associated GitHub repository](https://github.com/sethvargo/vault-chef-webinar)
904- [Vault AppRole Authentication written by Alan Thatcher](http://blog.alanthatcher.io/vault-approle-authentication/)
905- [Integrating Chef and HashiCorp Vault written by Alan Thatcher](http://blog.alanthatcher.io/integrating-chef-and-hashicorp-vault/)
906- [Vault Ruby Client](https://github.com/hashicorp/vault-ruby)
907
908
909## Next Steps
910
911Watch the video recording of the [Delivering Secret Zero: Vault AppRole with
912Terraform and
913Chef](https://www.hashicorp.com/resources/delivering-secret-zero-vault-approle-terraform-chef)
914webinar which talks about the usage of AppRole with Terraform and Chef as its
915trusted entities.
916