[CONSUL][ACL] Using ACL with traefik 2.0 for configuration discovery

Hi,
I am looking to use the KV function of consul to configure traefik.
For security reasons, I have created an ACL that allows the traefik root to read.
I can't configure the token associated to this ACL for traefik.
I found some elements on the traefik V1 doc to use an environment variable "CONSUL_HTTP_TOKEN" but it doesn't seem to work for traefik V2.0

additional information

Traefik version : v2.4.8
Consul : v1.9.5
Kubernetes : v1.19.7
error: level=error msg="KV connection error: field not found,

Thanks for your help

Hi @bvivi57

I'm not familiar with the consul provider but is this the parameter you are looking for?
https://doc.traefik.io/traefik/providers/consul/#rootkey

Hi,
Thanks for your help.

I read this doc, but I tried the login and password option, but it doesn't work. I use consul in its classic version and I don't know if the login and password feature is only possible with the enterprise version. Basically, I only have ACLs and if the documentation of traefik V1 refers to them, it is not the case with 2.

Have you got an example of your consul setup and data?

Hi this is my traefik configuration

apiVersion: apps/v1
kind: DaemonSet
metadata:
 name: dae-traefik-ingress-controller-lan-prd 
 namespace: prd-lan-coolcorp
 labels:
   k8s-app: traefik-ingress-lb-prd-lan
   kubernetes.io/cluster-service: "true"
spec:
 selector:
   matchLabels:
      k8s-app: traefik-ingress-lb-prd-lan
 template:
   metadata:
     namespace: prd-lan-coolcorp
     labels:
       k8s-app: traefik-ingress-lb-prd-lan
       name: traefik-ingress-lb-prd-lan
   spec:
     hostNetwork: true
     dnsPolicy: ClusterFirstWithHostNet
     serviceAccountName: traefik-ingress-controller
     terminationGracePeriodSeconds: 60
     tolerations:
     - key: node-role.kubernetes.io/master
       effect: NoSchedule
     containers:
     - image: traefik:v2.4.8
       name: traefik-ingress-lb-prd-lan
       imagePullPolicy: Always
       volumeMounts:
         - mountPath: "/etc/static_certs"
           name: traefik-certif-ro
         - mountPath: "/etc/traefik/"
           name: traefik-cfg-ro 
         - mountPath: "/etc/dynamic_certs"
           name: traefik-certif-rw  
       resources:
         requests:
           cpu: 100m
           memory: 20Mi
       args:
       - --providers.kubernetescrd
       - --entrypoints.web.address=:80
       - --entrypoints.websecure.address=:443
       - --entrypoints.sftp.address=:2222
       - --entrypoints.velero.address=:8085
       - --entrypoints.nexus-docker-private-registry.address=:5001
       - --entrypoints.nexus-docker-private-registry-groupe.address=:5000
       - --entrypoints.consul-lan.address=:8501
       - --api.dashboard=true
       - --log.level=INFO
       - --providers.file.directory=/etc/traefik/
       - --providers.consul.endpoints=consul-lan-coolcorp-server:8501
       - --providers.consul.tls.insecureSkipVerify=true
       - --serverstransport.insecureskipverify=true
       - --metrics.prometheus=true
       - --metrics.prometheus.addEntryPointsLabels=true
       - --entryPoints.metrics.address=:8082
       - --metrics.prometheus.entryPoint=metrics
       - --tracing=true
       env: 
       - name: CONSUL_HTTP_TOKEN
         value: "5b493dff-0c98-2e33-0d70-7182b42af169"
     nodeSelector:
        node-role.kubernetes.io/worker: ''
        arch: x86
        net: lan
     volumes:
     - name: traefik-cfg-ro
       nfs: 
            path: /volume1/k8s-psv-nfs-rwm/traefik-ingress-controller-lan-prd/traefik-cfg-ro 
            server: storage.coolcorp.priv
            readOnly: true
     - name: traefik-certif-ro
       nfs: 
            path: /volume1/k8s-psv-nfs-rwm/traefik-ingress-controller-lan-prd/traefik-certif-ro 
            server: storage.coolcorp.priv
            readOnly: true
     - name: traefik-certif-rw
       nfs: 
            path: /volume1/k8s-psv-nfs-rwm/traefik-ingress-controller-lan-prd/traefik-certif-rw 
            server: storage.coolcorp.priv          

This my helm config file for consul:

#Configuration globales
#https://learn.hashicorp.com/tutorials/consul/kubernetes-secure-agents
global:
  name: consul-lan-coolcorp
  datacenter: Paris 
  image: consul:1.9.5
  # activation ACL
  acls:
    manageSystemACLs: true
  # activation encryption à partir d'un secret kubernetes
  gossipEncryption:
    secretName: 'sec-consul-gossip'
    secretKey: 'key'
  #activation TLS
  tls:
    enabled: true
    enableAutoEncrypt: true
    verify: true
    #serverAdditionalDNSSANs: ["'api-consul-lan.inf.prd.k8s.coolcorp.priv'","'consul-lan.inf.prd.k8s.coolcorp.priv'","'consul-lan.coolcorp.priv'"]
    serverAdditionalDNSSANs: ["consul-lan.inf.prd.k8s.coolcorp.priv"]
    serverAdditionalIPSANs:  ["192.168.10.45"]
    caCert:
      secretName: "coolcorp-consul-ca-cert"
      secretKey: tls.crt
    caKey:
      secretName: "coolcorp-consul-ca-key"
      secretKey: tls.key
   
# Configuration de la partie server
server:
  # 3 serveur réplicé
  replicas: 3
  storage: 10Gi
  nodeSelector: |
    node-role.kubernetes.io/worker: ''
    arch: x86
    net: lan
  service:
    type: ClusterIP  

client:
  enabled: false

dns:
  enabled: false  

# Enable and configure the Consul UI.
ui:
  enabled: true
  service:
    type: ClusterIP

To try to understand, I added in the consul "anonymous-token-policy" the possibility to read the traefik branch.

  key_prefix "" {
    policy = "read"
  }
  node_prefix "" {
     policy = "read"
  }
  service_prefix "" {
     policy = "read"
  }

I have launched a test container to test with a curl command:

curl -k https://consul-lan-coolcorp-server:8501/v1/kv/traefik

The command works and I manage to browse the traefik tree.

But under traefik, I still get the error :

level=error msg="KV connection error: field not found, node: , retrying in 8.840552292s" providerName=consul

I've not use the KV provider before. But I think I managed to replicate?

I got it working first try then I tried to break it by removing the root. It was okay. It updated.

I then recreated the KV(using the consul UI). But this time instead of creating the key http/services/whoami/loadbalancer/servers/0/url I created a 'folder' http/services/whoami/ I then got the:

{"level":"error","msg":"KV connection error: field not found, node: , retrying in 2.847896791s","providerName":"consul","time":"2021-04-29T16:59:10Z"}

Looking at the KV tree it looks like the provider does not handle a null value in the service name. It might be a similar issue with yours.

I could reproduce this in the routers tree also.

erroring KV tree
curl -sq localhost:8500/v1/kv/traefik?recurse=true | jq '.[] | {key: .Key, value: .Value|@base64d}'
{
  "key": "traefik/",
  "value": "��"
}
{
  "key": "traefik/http/routers/kv/rule",
  "value": "PathPrefix(`/whoami`)"
}
{
  "key": "traefik/http/routers/kv/service",
  "value": "whoami"
}
{
  "key": "traefik/http/services/",
  "value": "��"
}
{
  "key": "traefik/http/services/whoami/",
  "value": "��"
}
{
  "key": "traefik/http/services/whoami/loadbalancer/servers/0/url",
  "value": "http://172.21.0.2"
}

OK KV tree
curl -sq localhost:8500/v1/kv/traefik?recurse=true | jq '.[] | {key: .Key, value: .Value|@base64d}'
   {
     "key": "traefik/",
     "value": "��"
   }
   {
     "key": "traefik/http/routers/kv/rule",
     "value": "PathPrefix(`/whoami`)"
   }
   {
     "key": "traefik/http/routers/kv/service",
     "value": "whoami"
   }
   {
     "key": "traefik/http/services/whoami/loadbalancer/servers/0/url",
     "value": "http://172.21.0.2"
   }

Looks like it works with v2 as removing the ACL from Anonymous token and applying it to a new token it works.

I think rookey is a bit of a misnomer. I think the rootkey is the root key for all of the traefik config within consul. for example if rootkey=traefik, then all of the consul kv keys will begin with traefik/

Correct, it is the base of the tree.