Vault ACL with Nomad Workload Identities
Nomad integrates with Vault to retrieve static and dynamic secrets for workloads.
Production deployments of Nomad and Vault must always run with the Access Control List (ACL) system enabled since it protects against unauthorized access to the cluster. When ACLs are enabled, both Nomad and Vault must be properly configured in order for their integrations to work.
Nomad can generate workload identities for tasks, which are represented as JSON Web Tokens (JWT) signed by Nomad. These identities can be used as proof to third parties that a workload was actually created and is managed by Nomad. If the third party is configured to trust Nomad, it can automatically grant specific access and permissions to Nomad workloads.
In this tutorial, you will:
- Start a Nomad and Vault agent with ACL enabled.
- Generate ACL tokens to access Nomad and Vault.
- Configure Vault to accept workload identities from Nomad.
- Configure Nomad to automatically generate and sign workload identities for tasks that need access to Vault.
- Deploy sample Nomad jobs that interact with Vault.
Launch Terminal
This tutorial includes a free interactive command-line lab that lets you follow along on actual cloud infrastructure.
Prerequisites
This tutorial requires you to have basic familiarity with Nomad and Vault. If you are new to these tools, complete the Nomad Get Started and Vault Get Started tutorials before following this one.
You will need the following tools installed:
- Nomad 1.7 or later installed locally
- Vault 1.12 or later installed locally
- Docker installed and running locally
Start the Vault agent
Start a Vault dev server.
Dev Agents
This tutorial uses development agents for Vault and Nomad as a quick way to get started. Dev agents have ephemeral state and should not be used in production environments. They also run in the foreground of your terminal so do not close the terminal window or you will need to rerun the agent configuration steps again.
Copy the value for Root Token
.
Open another terminal window in the same directory and set the root token as
the environment variable VAULT_TOKEN
. This terminal will act as the main
terminal session where you will run commands.
Set the environment variable VAULT_ADDR
.
Start the Nomad agent
Create a file named nomad.hcl
. Add the following contents to it and save the
file.
The vault
block in this configuration file provides
the information necessary for Nomad to connect to Vault.
It also defines a default workload identity, default_identity
, that is
automatically added to jobs that need access to Vault. Without this identity,
you would need to define an identity
block in your jobs for every task that
needs access to Vault.
Open another terminal window in the same directory and start the Nomad dev agent.
Return to your main terminal window and bootstrap the Nomad ACL system.
Copy the value of Secret ID
and set it as the environment variable
NOMAD_TOKEN
.
Using Bootstrap Tokens
The initial ACL bootstrap tokens from Vault and Nomad have full access to the cluster and should not be used for regular day-to-day operations in a production environment. They are used in this tutorial as an illustration. We recommend creating ACL policies and tokens with only a level of access necessary to perform the required operations.
Configure Vault to accept Nomad workload identities
Create a Vault ACL auth method
Enable a jwt
auth method in Vault under the path
jwt-nomad
.
The JWT auth method creates an endpoint that Nomad clients use to exchange Nomad workload identity JWTs for Vault ACL tokens.
Create a file named vault-auth-method-jwt-nomad.json
. Add the following
contents to it and save the file.
This configuration file contains important information.
jwks_url
is the URL that Vault uses to contact Nomad and retrieve the data necessary to validate Nomad workload identities. In a production environment, this should resolve to multiple Nomad agents via a reverse proxy, load balancer, or DNS entry to prevent a single point of failure.default_role
is the Vault ACL role applied by default to tokens generated by this auth method. You will create thenomad-workloads
role in the next section.
Apply the configuration file vault-auth-method-jwt-nomad.json
to the
jwt-nomad
auth method.
Create a Vault ACL role
Create a file named vault-role-nomad-workloads.json
. Add the following
contents to it and save the file.
It defines properties for the Vault ACL tokens that are used for Nomad tasks.
bound_audiences
configures Vault to only accept JWTs that have an audience value ofvault.io
. It must match theaud
value present in the Nomad agent configuration and jobs.claim_mappings
are values from the Nomad workload identity. You will reference them when creating the Vault ACL policy for this role.token_period
determines how long the token is valid for before it expires. Nomad automatically renews tokens before they expire.token_explicit_max_ttl
is the maximum amount of time the token is valid. It must be set to0
so Nomad can renew them for as long as the workload runs.token_policies
are the ACL policies applied to the tokens. They specify the permissions that tokens with this role have. You will create the policynomad-workloads
policy in the next section.
Create a Vault ACL role named nomad-workloads
using the
vault-role-nomad-workloads.json
file.
This role is applied by default to Vault ACL tokens generated from the auth
method jwt-nomad
.
Create a Vault ACL policy
List all of the auth methods registered in Vault.
Copy the Accessor
value for the auth method in the jwt-nomad/
path.
Create a file named vault-policy-nomad-workloads.hcl
. Add the following
contents to it, replace all the instances of the AUTH_METHOD_ACCESSOR
placeholder with the Accessor
value from the output, and save the file. There
are five occurrences to update.
This file is a templated Vault ACL policy that
automatically grants Nomad workloads access to secrets based on the
properties mapped in the claim_mappings
of the Vault ACL role.
More specifically, this policy grants access to secrets in the path
kv/data/<job namespace>/<job name>/*
where <job namespace>
and <job name>
are dynamically set for each workload.
Create a Vault ACL policy named nomad-workloads
using the file
vault-policy-nomad-workloads.hcl
.
Run a Nomad job to read secrets from Vault
Start a MongoDB database with a root password that is read from Vault using the Nomad workload identity for the task.
Enable the kv
secret engine.
Write a secret in Vault for the database root password in the path
default/mongo/config
.
Create a file named mongo.nomad.hcl
. Add the following contents to it and
save the file.
- The
vault
block indicates that the task needs access to Vault and that Nomad should use the task workload identity to get a Vault ACL token. - The
template
block reads the root password secret from Vault under the pathkv/data/default/mongo/config
. - The job runs in the Nomad
default
namespace and the job name ismongo
. Thenomad-workloads
Vault role grants access to secrets in the pathkv/data/default/mongo/*
, which is where the root password exists. - The job does not specify any identity for Vault, so Nomad uses the
default_identity
from the agent configuration.
Run the job with the mongo.nomad.hcl
file and wait for the deployment to
complete.
Verify that you are able to execute a query against the database using the
root
user credentials.
Retrieve the job definition from Nomad and filter the output to only display its task.
The Identities
list contains the workload identity that Nomad injects
following the specification in the default_identity
block from the Nomad
server configuration file.
By configuring Vault to accept workload identities from Nomad, the Nomad task was able to automatically receive a Vault ACL token scoped to the level of access defined by the auth method default role. With this method, Nomad agents no longer require long-lived, highly permissive Vault tokens.
Configure Vault dynamic secrets for MongoDB
The MongoDB database reads a secret from Vault using the permissions in the default Vault ACL role.
In some situations, it may be necessary to customize the permissions granted to a task to be different from this default. This is done by creating additional Vault ACL roles for Nomad jobs.
Configure Vault with a dynamic secret for a non-root MongoDB user that the default Vault ACL policy does not grant access to then run a Nomad job using a custom Vault ACL role to be able to access the dynamic secret.
Enable the Vault database secrets engine.
Create a file named vault-dynamic-secret-mongo.json
. Add the following
contents to it and save the file.
Write the vault-dynamic-secret-mongo.json
configuration for the MongoDB
dynamic secret to connect to the database.
Create a file named vault-database-role-mongo.json
. Add the following
contents to it and save the file.
Create a Vault database role using the vault-database-role-mongo.json
file.
Create a Vault ACL role to access the dynamic secret
Create a file named vault-role-mongo-dynamic-secret.json
. Add the following
contents to it and save the file.
This role is similar to the one from earlier in the tutorial but this one uses
a different policy, called mongo-dynamic-secret
, which you will create in the
next section.
It also defines a set of bound_claims
to restrict which workload identities
from Nomad are able to use this role. In this example, the role only allows the
job mongo-query
in the Nomad namespace default
to use it.
Create the mongo-dynamic-secret
ACL role using the
vault-role-mongo-dynamic-secret.json
file.
Create a file named vault-policy-mongo-dynamic-secret.hcl
. Add the following
contents to it and save the file.
This ACL policy only grants access to the specific path database/creds/mongo
,
which is not included in the default role used by the jwt-nomad
auth method.
Create the mongo-dynamic-secret
ACL policy using the
vault-policy-mongo-dynamic-secret.hcl
file.
Run a Nomad job with a custom Vault ACL role
Create a file named mongo-query.nomad.hcl
. Add the following contents to it
and save the file.
Note that the vault
block specifies the mongo-dynamic-secret
role. The task
can only access the dynamic credentials for MongoDB.
The template
block reads these credentials and exposes them as environment
variables to the task so it can use them.
Run the Nomad job from the file mongo-query.nomad.hcl
.
Retrieve the allocation information and wait until the status is complete
.
You may need to run the command a few times before the status changes to
complete
.
Retrieve the query result to confirm the job was able to connect to the MongoDB database.
Note that the authenticated user is now a dynamic user credential.
Templated Vault ACL policies provide great flexibility when defining access rules, but a single policy, or a specific group of policies, may not be enough to cover all use cases.
Creating additional Vault ACL roles for specific Nomad jobs can help better manage access control to Vault secrets.
Next steps
In this tutorial, you configured Nomad and Vault to communicate with ACL enabled. You also configured Nomad to automatically add workload identities for tasks that need access to Vault.
You then deployed Nomad jobs to read static and dynamic secrets from Vault using different Vault ACL roles and policies. Both jobs used their workload identities to receive a Vault ACL token properly scoped to the work they needed to do.
This process required several steps, with certain values having to match each other in order for everything to work properly.
There are two resources available to help you automate these steps.
- The Nomad CLI command
nomad setup vault
can be useful for a quick setup with default values for a development or test cluster. - The
hashicorp-modules/nomad-setup/vault
Terraform module provides a basis for applying these steps with a infrastructure-as-code approach, which is more suitable for a production environment. Thehashicorp-guides/nomad-workload-identity-terraform-demo
repository demonstrates how this module can be used.
You may continue exploring additional integrations between Nomad and Vault or learn how to similarly integrate Nomad and Consul with ACL enabled.