I've been happily using treafik on a self-hosted docker swarm for a couple of years.
I had it configured to take care of SSL certificates via DNS challenge, and a wildcard worked fine for my domain, having only to specify the hostname I wanted on my container labels.
I'm now moving to Kubernetes (k3s) for several reasons, and I was happy to see I can use Traefik as an ingress controller, so I proceeded to configure it as I used it so far, with a wildcard certificate automatically obtained from let's encrypt.
checking the "acme-cloudflare.json" file the certificate is obtained and valid, yet whenever I try to curl (or open in a browser) one of the hosted services, treafik serves a self-signed certificate.
I've been banking my head on this for a couple of days but I don't understand why. I'm not a "Kubernetes ninja master" by any means, but I can make my way around, and that's probably not helping despite my strong computer science base and decades of experience.
Right now I'm a bit lost, and I'd appreciate if someone can perhaps point me in the right direction, or perhaps point out my mistakes so I can fix my issue.
Here are the part of my config that have to do with SSL:
additionalArguments:
- '--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare'
- '--certificatesresolvers.cloudflare.acme.email=my@email.address'
- '--certificatesresolvers.cloudflare.acme.dnschallenge.resolvers=1.1.1.1'
- '--certificatesresolvers.cloudflare.acme.storage=/ssl-certs/acme-cloudflare.json'
deployment:
initContainers:
- command:
- sh
- '-c'
- 'touch /ssl-certs/acme-cloudflare.json; chown 65532 /ssl-certs/acme-cloudflare.json; chmod -v 600 /ssl-certs/acme-cloudflare.json'
image: busybox:1.36.1
name: volume-permissions
volumeMounts:
- mountPath: /ssl-certs
name: ssl-certs
kind: Deployment
env:
- name: CF_DNS_API_TOKEN
valueFrom:
secretKeyRef:
key: apiKey
name: cloudflare-credentials
- name: CF_ZONE_API_TOKEN
valueFrom:
secretKeyRef:
key: apiKey
name: cloudflare-credentials
ingressClass:
enabled: true
isDefaultClass: true
name: ''
ingressRoute:
dashboard:
enabled: true
entryPoints:
- web
- websecure
matchRule: Host(`proxy.kube.mydomain.com`) || Host(`proxy.mydomain.com`)
services:
- kind: TraefikService
name: api@internal
tls:
certResolver: cloudflare
persistence:
accessMode: ReadWriteOnce
enabled: true
name: ssl-certs
path: /ssl-certs
size: 1Gi
ports:
web:
expose:
default: true
exposedPort: 80
forwardedHeaders:
insecure: true
trustedIPs:
- 0.0.0.0/0
port: 8000
protocol: TCP
proxyProtocol:
insecure: true
trustedIPs:
- 0.0.0.0/0
redirectTo:
port: websecure
websecure:
allowACMEByPass: false
expose:
default: true
exposedPort: 443
forwardedHeaders:
insecure: true
trustedIPs:
- 0.0.0.0/0
tls:
certResolver: cloudflare
domains:
- main: mydomain.com
sans:
- '*.mydomain.com'
enabled: true
providers:
kubernetesCRD:
allowCrossNamespace: true
allowEmptyServices: true
allowExternalNameServices: true
enabled: true
nativeLBByDefault: false
kubernetesGateway:
enabled: false
kubernetesIngress:
allowEmptyServices: true
allowExternalNameServices: true
service:
enabled: true
single: true
type: LoadBalancer
I included this:
ingressRoute:
dashboard:
enabled: true
entryPoints:
- web
- websecure
matchRule: Host(`proxy.kube.mydomain.com`) || Host(`proxy.mydomain.com`)
services:
- kind: TraefikService
name: api@internal
tls:
certResolver: cloudflare
for sake of example (I will protect access to the dashboard with authentic, once the SSL problem is gone):
➜ rancher git:(main) ✗ curl https://proxy.kube.mydomain.com/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
This is minor, but another thing that is a bit confusing to me is why I need to fill my certificate resolver in this way:
additionalArguments:
- '--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare'
- '--certificatesresolvers.cloudflare.acme.email=my@email.address'
- '--certificatesresolvers.cloudflare.acme.dnschallenge.resolvers=1.1.1.1'
- '--certificatesresolvers.cloudflare.acme.storage=/ssl-certs/acme-cloudflare.json'
instead of the usual:
certificatesResolvers:
cloudflare:
acme:
email: my@email.address
storage: /ssl-certs/acme-cloudflare.json
dnschallenge:
provider: cloudflare
resolvers: 1.1.1.1
or the helm installation just hangs forever