Nomad
ACL Policy Specification
The Secure Nomad with Access Control guide includes step-by-step instructions for bootstrapping Nomad's Access Control List (ACL) system, authoring policies, and granting policies. This document is a detailed reference of the expected policy structure and available options.
ACL policies are written using HashiCorp Configuration Language (HCL). The HCL interpreter can also parse JSON to facilitate machine-generated configuration. A detailed syntax specification for HCL can be found at HCL Native Syntax Specification.
All content of an ACL policy is case-sensitive.
An ACL policy contains one or more rules. Each rule block contains a
combination of policy
and capabilities
fields. The specific values permitted
are described for each rule definition below. An example structure of an ACL
policy is as follows:
# this is a namespace rule for the "foo" namespace
namespace "foo" {
policy = "write" # this is a policy field
capabilities = ["alloc-exec"] # this is a capabilities list
# this block controls access to variables in this namespace
variables {
path "project/*" {
capabilities = ["read", "write"]
}
}
}
# this is a namespace rule, with a wildcard label
namespace "*" {
policy = "read"
}
node {
policy = "read"
}
agent {
policy = "read"
}
operator {
policy = "read"
}
quota {
policy = "read"
}
# this is a host_volume rule, with a wildcard label
host_volume "*" {
policy = "read"
}
plugin {
policy = "read"
}
Namespace Rules
Namespace rules are defined with a namespace
block. An ACL policy can include
zero, one, or more namespace rules.
Namespace rules control access to APIs in Nomad that are namespaced: Jobs, Allocations, Deployments, Evaluations, Recommendations, Scaling Policies, Services, and CSI Volumes. Namespace rules also filter items related to the above APIs from the Event Stream and Search APIs.
Each namespace rule is labeled with the namespace name it applies to. If no
namespace label is specified, the rule will apply to the "default"
namespace. You may use wildcard globs ("*"
) in the namespace label, to apply a
rule to multiple namespaces.
Only one namespace rule can apply. When Nomad checks an action against the ACL Policy, the namespace rule is selected by first checking for an exact match, before falling back to a glob-based lookup. When looking up the namespace by glob, Nomad chooses the rule with the greatest number of matched characters. In other words, Nomad chooses the rule with the smallest character difference, which is the greatest number of matched characters.
In this example, you have a 'production-web' namespace. For the "*-web"
rule,
nine characters match. The character difference is four. For the "*"
rule, no
characters match the rule. The character difference is thirteen. Nomad chooses
the "*-web"
rule since it has the greatest number of matched characters.
namespace "*-web" {
policy = "deny"
}
namespace "*" {
policy = "write"
}
Each namespace rule can include a coarse-grained policy
field, a fine-grained
capabilities
field, a variables
block, or all three.
The policy
field for namespace rules can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
In addition to the coarse-grained policy
, you can provide a fine-grained list
of capabilities
. This includes:
deny
- When multiple policies are associated with a token, deny will take precedence and prevent any capabilities.list-jobs
- Allows listing the jobs and seeing coarse grain status. This implicitly grantscsi-list-volume
.parse-job
- Allows parsing a job from HCL to JSON.read-job
- Allows inspecting a job and seeing fine grain status. This implicitly grantscsi-read-volume
.submit-job
- Allows jobs to be submitted, updated, or stopped.dispatch-job
- Allows jobs to be dispatchedread-logs
- Allows the logs associated with a job to be viewed.read-fs
- Allows the filesystem of allocations associated to be viewed. Implicitly grantsread-logs
.alloc-exec
- Allows an operator to connect and run commands in running allocations.alloc-node-exec
- Allows an operator to connect and run commands in allocations running without filesystem isolation, for example, raw_exec jobs.alloc-lifecycle
- Allows an operator to stop individual allocations manually.csi-register-plugin
- Allows jobs to be submitted that register themselves as CSI plugins.csi-write-volume
- Allows CSI volumes to be registered or deregistered. This implicitly grantscsi-read-volume
.csi-read-volume
- Allows inspecting a CSI volume, seeing fine grain status, and listing external volumes and snapshots. This implicitly grantscsi-list-volume
.csi-list-volume
- Allows listing CSI volumes, seeing coarse grain status, and listing external volumes and snapshots.csi-mount-volume
- Allows jobs to be submitted that claim a CSI volume. This implicitly grantscsi-read-volume
.list-scaling-policies
- Allows listing scaling policies.read-scaling-policy
- Allows inspecting a scaling policy.read-job-scaling
- Allows inspecting the current scaling of a job.scale-job
: Allows scaling a job up or down.sentinel-override
- Allows soft mandatory policies to be overridden.submit-recommendation
- Allows submitting vertical job scaling recommendations.
The coarse-grained policy permissions are shorthand for the following fine- grained namespace capabilities:
Policy | Capabilities |
---|---|
deny | deny |
read | list-jobs parse-job read-job csi-list-volume csi-read-volume list-scaling-policies read-scaling-policy read-job-scaling |
write | list-jobs parse-job read-job submit-job dispatch-job read-logs read-fs alloc-exec alloc-lifecycle csi-write-volume csi-mount-volume list-scaling-policies read-scaling-policy read-job-scaling scale-job submit-recommendation |
scale | list-scaling-policies read-scaling-policy read-job-scaling scale-job |
If you provide both a policy
and capabilities
list, the capabilities are
merged. For example, the policy below adds the submit-job
capability to the read
policy disposition, which provides the list-job
and read-job
capabilities:
# Allow reading jobs and submitting jobs, without allowing access
# to view log output or inspect the filesystem
namespace "default" {
policy = "read"
capabilities = ["submit-job"]
}
A similar policy could also be expressed as:
# Allow reading jobs and submitting jobs, without allowing access
# to view log output or inspect the filesystem
namespace "default" {
capabilities = ["submit-job","list-jobs","read-job"]
}
Variables
The variables
block in the namespace
rule controls access to
Variables. The variables block is optional, but you can specify only one
variables block per namespace rule.
A variables
block includes one or more path
blocks. Each path
block is
labeled with the path it applies to. You may use wildcard globs ("*"
) in the
path label, to apply the block to multiple paths in the namespace. Note that
variable paths never start with a leading /
, so Nomad will return an error if
you submit a policy that has such a path.
Each path has a list of capabilities
. The available capabilities for Variables
are as follows:
Capability | Notes |
---|---|
write | Create or update Variables at this path. Includes the "list" capability but not the "read" or "destroy" capabilities. |
read | Read the decrypted contents of Variables at this path. Also includes the "list" capability |
list | List the metadata but not contents of Variables at this path. |
destroy | Delete Variables at this path. |
deny | No permissions at this path. Deny takes precedence over other capabilities. |
For example, the policy below allows full access to variables at all paths in the "dev" namespace that are prefixed with "project/", but only read access to paths prefixed with "system/". Note that the glob can match an empty string but all other characters are strictly matched. This policy grants read access to paths prefixed with "system/" but not a path named "system" (without a trailing slash). This policy does not grant any other coarse-grained policy or fine-grained capabilities.
namespace "dev" {
variables {
# full access to secrets in all "project" paths
path "project/*" {
capabilities = ["write", "read", "destroy", "list"]
}
# read/list access within a "system/" path belonging to administrators
path "system/*" {
capabilities = ["read"]
}
}
}
Node rules
The node
rule controls access to the Node API such as listing
nodes or triggering a node drain. The node rule is optional, but you can specify
only one node rule per ACL Policy.
node {
policy = "read"
}
The policy
field for the node rule can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
Node Pools rules
Node pool rules are defined with a node_pool
block. An ACL policy can
include zero, one, or more node pool rules.
Node pool rule controls access to the Node Pools API such as create, update, and list node pools.
Each node pool rule is labeled with the node pool name it applies to. You may
use wildcard globs ("*"
) in the label to apply a rule to multiple node pools.
Similarly to namespace rules only one node_pool
rule can
be applied. First an exact match is tried before falling back to a glob-based
lookup, where the rule with the greatest number of matched characters is
chosen.
Each node pool rule can include a coarse-grained policy
field and a
fine-grained capabilities
field.
The policy
field for node pool rules can have one of the following values.
read
allows node pools to be listed and read but not modified.write
allows node pools to be read, create, updated, and deleted.deny
forbids node pools to be read or modified. Deny takes precedence when multiple policies are associated with a token.
In addition to the coarse-grained policy
, you can provide a fine-grained list
of capabilities
.
deny
forbids node pools to be read or modified. Deny takes precedence when multiple policies are associated with a token.delete
allows node pools to be deleted.read
allows node pools to be listed and read.write
allows node pools to be created and updated.
The coarse-grained policy permissions are shorthand for the following fine-grained capabilities.
Policy | Capabilities |
---|---|
deny | deny |
read | read |
write | delete , read , write |
If you provide both a policy
and capabilities
list the capabilities are
merged. For example, the policy below adds the write
capability to the read
policy, thus allowing read
and write
permission but no delete
.
node_pool "dev-*" {
policy = "read"
capabilities = ["write"]
}
Agent rules
The agent
rule controls access to the Agent API such as join and
leave. The agent rule is optional, but you can specify only one agent rule per
ACL Policy.
agent {
policy = "read"
}
The policy
field for the agent rule can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
Operator rules
The operator
rule controls access to the Operator API such
raft or scheduler configuration. The operator rule is optional, but you can
specify only one operator rule per ACL Policy.
operator {
policy = "read"
}
The policy
field for the operator rule can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
In the example above, the token could be used to query the operator endpoints for diagnostic purposes but not make any changes.
Quota rules
The quota
rule controls access to the Quota API such as quota
creation and deletion. The quota rule is optional, but you can specify only one
quota rule per ACL Policy.
quota {
policy = "read"
}
The policy
field for the quota rule can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
Host Volume rules
The host_volume
rule controls access to mounting and accessing host
volumes. An ACL Policy can include zero, one, or more host volume
rules.
host_volume "*" {
policy = "write"
}
host_volume "prod-*" {
policy = "deny"
}
host_volume "prod-ca-certificates" {
policy = "read"
}
Host volume rules are labeled with the volume names that they apply to. As with namespaces, you may use wildcards to reuse the same configuration across a set of volumes.
The policy
field for host volume rules can have one of the following values:
read
: allow the resource to be read but not modifiedwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
In addition to the coarse grained policy, host volume rules can include a list
of fine-grained capabilities
. These include:
deny
- Do not allow a user to mount a volume in any way.mount-readonly
- Only allow the user to mount the volume asreadonly
mount-readwrite
- Allow the user to mount the volume asreadonly
orreadwrite
if thehost_volume
configuration allows it.
The coarse-grained policy permissions are shorthand for the fine grained capabilities:
Policy | Capabilities |
---|---|
deny | deny |
read | mount-readonly |
write | mount-readonly mount-readwrite |
When both the policy short hand and a capabilities list are provided, the capabilities are merged.
Note: Host Volume policies are applied when attempting to use a volume.
Regardless of this configuration, users with access to the Node API will be able
to list available volumes using the nomad node status
command or API call. .
Plugin rules
The plugin
rule controls access to CSI plugins, such as listing
plugins or getting plugin status. The plugin rule is optional, but you can
specify only one plugin rule per ACL policy.
plugin {
policy = "read"
}
The policy
field for the plugin rule can have one of the following values:
read
: allow the resource to be read but not modifiedlist
: allow the resource to be listed, but not inspected in detailwrite
: allow the resource to be read and modifieddeny
: do not allow the resource to be read or modified. Deny takes precedence when multiple policies are associated with a token.
Configuring ACLs for the web UI
The Nomad web UI uses the API endpoints /v1/agent
and /v1/node
for nearly
every page. ACL policies for users who will use the Nomad UI should include the
following rules.
node {
policy = "read"
}
agent {
policy = "read"
}
Additionally, ACL policies for users who can read jobs that mount CSI volumes should include the following rules.
plugin {
policy = "read"
}