Been trying to force to set the minimum TLS version in Traefik using labels or CLI option on docker-compose.
There is a post from September that says it's not possible:
I have been doing some research on how to disable tls v1.0 and v1.1 on Traefik. I found the configuration in the dynamic file, but how would I translate this to docker compose file? Or even better, what command would I run to disable it globally?
I searched the docker reference file, and could not find the option:
But then I find a 2 years old (solved) issue:
Ability to set ciphersuites and MinTLSVersion by CLI · Issue #3103 · traefik/traefik · GitHub and its PR Support TLS MinVersion and CipherSuite as CLI option. by ldez · Pull Request #3107 · traefik/traefik · GitHub
My config:
version: "3.8"
services:
traefik:
image: "traefik:v2.3.4"
container_name: "traefik"
command:
- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.route53.acme.dnschallenge=true"
- "--certificatesresolvers.route53.acme.dnschallenge.provider=route53"
- "--certificatesresolvers.route53.acme.email=${EMAIL}"
- "--certificatesresolvers.route53.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
environment:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- AWS_HOSTED_ZONE_ID=${AWS_HOSTED_ZONE_ID}
labels:
traefik.enable: true
traefik.http.routers.traefik.rule: Host(`traefik.${DOMAIN}`)
traefik.http.routers.traefik.tls.certresolver: route53
traefik.http.routers.traefik.entrypoints: websecure
traefik.http.services.traefik.loadbalancer.server.port: 8080
[...]
Tried:
- "--entrypoints.websecure.address=:443 TLS TLS.MinVersion:VersionTLS11"
- "--entrypoints.websecure.http.tls.options.default.MinVersion=VersionTLS13"
- "--entrypoints='Name:websecure TLS TLS:MinVersion:VersionTLS13'"
Testing was done with testssl.sh.
Hello, I do have a solution for you. I had similar issues for setting up TLS. See my site for a full breakdown. Hope it helps.
https://www.djpic.net/articles/traefik-v2-secure-tls-and-header-configuration-with-docker-provider/
kit
September 3, 2021, 3:34pm
3
I've been working with Traefik for a few weeks, tinkering here and there trying to get it all working how I want it. The only piece I can't get to work at all is the minimum TLS options in Docker Compose. I've looked over your examples @webmastadj but I can't seem to get it. Clearly something wrong with my configuration elsewhere.
Hopefully someone will be able to point out where I've made a rookie mistake.
docker-compose.yml
version: "3.7"
networks:
default:
driver: bridge
socket_proxy:
name: socket_proxy
driver: bridge
traefik_proxy:
name: traefik_proxy
driver: bridge
services:
# Including socket-proxy as it is a dependency in this example.
socket-proxy:
image: docker.io/tecnativa/docker-socket-proxy:latest
container_name: socket-proxy
restart: unless-stopped
privileged: true
ports:
- "127.0.0.1:2375:2375/tcp"
networks:
- socket_proxy
environment:
LOG_LEVEL: info
EVENTS: 1
PING: 1
VERSION: 1
AUTH: 0
SECRETS: 0
POST: 0
BUILD: 0
COMMIT: 0
CONFIGS: 0
CONTAINERS: 1
DISTRIBUTION: 0
EXEC: 0
IMAGES: 1
INFO: 0
NETWORKS: 0
NODES: 0
PLUGINS: 0
SERVICES: 0
SESSION: 0
SWARM: 0
SYSTEM: 0
TASKS: 0
VOLUMES: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock
reverse-proxy:
build:
context: ./containers/traefik
dockerfile: Dockerfile
image: docker.io/custom-traefik:2.5.1
container_name: traefik
ports:
- "80:80/tcp"
- "443:443/tcp"
networks:
- traefik_proxy
- socket_proxy
environment:
CLOUDFLARE_EMAIL: ${CLOUDFLARE_EMAIL}
CLOUDFLARE_DNS_API_TOKEN: ${CLOUDFLARE_DNS_API_TOKEN}
CLOUDFLARE_ZONE_API_TOKEN: ${CLOUDFLARE_ZONE_API_TOKEN}
TRAEFIK_ACCESSLOG: "true"
TRAEFIK_ACCESSLOG_BUFFERINGSIZE: 100
TRAEFIK_ACCESSLOG_FILEPATH: /access.log
TRAEFIK_ACCESSLOG_FILTERS_STATUSCODES: 400-499
TRAEFIK_ACCESSLOG_FORMAT: common
TRAEFIK_API: "true"
TRAEFIK_API_DASHBOARD: "true"
TRAEFIK_API_DEBUG: "true"
TRAEFIK_API_INSECURE: "false"
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE: "true"
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_CASERVER: ${TRAEFIK_CASERVER}
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_EMAIL: ${TRAEFIK_EMAIL}
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_KEYTYPE: RSA4096
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_STORAGE: /acme.json
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_DNSCHALLENGE: "true"
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_DNSCHALLENGE_DELAYBEFORECHECK: 0
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_DNSCHALLENGE_PROVIDER: cloudflare
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_DNSCHALLENGE_RESOLVERS: 1.1.1.1:53,1.0.0.1:53
TRAEFIK_ENTRYPOINTS_HTTP_ADDRESS: ":80"
TRAEFIK_ENTRYPOINTS_HTTPS_ADDRESS: ":443"
TRAEFIK_ENTRYPOINTS_HTTPS_HTTP_TLS: "true"
TRAEFIK_ENTRYPOINTS_HTTPS_HTTP_TLS_CERTRESOLVER: cloudflare
TRAEFIK_ENTRYPOINTS_HTTPS_HTTP_TLS_DOMAINS_0_MAIN: ${BASE_DOMAIN}
TRAEFIK_ENTRYPOINTS_HTTPS_HTTP_TLS_DOMAINS_0_SANS: "*.${BASE_DOMAIN}"
TRAEFIK_GLOBAL_CHECKNEWVERSION: "false"
TRAEFIK_GLOBAL_SENDANONYMOUSUSAGE: "false"
TRAEFIK_LOG: "true"
TRAEFIK_LOG_FORMAT: common
TRAEFIK_LOG_LEVEL: DEBUG
TRAEFIK_PILOT_DASHBOARD: "false"
TRAEFIK_PING: "true"
TRAEFIK_PING_MANUALROUTING: "true"
TRAEFIK_PROVIDERS_DOCKER: "true"
TRAEFIK_PROVIDERS_DOCKER_ENDPOINT: tcp://socket-proxy:2375
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"
TRAEFIK_PROVIDERS_DOCKER_NETWORK: traefik_proxy
TRAEFIK_PROVIDERS_DOCKER_SWARMMODE: "false"
TRAEFIK_PROVIDERS_DOCKER_WATCH: "true"
TRAEFIK_PROVIDERS_FILE_DEBUGLOGGENERATEDTEMPLATE: "false"
TRAEFIK_PROVIDERS_FILE_DIRECTORY: /config
TRAEFIK_PROVIDERS_FILE_WATCH: "true"
labels:
traefik.enable: "true"
traefik.docker.network: traefik_proxy
# Redirect
traefik.http.routers.http-catch-all.entrypoints: http
traefik.http.routers.http-catch-all.rule: HostRegexp(`{host:.+}`)
traefik.http.routers.http-catch-all.middlewares: https-redirect@file
traefik.http.routers.http-catch-all.service: reverse-proxy@docker
traefik.http.services.reverse-proxy.loadbalancer.server.port: 80
# Routers
traefik.http.routers.api.entrypoints: https
traefik.http.routers.api.middlewares: basic-auth@docker
traefik.http.routers.api.rule: Host(`traefik.${BASE_DOMAIN}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
traefik.http.routers.api.service: api@internal
traefik.http.routers.api.tls.certresolver: cloudflare
traefik.http.routers.ping.entrypoints: https
traefik.http.routers.ping.rule: Host(`traefik.${BASE_DOMAIN}`) && PathPrefix(`/ping`)
traefik.http.routers.ping.service: ping@internal
traefik.http.routers.ping.tls.certresolver: cloudflare
# Middleware
traefik.http.middlewares.basic-auth.basicauth.users: ${TRAEFIK_DASHBOARD_ADMIN}
volumes:
- ./config/traefik/file:/config
- ./log/traefik/access.log:/access.log
depends_on:
- socket-proxy
I'm on Windows, so the Traefik image is a minor customization of the default to add an acme.json
Dockerfile
FROM docker.io/traefik:2.5.1
RUN touch /acme.json && chmod 0600 /acme.json
And finally my File Provider configurations
http:
middlewares:
# HTTPS Scheme redirect
https-redirect:
redirectScheme:
scheme: https
# Enabled Secure headers
secure-headers:
headers:
sslRedirect: true
frameDeny: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 63072000
contentTypeNosniff: true
accessControlAllowMethods:
- GET
- POST
accessControlMaxAge: 100
addVaryheader: true
contentSecurityPolicy: script-src 'self'
referrerPolicy: origin-when-cross-origin
# Semi Secure Headers to allow custom contentSecurityPolicy
semi-secure-headers:
headers:
sslRedirect: true
frameDeny: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 63072000
contentTypeNosniff: true
accessControlAllowMethods:
- GET
- POST
accessControlMaxAge: 100
addVaryheader: true
referrerPolicy: origin-when-cross-origin
# Allow compressed content
compress-content:
compress: {}
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
# Recommended ciphers for TLSv1.2
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
# Recommended ciphers for TLSv1.3
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
tlsv13only:
minVersion: VersionTLS13
I know that the File Provider is being consumed, as the extra middleware defined within is showing in the Dashboard. No matter how I reference the TLS options, however, I'm still getting results back from sslyze
showing
* TLS 1.1 Cipher Suites:
Attempted to connect using 80 cipher suites.
The server accepted the following 2 cipher suites:
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 256 ECDH: prime256v1 (256 bits)
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 128 ECDH: prime256v1 (256 bits)
The group of cipher suites supported by the server has the following properties:
Forward Secrecy OK - Supported
Legacy RC4 Algorithm OK - Not Supported
* TLS 1.0 Cipher Suites:
Attempted to connect using 80 cipher suites.
The server accepted the following 2 cipher suites:
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 256 ECDH: prime256v1 (256 bits)
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 128 ECDH: prime256v1 (256 bits)
The group of cipher suites supported by the server has the following properties:
Forward Secrecy OK - Supported
Legacy RC4 Algorithm OK - Not Supported
I'm assuming that this may be due to the horrific things I've done to the Traefik routers and entrypoints, but I'm really not sure.
kit
September 4, 2021, 4:06pm
4
Disregard my previous message, it's all working fine.
I'm using Cloudflare to front my DNS, and it is proxying my server. As Cloudflare wasn't configured for minimum TLS of 1.2 it was returning the ciphers mentioned above. I enabled that setting in Cloudflare and it was al lfine. I then disabled the DNS proxy settings to confirm that my local configuration in Traefik was working, and it was.