327 lines
12 KiB
YAML
327 lines
12 KiB
YAML
---
|
|
|
|
- name: traefik
|
|
hosts: all
|
|
tasks:
|
|
|
|
- name: Create a network
|
|
community.docker.docker_network:
|
|
name: traefik
|
|
enable_ipv6: yes
|
|
driver_options:
|
|
com.docker.network.bridge.name: br-traefik
|
|
ipam_config:
|
|
- subnet: 192.168.41.0/24
|
|
gateway: 192.168.41.1
|
|
# Local v6 IP
|
|
- subnet: fdaa:a192:b168:cd41::/64
|
|
gateway: fdaa:a192:b168:cd41::1
|
|
notify: Restart traefik
|
|
|
|
- name: /home/docker/traefik/docker-compose.yml Traefik Container Configuration
|
|
blockinfile:
|
|
path: /home/docker/traefik/docker-compose.yml
|
|
create: yes
|
|
mode: 0440
|
|
owner: root
|
|
group: docker
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
block: |
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:latest
|
|
#extra_hosts:
|
|
# - "host.docker.internal:host-gateway"
|
|
command:
|
|
# Try to enable this if something isn't working.
|
|
# Chances are, Traefik will tell you why.
|
|
# Be careful in production as it exposes the traffic you might not want to expose.
|
|
- --log.level=INFO
|
|
# http -> https redirect
|
|
- --entrypoints.http.address=:80
|
|
- --entrypoints.http.http.redirections.entryPoint.to=https
|
|
- --entrypoints.http.http.redirections.entryPoint.scheme=https
|
|
- --entrypoints.http.http.redirections.entrypoint.permanent=true
|
|
# https
|
|
- --entrypoints.https.address=:443
|
|
# Docker
|
|
- --providers.docker=true
|
|
- --providers.docker.endpoint=unix:///var/run/docker.sock
|
|
- --providers.docker.exposedByDefault=false
|
|
# Traefik
|
|
- --api=true
|
|
- --api.dashboard=true
|
|
- --api.insecure=false
|
|
# LetsEncrypt
|
|
# Staging Server - uncomment when testing
|
|
#- --certificatesResolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
|
|
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
|
|
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http
|
|
- --certificatesresolvers.letsencrypt.acme.email=ssl@{{inventory_hostname}}
|
|
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
|
# non-docker services
|
|
- --providers.file=true
|
|
- --providers.file.directory=/etc/traefik/providers.local
|
|
- --providers.file.watch=true
|
|
container_name: traefik
|
|
restart: unless-stopped
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
networks:
|
|
traefik:
|
|
ipv4_address: 192.168.41.200
|
|
ports:
|
|
- 80:80
|
|
- 443:443
|
|
volumes:
|
|
- /etc/localtime:/etc/localtime:ro
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ./letsencrypt:/letsencrypt
|
|
- ./providers:/etc/traefik/providers.local
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.http.routers.traefik.rule=Host(`traefik.{{inventory_hostname}}`)
|
|
- traefik.http.routers.traefik.entrypoints=https
|
|
- traefik.http.routers.traefik.middlewares=secHeaders@file,auth
|
|
- traefik.http.routers.traefik.service=api@internal
|
|
- traefik.http.routers.traefik.tls=true
|
|
- traefik.http.routers.traefik.tls.certresolver=letsencrypt
|
|
- traefik.http.middlewares.to-https.redirectscheme.scheme=https
|
|
# echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
|
|
- traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$XLxGs/Ba$$3phZ1a2RtfExOp8x6NFjZ.
|
|
networks:
|
|
traefik:
|
|
external: true
|
|
|
|
backup: yes
|
|
notify: Restart traefik
|
|
|
|
- name: Create traefik dir
|
|
ansible.builtin.file:
|
|
path: /home/docker/traefik/providers
|
|
owner: root
|
|
group: docker
|
|
state: directory
|
|
mode: '0755'
|
|
|
|
- name: Defaults for TLS,...
|
|
blockinfile:
|
|
path: /home/docker/traefik/providers/_default.yml
|
|
create: yes
|
|
mode: 0444
|
|
owner: root
|
|
group: docker
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
block: |
|
|
---
|
|
tls:
|
|
options:
|
|
default:
|
|
minVersion: VersionTLS12
|
|
cipherSuites:
|
|
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 # TLS 1.2
|
|
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 # TLS 1.2
|
|
- TLS_AES_256_GCM_SHA384 # TLS 1.3
|
|
- TLS_CHACHA20_POLY1305_SHA256 # TLS 1.3
|
|
curvePreferences:
|
|
- CurveP521
|
|
- CurveP384
|
|
sniStrict: true
|
|
http:
|
|
middlewares:
|
|
secHeaders:
|
|
compress: false
|
|
headers:
|
|
browserXssFilter: true
|
|
contentTypeNosniff: true
|
|
frameDeny: true
|
|
# HSTS Configuration
|
|
forceSTSHeader: true
|
|
stsIncludeSubdomains: true
|
|
stsPreload: true
|
|
stsSeconds: 31536000
|
|
customFrameOptionsValue: "SAMEORIGIN"
|
|
sslProxyHeaders:
|
|
X-Forwarded-Proto: "https"
|
|
notify: Restart traefik
|
|
|
|
- name: /usr/local/sbin/traefik-qualys-ssl-labs-check.sh
|
|
blockinfile:
|
|
path: /usr/local/sbin/traefik-qualys-ssl-labs-check.sh
|
|
mode: "0700"
|
|
owner: root
|
|
group: root
|
|
create: yes
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
block: |
|
|
. /etc/bash/gaboshlib.include
|
|
g_lockfile
|
|
g_nice
|
|
g_all-to-syslog
|
|
g_echo_ok "Starting $0"
|
|
|
|
|
|
# Using official API-CLI-Tool
|
|
# https://www.ssllabs.com/projects/ssllabs-apis/
|
|
# https://github.com/ssllabs/ssllabs-scan/
|
|
|
|
# Download and install if unavailable
|
|
if ! [ -f /usr/local/bin/ssllabs-scan ]
|
|
then
|
|
cd /tmp
|
|
rm -rf ssllabs-scan
|
|
git clone https://github.com/ssllabs/ssllabs-scan/ || g_echo_error "Could not download ssllabs-scan"
|
|
cd ssllabs-scan
|
|
make >${g_tmp}/ssllabs-scan-make.out
|
|
if [ -f ssllabs-scan-v3 ]
|
|
then
|
|
cp ssllabs-scan-v3 /usr/local/bin/ssllabs-scan
|
|
chmod 755 /usr/local/bin/ssllabs-scan
|
|
chown root. /usr/local/bin/ssllabs-scan
|
|
else
|
|
g_echo_error "Could not build ssllabs-scan $(cat ${g_tmp}/ssllabs-scan-make.out)"
|
|
fi
|
|
fi
|
|
|
|
# Check every Traefik Host
|
|
if [ -f /usr/local/bin/ssllabs-scan ]
|
|
then
|
|
find /home/docker -maxdepth 1 -mindepth 1 -type d | egrep -v ".del$|.bak$|.old$|var-lib-docker$" | while read dir
|
|
do
|
|
if grep -q Host "$dir"/docker-compose.override.yml >/dev/null 2>&1
|
|
then
|
|
grep Host "$dir"/docker-compose.override.yml >>$g_tmp/hosts
|
|
else
|
|
[ -f "$dir"/docker-compose.yml ] && grep Host "$dir"/docker-compose.yml >>$g_tmp/hosts
|
|
fi
|
|
done
|
|
grep Host /home/docker/traefik/providers/*.yml >>$g_tmp/hosts
|
|
cat $g_tmp/hosts | cut -d '`' -f2 | sort -u | while read host
|
|
do
|
|
resultfile="/tmp/ssllabs-scan-result-$$-$host"
|
|
host ${host} >/dev/null 2>&1 || continue
|
|
curl -s https://${host} >/dev/null 2>&1 || continue
|
|
echo '[]' >$resultfile
|
|
while cat $resultfile | jq -r | egrep -q '^\[\]$'
|
|
do
|
|
until ssllabs-scan --quiet ${host} >$resultfile
|
|
do
|
|
sleep 60
|
|
done
|
|
sleep 60
|
|
done
|
|
cat $resultfile | jq '.[] | .endpoints | .[] | .grade' >${g_tmp}/ssllabs-scan-result 2>&1 >${g_tmp}/ssllabs-scan-result
|
|
if ! egrep -q 'A+|null' ${g_tmp}/ssllabs-scan-result
|
|
then
|
|
#if ! grep -q T ${g_tmp}/ssllabs-scan-result
|
|
#then
|
|
g_echo_error "Qualys SSL Labs scan-result for ${host} not A+: $(cat ${g_tmp}/ssllabs-scan-result)
|
|
|
|
https://www.ssllabs.com/ssltest/analyze.html?d=${host}&hideResults=on
|
|
|
|
Result: $(cat ${g_tmp}/ssllabs-scan-result)"
|
|
#fi
|
|
else
|
|
g_echo_ok "Qualys SSL Labs scan-result for ${host}: $(cat ${g_tmp}/ssllabs-scan-result)"
|
|
fi
|
|
done
|
|
fi
|
|
backup: yes
|
|
validate: /bin/bash -n %s
|
|
|
|
- name: /usr/local/sbin/traefik-qualys-ssl-labs-check.sh shebang
|
|
lineinfile:
|
|
path: /usr/local/sbin/traefik-qualys-ssl-labs-check.sh
|
|
insertbefore: BOF
|
|
line: "#!/bin/bash"
|
|
|
|
- name: /usr/local/sbin/runchecks.d/traefik.check
|
|
blockinfile:
|
|
path: /usr/local/sbin/runchecks.d/traefik.check
|
|
mode: "0700"
|
|
owner: root
|
|
group: root
|
|
create: yes
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
block: |
|
|
>$g_tmp/hosts
|
|
find /home/docker -maxdepth 1 -mindepth 1 -type d | egrep -v ".del$|.bak$|.old$|var-lib-docker$" | while read dir
|
|
do
|
|
if grep -q Host "$dir"/docker-compose.override.yml >/dev/null 2>&1
|
|
then
|
|
grep Host "$dir"/docker-compose.override.yml >>$g_tmp/hosts
|
|
else
|
|
[ -f "$dir"/docker-compose.yml ] && grep Host "$dir"/docker-compose.yml >>$g_tmp/hosts
|
|
fi
|
|
done
|
|
grep Host /home/docker/traefik/providers/*.yml >>$g_tmp/hosts
|
|
|
|
cat $g_tmp/hosts | cut -d '`' -f2 | sort -u | while read host
|
|
do
|
|
find -mmin -5 /tmp/$host >/dev/null 2>&1 | grep -q $host && continue
|
|
egrep -q "192.168.41.1 $host" /etc/hosts || echo "192.168.41.1 $host" >>/etc/hosts
|
|
if ! wget --dns-timeout=120 -t5 --waitretry=120 --connect-timeout=300 --read-timeout=15 http://${host} >${g_tmp}/traefik-wget-check -O /dev/null 2>&1
|
|
then
|
|
if ! egrep -q "401 Unauthorized|403 Forbidden" ${g_tmp}/traefik-wget-check
|
|
then
|
|
g_echo_error "Error while connecting ${host} with wget:
|
|
|
|
$(cat ${g_tmp}/traefik-wget-check)"
|
|
else
|
|
[ -f "${g_tmp}/$host-502" ] && rm "${g_tmp}/$host-502"
|
|
fi
|
|
if egrep -q "502 Bad Gateway" ${g_tmp}/traefik-wget-check
|
|
then
|
|
if [ -s "${g_tmp}/$host-502" ] && find "${g_tmp}/$host-502" | grep "$host-502" -mmin +15
|
|
then
|
|
g_echo_error "Error while connecting ${host} with wget:
|
|
$(cat ${g_tmp}/traefik-wget-check)"
|
|
else
|
|
date >"${g_tmp}/$host-502"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
backup: yes
|
|
validate: /bin/bash -n %s
|
|
|
|
- name: /etc/cron.d/traefik-qualys-ssl-labs-check_local
|
|
blockinfile:
|
|
path: /etc/cron.d/traefik-qualys-ssl-labs-check_local
|
|
create: yes
|
|
mode: 0644
|
|
owner: root
|
|
group: root
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
block: |
|
|
@daily root /usr/local/sbin/traefik-qualys-ssl-labs-check.sh
|
|
backup: yes
|
|
|
|
- name: Allow http from all clients
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: '80'
|
|
proto: tcp
|
|
|
|
- name: Allow https from all clients
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: '443'
|
|
proto: tcp
|
|
|
|
- name: Allow access from br-traefik to Docker-Host for services running without docker
|
|
community.general.ufw:
|
|
rule: allow
|
|
interface: br-traefik
|
|
direction: in
|
|
|
|
|
|
handlers:
|
|
|
|
- name: Restart traefik
|
|
ansible.builtin.shell: docker-compose up -d --force-recreate
|
|
args:
|
|
chdir: /home/docker/traefik
|
|
|