Configure Consul Access Control Lists.

Inspect current server configuration.

$ sudo -u consul cat /etc/consul.d/consul.hcl
# datacenter
datacenter = "dc-lab-1"

# data directory
data_dir = "/opt/consul"

# server mode
server = true

# bind address
bind_addr = "0.0.0.0"

# single-node server
bootstrap = true

# number of expected servers in the datacenter
#bootstrap_expect = 3

# servers in the datacenter
#retry_join = ["172.16.151.117", "172.16.151.118", "172.16.151.119"]

# logging
log_level = "info"
log_file = "/var/log/consul/"
log_rotate_duration = "24h"
log_rotate_max_files = 30

# encrypt gossip protocol
encrypt = "AcHUV+z4kLDJiQeVqLAh2sG25SH4K4WYU6oIru29lSM="

# tls encryption
tls {
  defaults{
    verify_incoming = true
    verify_outgoing = true
    ca_file = "/opt/consul/ssl/consul-agent-ca.pem"
    cert_file = "/opt/consul/ssl/dc-lab-1-server-consul-0.pem"
    key_file = "/opt/consul/ssl/dc-lab-1-server-consul-0-key.pem"
  }
}

# Auto-Encrypt-TLS
auto_encrypt {
  allow_tls = true
}

Enable access control lists, but do not block anything at this moment.

$ sudo -u consul tee /etc/consul.d/acl.hcl << EOF
# acl
acl = {
  enabled = true
  default_policy = "allow"
  enable_token_persistence = true
  tokens {
    default = ""
  }
}
EOF

Validate configuration.

$ sudo -u consul consul validate /etc/consul.d
skipping file /etc/consul.d/consul.env, extension must be .hcl or .json, or config format must be set
bootstrap = true: do not enable unless necessary
Configuration is valid!

Restart consul service.

$ sudo systemctl restart consul

Bootstrap Consul’s ACL system.

$ consul acl bootstrap
AccessorID:       c52986b0-8e88-c500-dcfc-8a83bb283319
SecretID:         7b97f249-c6a3-d1bd-aa58-9ed45a548970
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2022-07-15 10:21:43.395811397 +0000 UTC
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

Export global-management token.

$ export CONSUL_TOKEN=7b97f249-c6a3-d1bd-aa58-9ed45a548970

List defined policies.

$ consul acl policy list
global-management:
   ID:           00000000-0000-0000-0000-000000000001
   Description:  Builtin Policy that grants unlimited access
   Datacenters:  

Write down policy for mgmt node, so it can read acl definitions, manage itself, display information about other nodes and consul service.

$ cat > mgmt-policy.hcl << EOF
acl = "read"

node "mgmt" {
  policy = "write"
}

node_prefix "" {
  policy = "read"
}


service "consul" {
  policy = "read"
}
EOF

Define mgmt node policy.

$ consul acl policy create -name "mgmt-policy" -description "mgmt node policy" -rules @mgmt-policy.hcl
ID:           6ba78a2d-6877-a352-6228-4f0602eac1b8
Name:         mgmt-policy
Description:  mgmt node policy
Datacenters:  
Rules:
acl = "read"

node "mgmt" {
  policy = "write"
}

node_prefix "" {
  policy = "read"
}

service "consul" {
  policy = "read"
}

List policies.

$ consul acl policy list
global-management:
   ID:           00000000-0000-0000-0000-000000000001
   Description:  Builtin Policy that grants unlimited access
   Datacenters:  
mgmt-policy:
   ID:           6ba78a2d-6877-a352-6228-4f0602eac1b8
   Description:  mgmt node policy
   Datacenters: 

Display specific policy.

$ consul acl policy read -name mgmt-policy
ID:           6ba78a2d-6877-a352-6228-4f0602eac1b8
Name:         mgmt-policy
Description:  mgmt node policy
Datacenters:  
Rules:
acl = "read"

node "mgmt" {
  policy = "write"
}

node_prefix "" {
  policy = "read"
}

service "consul" {
  policy = "read"
}

List tokens.

$ consul acl token list
AccessorID:       c52986b0-8e88-c500-dcfc-8a83bb283319
SecretID:         7b97f249-c6a3-d1bd-aa58-9ed45a548970
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2022-07-15 10:21:43.395811397 +0000 UTC
Legacy:           false
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

AccessorID:       00000000-0000-0000-0000-000000000002
SecretID:         anonymous
Description:      Anonymous Token
Local:            false
Create Time:      2022-07-15 10:21:27.372305034 +0000 UTC
Legacy:           false

Clone bootstrap token if you want to gain full access inside web-ui, just to know that you can clone tokens.

$ consul acl token clone -id c52986b0-8e88-c500-dcfc-8a83bb283319 -description "user global-management token" 
AccessorID:       b462abdd-4255-8dcd-310c-4baf964b7bc7
SecretID:         68a6352d-7b15-90c5-4176-8c42da4dbc9e
Description:      user global-management token
Local:            false
Create Time:      2022-07-16 15:53:43.340385559 +0000 UTC
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

Create token for mgmt node.

$ consul acl token create -description "mgmt node token" -policy-name "mgmt-policy"
AccessorID:       788f2947-d26e-2c41-55de-f1f2ede5ae46
SecretID:         9b220a8e-80d0-47bf-04dd-e547cc88c83c
Description:      mgmt node token
Local:            false
Create Time:      2022-07-16 15:59:06.04181954 +0000 UTC
Policies:
   6ba78a2d-6877-a352-6228-4f0602eac1b8 - mgmt-policy

List tokens.

$ consul acl token list
AccessorID:       b462abdd-4255-8dcd-310c-4baf964b7bc7
SecretID:         68a6352d-7b15-90c5-4176-8c42da4dbc9e
Description:      user global-management token
Local:            false
Create Time:      2022-07-16 15:53:43.340385559 +0000 UTC
Legacy:           false
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

AccessorID:       c52986b0-8e88-c500-dcfc-8a83bb283319
SecretID:         7b97f249-c6a3-d1bd-aa58-9ed45a548970
Description:      Bootstrap Token (Global Management)
Local:            false
Create Time:      2022-07-15 10:21:43.395811397 +0000 UTC
Legacy:           false
Policies:
   00000000-0000-0000-0000-000000000001 - global-management

AccessorID:       788f2947-d26e-2c41-55de-f1f2ede5ae46
SecretID:         9b220a8e-80d0-47bf-04dd-e547cc88c83c
Description:      mgmt node token
Local:            false
Create Time:      2022-07-16 15:59:06.04181954 +0000 UTC
Legacy:           false
Policies:
   6ba78a2d-6877-a352-6228-4f0602eac1b8 - mgmt-policy

AccessorID:       00000000-0000-0000-0000-000000000002
SecretID:         anonymous
Description:      Anonymous Token
Local:            false
Create Time:      2022-07-15 10:21:27.372305034 +0000 UTC
Legacy:           false

Create a access contol list definition on an agent.

$ sudo -u consul tee /etc/consul.d/acl.hcl << EOF
# acl
acl = {
  enabled = true
  default_policy = "deny"
  enable_token_persistence = true
  tokens {
    default = "9b220a8e-80d0-47bf-04dd-e547cc88c83c"
  }
}
EOF

Restart consul service on agent.

$ sudo systemctl restart consul

Alter default policy on server nodes and use global management token.

$ sudo -u consul tee /etc/consul.d/acl.hcl << EOF
# acl
acl = {
  enabled = true
  default_policy = "deny"
  enable_token_persistence = true
  tokens {
    default = "7b97f249-c6a3-d1bd-aa58-9ed45a548970"
  }
}
EOF

Restart consul service on server.

$ sudo systemctl restart consul

Inspect nodes and service visibility on mgmt node (agent).

$ consul catalog nodes
Node   ID        Address         DC
jammy  1c49ba0a  172.16.151.111  dc-lab-1
mgmt   54fa23de  172.16.151.120  dc-lab-1
$ consul catalog services
consul

Additional notes

You can use the same token/policy on a group of the same backend servers, but this should be obvious from the previous example.

$ cat > nginx-backend-policy.hcl << EOF
acl = "read"

node_prefix "nginx-backend-" {
  policy = "write"
}

service "nginx-backend" {
  policy = "write"
}
EOF