Skip to main content

Hashicorp Consul Refresher - Access Control Lists

Phnom Penh, Cambodia

Configuration

To enable ACLs, add the following ACL parameters to the agent's configuration file and then restart the Consul service. In order for ACL configuration to be applied correctly you will need to apply the same parameters to every server and every client in your datacenter.

nano /etc/consul.d/consul.hcl

I am going to set the default policy to allow for now - so I am not going to have to use ACL tokens before I had a chance to set them up:

acl = {
  enabled = true
  default_policy = "allow"
  enable_token_persistence = true
}

Add those lines to all agents configs and restart the agents:

service consul restart

Create the initial bootstrap token

consul acl bootstrap

AccessorID:       26ec3264-b39b-116f-c215-14fed44c6abc
SecretID:         c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2021-09-08 15:00:23.015534911 +0800 HKT
Policies:         00000000-0000-0000-0000-000000000001 - global-management

The output gives you important information about the token, including the associated policy global-management and SecretID. And trying to use the Consul CLI will now fail - if you don't provide the SecretID token:

consul acl token list
Failed to retrieve the token list: Unexpected response code: 403 (Permission denied)
consul acl token list -token c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865

AccessorID:       00000000-0000-0000-0000-000000000002
SecretID:         anonymous
Description:      Anonymous Token
Local:            false
Create Time:      2021-09-08 14:59:29.508323787 +0800 HKT
Legacy:           false

AccessorID:       26ec3264-b39b-116f-c215-14fed44c6abc
SecretID:         c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2021-09-08 15:00:23.015534911 +0800 HKT
Legacy:           false
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

Adding the Secret Token to your Environment

This might be a security risk - but it is very convenient during development. Adding the SecretID as an environment variable saves you a lot of typing.

HTTP Token

While you are setting up the ACL system, set the CONSUL_HTTP_TOKEN environment variable (SecretID) to the bootstrap token on one server - you can add this to your shell config, e.g. .bashrc, .zshrc, etc.:

nano ~/.zshrc
export CONSUL_HTTP_TOKEN=c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865
source ~/.zshrc

Or write the token into a file:

.zshrc

export CONSUL_HTTP_TOKEN_FILE=/opt/consul_certs/token

Or just use the file inside your Consul command like:

consul acl token list -token-file /opt/token

And login to the Consul UI with the SecretID:

Hashicorp Consul ACL Token

Policies

Policies are reusable sets of rules that token are bound by. They include:

  • ID - Auto-generated public identifier
  • Name - A unique, human-readable name
  • Description - Optional description
  • Rules - Set of rules that grant or deny permissions in Consul
  • __Datacenters - The datacenters this policy is valid for

The Policy Control Levels are:

  • READ
  • WRITE
  • LIST (lists all keys in the Consul k/v store)
  • DENY

Example

key "kv/elasticsearch/elkversion"{
  policy = "write"
}

service "elasticsearch"{
  policy = "read"
}

node "elasticsearch_01"{
  policy = "write"
}
  1. You have permission to read/write to the key kv/elasticsearch/elkversion in the Consul K/V Store.
  2. You only have permission to read all resources related to the service elasticsearch
  3. And read/write permission to everything related to the node server elasticsearch_01

You can also use Wildcards with resource_prefix:

key_prefix "kv/"{
  policy = "read"
}

service_prefix ""{
  policy = "read"
}
  1. Read all keys and all service resources.

ACL Policies CLI and REST API

consul acl policy:

  • create
  • delete
  • list
  • read
  • update

We can now create a policy file nano elasticsearch_policy.hcl:

node "consul-minion" {
  policy = "write"
}

key_prefix "frontend/elasticsearch"{
  policy = "write"
}

sessions ""{
  policy = "write"
}

service "elasticsearch"{
  policy = "write"
}

And use the CLI to register the policy:

consul acl policy create -name "elasticsearch" -description "Elastic Stack Service" -rules @elasticsearch_policy.hcl -token c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865

ID:           fd5a4edd-c1d0-4307-f078-72c4fd1605df
Name:         elasticsearch
Description:  Elastic Stack Service
Datacenters:
Rules:
node "consul-minion" {
  policy = "write"
}

key_prefix "frontend/elasticsearch"{
  policy = "write"
}

sessions ""{
  policy = "write"
}

service "elasticsearch"{
  policy = "write"
}

Or you can use the REST API:

curl -X PUT \
  --header "X-Consul-Token: c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865" \
  --data @elasticsearch_policy.hcl \
  http://192.168.2.110:8500/v1/acl/policy

Alternatively, you can also add/edit policies from the Consul UI:

Hashicorp Consul ACL Token

Creating ACL Tokens

consul acl token:

  • clone
  • create
  • delete
  • list
  • read
  • update

To create a token for the policy fd5a4edd-c1d0-4307-f078-72c4fd1605df created earlier:

consul acl policy list -token c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865

elasticsearch:
   ID:           fd5a4edd-c1d0-4307-f078-72c4fd1605df
   Description:  Elastic Stack Service
   Datacenters:
global-management:
   ID:           00000000-0000-0000-0000-000000000001
   Description:  Builtin Policy that grants unlimited access
   Datacenters:

Run the following command:

consul acl token create -description 'Elastic Stack Service Token' -policy-id fd5a4edd-c1d0-4307-f078-72c4fd1605df  -token c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865

AccessorID:       af3bbd81-5917-5628-5f07-3a40413edaa9
SecretID:         40c6f5ef-c9c7-b098-6046-7fed34772834
Description:      Elastic Stack Service Token
Local:            false
Create Time:      2021-09-11 17:44:38.82495481 +0800 HKT
Policies:
   fd5a4edd-c1d0-4307-f078-72c4fd1605df - elasticsearch

Or you can use the REST API:

curl -X PUT \
  --header "X-Consul-Token: c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865" \
  --data @payload.json \
  http://192.168.2.110:8500/v1/acl/token

With payload.json:

{
  "Description": "Elastic Stack Service Token",
  "Policies": [
    { "ID": "fd5a4edd-c1d0-4307-f078-72c4fd1605df" }
  ]
}

And the token will have been added:

consul acl token list -token c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865

AccessorID:       af3bbd81-5917-5628-5f07-3a40413edaa9
SecretID:         40c6f5ef-c9c7-b098-6046-7fed34772834
Description:      Elastic Stack Service Token
Local:            false
Create Time:      2021-09-11 17:44:38.82495481 +0800 HKT
Legacy:           false
Policies:
   fd5a4edd-c1d0-4307-f078-72c4fd1605df - elasticsearch

AccessorID:       00000000-0000-0000-0000-000000000002
SecretID:         anonymous
Description:      Anonymous Token
Local:            false
Create Time:      2021-09-08 14:59:29.508323787 +0800 HKT
Legacy:           false

AccessorID:       26ec3264-b39b-116f-c215-14fed44c6abc
SecretID:         c7fe7af1-ac0c-e8a8-f527-ba5cf75a3865
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2021-09-08 15:00:23.015534911 +0800 HKT
Legacy:           false
Policies:
   00000000-0000-0000-0000-000000000001 - global-management