Retrieve secrets for AWS applications with Vault Agent
You must pass an authentication token with any request from an authenticated endpoint in Vault. This includes all API requests, as well as via the Vault CLI and other libraries.
Vault supports several different authentication methods to enable delivery of the initial token. If you can securely get the first secret from an originator to a consumer, then all secrets later exchanged between them can be authenticated. Getting that first secret to the consumer is the secure introduction challenge.
To that end, Vault provides integration with native authentication capabilities in various environments. For example: IAM in AWS and Google Cloud, Managed Service Identities in Azure, and Service Accounts in Kubernetes are all supported.
Challenge
Although Vault provides the auth method, the client is still responsible for managing the lifecycle of tokens created from the auth method. The challenge then becomes how to enable authentication to Vault, and manage token lifecycle in a standard way without writing custom logic.
Solution
Vault Agent provides a number of different helper features, specifically addressing the following challenges:
- Automatic authentication
- Secure delivery/storage of tokens
- Lifecycle management of these tokens (renewal & re-authentication)
NOTE: The Vault Agent Auto-Auth functionality addresses the challenges related to obtaining and managing authentication tokens (secret zero).
Note
The Secure Introduction of Vault Clients introduced three basic approaches: Platform Integration, Trusted Orchestrator, and Vault Agent. This tutorial demonstrates how Vault Agent works.
Prerequisites
To complete this section of the tutorial, you need the following:
- Terraform v1.0.0 or later installed.
- AWS account and associated credentials that allow for the creation of resources.
tree
utility for visualizing directory contents (you can usels -1R
instead).
Provision the cloud resources
Clone the demo assets from the HashiCorp Education repository GitHub repository to perform the steps described in this tutorial.
This repository has supporting content for all the Vault learn tutorials. You can find the content for this tutorial within a sub-directory.
Be sure to set your working directory to location of the
learn-vault-agent-demo/terraform-aws
folder.The working directory should contain the provided Terraform files:
NOTE: The example Terraform configuration in this repository is for demonstration purposes, and not suitable for production use. For production deployment, refer the example Terraform in the Vault Guides repository /operations/provision-vault.
Set an
AWS_ACCESS_KEY_ID
environment variable to hold your AWS access key ID.Set an
AWS_SECRET_ACCESS_KEY
environment variable to hold your AWS secret access key.Tip
The above example uses IAM user authentication. You can use any authentication method described in the AWS provider documentation.
Copy the
terraform.tfvars.example
file and rename it asterraform.tfvars
. Within this file, edit thekey_name
parameter to be the name of your EC2 key pair.Example:
terraform.tfvarsYou should also change the values of the AWS region and availability zone or instance type as necessary.
Tip
If you don't have an EC2 key pair, follow the AWS documentation to create one.
Initialize the Terraform workspace, and download the necessary provider resources.
Run
terraform apply
and review the planned actions. Your terminal output should show the plan, resources Terraform will provision.Enter
yes
to confirm and resume.When the
apply
command completes, the Terraform output will display the public IP address to SSH into your Vault server and client instances.Example output:
Configure AWS IAM auth method
Note
Perform this step on the Vault server instance.
In this step, you will configure Vault to allow AWS IAM authentication from specific IAM roles.
SSH into the Vault server instance.
At the prompt, enter "yes" to continue.
Tip
If you received
Permissions 0664 for '<key_name>.pem' are too open
error, be sure to set the file permission appropriately.To verify your Vault installation, run
vault status
command and notice that Initialized isfalse
.Run the
vault operator init
command to initialize the Vault server:Tip
The Vault server uses auto-unseal with AWS Key Management Service (KMS). When you initialize the Vault, the server is automatically unsealed. To learn how to auto-unseal Vault using AWS KMS, refer to the Auto-unseal using AWS KMS tutorial.
Copy the Initial Root Token value.
Log into Vault. Enter the generated initial root token when prompted.
Examine and then execute the
/home/ubuntu/aws_auth.sh
script.The script enables key/value v1 secrets engine at
secret
and writes some test data atsecret/myapp/config
(at line 1 and 2).At line 4 through 6, it creates a
myapp
policy, and line 8 enables theaws
auth method.It creates a role named
dev-role-iam
which is valid for 24 hours with capabilities set by themyapp
policy. (Note: The${account_id}
should be your AWS account ID.) Thebound_iam_principal_arn
is the Amazon Resource Name (ARN) of the IAM role created by theiam.tf
file (at line 11).aws_auth.sh1 2 3 4 5 6 7 8 9 1011
Execute the script.
Check the
myapp
policy.Check the secrets written in
secret/myapp/config
.
Run Vault Agent with auto-auth
Note
Perform this step on the Vault client instance.
Now, you are going to see how Vault Agent Auto-Auth method works, and write out a token to an arbitrary location on disk. Vault Agent is a client daemon and its Auto-Auth feature allows for easy authentication to Vault.
Open a new terminal and SSH into the Vault Client instance.
At the prompt, enter "yes" to continue.
In the client instance, explore the Vault Agent configuration file (
/home/ubuntu/vault-agent.hcl
).Starting at line 4, the
auto_auth
block has two configuration entries:method
andsink
. In this example, Auto-Auth uses theaws
auth method enabled at theauth/aws
path on the Vault server. The Vault Agent will use thedev-role-iam
role to authenticate.The
sink
block specifies the location on disk where to write tokens. You can define the Vault Agent Auto-Authsink
more than once if you want Vault Agent to place the token into additional locations. In this example, thesink
path is/home/ubuntu/vault-token-via-agent
.The
exit_after_auth
parameter istrue
. This means that the agent will exit with code 0 after a single successful authentication. The default isfalse
and the agent continues to run and automatically renew the client token for you.vault-agent.hcl1 2 3 4 5 6 7 8 9 10111213141516171819202122
The
vault
block points to the Vault serveraddress
. This should match to the private IP address of your Vault server host.Tip
For the full details of Vault Agent configuration parameters, refer to the Vault Agent documentation.
Execute the following command to get help:
Now, you are ready to run the Vault Agent. Execute the following command:
Because the
vault-agent.hcl
configuration file contained the lineexit_after_auth = true
, Vault Agent authenticated and retrieved a token once, wrote it to the defined sink, and exited. Vault Agent can also run in daemon mode where it will continuously renew the retrieved token, and try to re-authenticate if that token becomes invalid. Vault Agent Caching tutorial will show running Vault Agent as a daemon.Vault Agent writes the token to
/home/ubuntu/vault-token-via-agent
.Export a VAULT_ADDR environment variable to address the Vault server directly.
Try an API call using the token that Vault Agent retrieved to test:
Output:
Response wrap the token
Note
Perform this step on the Vault client instance.
It may not be ideal to write the token as a plaintext depending on the firewall around the client instance. Vault Agent supports response-wrapping of the token to offer an additional layer of protection for the token. You can wrap tokens by either the auth method or by the sink configuration, with each approach solving for different challenges as described in Response-Wrapping Tokens.
In the client instance, explore the
/home/ubuntu/vault-agent-wrapped.hcl
file which supports response-wrapping of the token.Notice the
wrap_ttl
parameter in thesink
block. This configuration uses the sink method to response-wrap the retrieved tokens.From the client, run the Vault Agent again and inspect the output:
Instead of a token value, you now have a JSON object containing a wrapping token as well as some additional metadata. To get to the true token, you need to first perform an
unwrap
operation.Unwrap the response-wrapped token and save it to a
VAULT_TOKEN
environment variable that other applications can use:View the unwrapped token value.
Test to make sure that the token has the read permission on
secret/myapp/config
.Notice that the value saved to the
VAULT_TOKEN
is not the same as thetoken
value in the/home/ubuntu/vault-token-via-agent
file. The value inVAULT_TOKEN
is the unwrapped token retrieved by Vault Agent.If you try to unwrap that same value again or wait longer than 5 minutes (
wrap_ttl
), it will throw an error:You can unwrap a response-wrapped token just once. Additional attempts to unwrap an already-unwrapped token will result in triggering an error.
Note
In this tutorial, you learned about the basic mechanics of Vault Agent. Read the Additional Discussion section about the next step.
Clean up
Return to the first terminal where you created the cluster and use Terraform to destroy the cluster.
Destroy the AWS resources provisioned by Terraform.
Delete the state file.
Additional discussion
In the above examples, you manually ran Vault Agent to show how it works. How you actually integrate Vault Agent into your application deployment workflow will vary based on several factors. Some questions to ask to help decide appropriate usage:
- What is the lifecycle of my application? Is it more ephemeral or long-lived?
- What are the lifecycles of my authentication tokens? Are they long-lived and requiring repetitive renewal to show liveliness of a service or do you want to enforce periodic re-authentications?
- Do I have a group of applications running on my host which each need their own token? Can I use a native authentication capability (e.g. AWS IAM, K8s, Azure MSI, Google Cloud IAM, etc.)?
The answers to these questions will help you decide if Vault Agent should run
as a daemon or as a prerequisite of a service configuration. Take for example
the following Systemd
service definition for running Nomad:
Notice the ExecStartPre
directive that runs Vault Agent before the desired
service starts. The service startup script expects a Vault token value set
as shown in the /usr/bin/nomad-vault.sh
startup script:
Applications which expect Vault tokens typically look for a VAULT_TOKEN
environment variable. Here, you're using Vault Agent to get a token and write it out to a
RAM disk and as part of the Nomad startup script. You read the response-wrapped
token from the RAM disk, and save it to your VAULT_TOKEN
environment variable before starting Nomad.
Vault Agent in Vault version 1.3.0 or higher also supports secret templates for use in configuration files, and other similar use cases. You can learn more about this feature in Vault Agent Templates.
Help and reference
- Blog post: Why Use the Vault Agent for Secrets Management?
- Video: Streamline Secrets Management with Vault Agent and Vault 0.11
- Secure Introduction of Vault Clients
- Vault Agent Auto-Auth documentation
- AWS Auth Method documentation
Other Vault Agent tutorials:
- Vault Agent with Kubernetes
- Vault Agent Templates
- Vault Agent Caching
- Vault Agent Windows Service
- Using HashiCorp Vault Agent with .NET Core
To learn more about the response wrapping feature, refer the following: