sslkuberneteshttpsconsulconsul-kv

Hashicorp Consul - How to do verified TLS from Pods in Kubernetes cluster


I'm having some difficulty understanding Consul end-to-end TLS. For reference, I'm using Consul in Kubernetes (via the hashicorp/consul Helm chart). Only one datacenter and Kubernetes cluster - no external parties or concerns.

I have configured my override values.yaml file like so:

global:
  datacenter: sandbox

  gossipEncryption:
    secretName: "consul"
    secretKey: "CONSUL_GOSSIP_ENCRYPTION_KEY"

  tls:
    enabled: true
    httpsOnly: true
    enableAutoEncrypt: true
    serverAdditionalDNSSANs: ["'consul.service.consul'"]

server:
  replicas: 3
  bootstrapExpect: 3
  storage: 20Gi

dns:
  clusterIP: 172.20.53.53

ui:
  service:
    type: 'LoadBalancer'

syncCatalog:
  enabled: true

All other values are as default from the shipped values.yaml file.

This works, and Consul client logs suggest that all agents area connecting nicely using TLS, with relevant certs and keys being created by (as I understand) the Auto-encryption feature of Consul.

What I don't understand is how to initiate a HTTPS connection from an application on Kubernetes, running in a Pod, to a Consul server. Since the Pod's container does not (presumably) have the Consul root CA cert in its trust store, all HTTPS calls fail, as per wget example below:

# Connect to Pod:
laptop$> kubectl exec -it my-pod sh

# Attempt valid HTTPS connection:
my-pod$> wget -q -O - https://consul.service.consul:8501
Connecting to consul.service.consul:8501 (10.110.1.131:8501)
ssl_client: consul.service.consul: certificate verification failed: unable to get local issuer certificate
wget: error getting response: Connection reset by peer

# Retry, but ignore certificate validity issues:
my-pod$> wget --no-check-certificate -q -O - https://consul.service.consul:8501/v1/status/leader
"10.110.1.131:8300"

How am I supposed to enforce end-to-end (verified) HTTPS connections from my apps on Kubernetes to Consul if the container does not recognize the certificate as valid? Am I misunderstanding something about certificate propagation?

Many thanks - Aaron


Solution

  • Solved with thanks to Hashicorp on their Consul discussion forum.

    global:
      datacenter: sandbox
    
      gossipEncryption:
        secretName: "consul"
        secretKey: "CONSUL_GOSSIP_ENCRYPTION_KEY"
    
      tls:
        enabled: true
        httpsOnly: true
        enableAutoEncrypt: true
        serverAdditionalDNSSANs: ["'consul.service.consul'"]
    
    server:
      replicas: 3
      bootstrapExpect: 3
      storage: 20Gi
    
    dns:
      clusterIP: 172.20.53.53
    
    ui:
      service:
        type: 'LoadBalancer'
    
    syncCatalog:
      enabled: true
    
    
    apiVersion: v1
    kind: Pod
    metadata:
      namespace: default
      name: test-pod
    spec:
      volumes:
      - name: consul-consul-ca-cert
        secret:
          secretName: consul-consul-ca-cert
      hostNetwork: false
      containers:
      - name: consul-test-pod
        image: alpine
        imagePullPolicy: IfNotPresent
        env:
        - name: HOST_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        command: ["/bin/sh"]
        args: ["-c", "while true; do sleep 24h; done"]
        volumeMounts:
        - name: consul-consul-ca-cert
          mountPath: /consul/tls/ca
    
    #> apk update
    #> apk add ca-certificates curl
    
    #> cp /consul/tls/ca/tls.crt /usr/local/share/ca-certificates/consul-server-ca.crt
    #> update-ca-certificates  # might give a trivial warning - ignore it
    
    #> curl https://consul.service.consul:8501/v1/status/leader
    ## No TLS errors ##
    
    #> cd /usr/local/bin
    #> wget https://releases.hashicorp.com/consul-k8s/0.15.0/consul-k8s_0.15.0_linux_amd64.zip  # (or whatever latest version is)
    #> unzip consul-k8s_0.15.0_linux_amd64.zip
    #> rm consul-k8s_0.15.0_linux_amd64.zip
    
    #> consul-k8s get-consul-client-ca -server-addr consul.service.consul -server-port 8501 -output-file /usr/local/share/ca-certificates/consul-client-ca.crt
    #> update-ca-certificates  # might give a trivial warning - ignore it
    
    #> curl https://$HOST_IP:8501/v1/status/leader
    ## No TLS errors ##
    
    #> curl https://$HOST_IP:8501/v1/kv/foo/bar/baz
    ## No TLS errors ##
    

    Naturally, all of the above should be automated by the implementer. These manual steps are purely for demonstration purposes.