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