r/samba-cert: Obtain LDAP/TLS cert via ACME

The *samba-cert* role configures `lego` and HAProxy to obtain an X.509
certificate via the ACME HTTP-01 challenge.  HAProxy is necessary
because LDAP server certificates need to have the apex domain in their
SAN field, and the ACME server may contact *any* domain controller
server with an A record for that name.  HAProxy will forward the
challenge request on to the first available host on port 5000, where
`lego` is listening to provide validation.

Issuing certificates this way has a couple of advantages:

1. No need for the wildcard certificate for the *pyrocufflink.blue*
   domain any more
2. Renewals are automatic and handled by the server itself rather than
   Ansible via scheduled Jenkins job

Item (2) is particularly interesting because it avoids the bi-monthly
issue where replacing the LDAP server certificate and restarting Samba
causes the Jenkins job to fail.

Naturally, for this to work correctly, all LDAP client applications
need to trust the certificates issued by the ACME server, in this case
*DCH Root CA R2*.
frigate-exporter
Dustin 2024-06-12 18:33:24 -05:00
parent 7b6e0bd100
commit ffe972d79b
8 changed files with 203 additions and 2 deletions

View File

@ -14,8 +14,9 @@ samba_shares:
read_only: no
samba_tls_enabled: true
samba_tls_keyfile: /etc/pki/tls/private/samba.key
samba_tls_certfile: /etc/pki/tls/certs/samba.cer
samba_tls_keyfile: /etc/samba/server.key
samba_tls_certfile: /etc/samba/server.cer
samba_tls_cafile: /etc/samba/ca.crt
collectd_processes:
- name: samba
@ -26,3 +27,14 @@ collectd_processes:
admin_users:
- 'PYROCUFFLINK\dustin'
- 'PYROCUFFLINK\jenkins'
haproxy_resolvers:
- name: local
nameservers:
- name: local
address: 127.0.0.1:53
options:
accepted_payload_size: 8192
samba_cert_acme_server: https://ca.pyrocufflink.blue:32599/acme/acme/directory
samba_cert_acme_email: '{{ ansible_hostname }}@pyrocufflink.net'

View File

@ -0,0 +1,5 @@
- name: restart samba-cert-renew.timer
systemd:
name: samba-cert-renew.timer
state: restarted

View File

@ -0,0 +1,3 @@
dependencies:
- role: haproxy
tags: haproxy

View File

@ -0,0 +1,122 @@
- name: ensure lego is installed
package:
name: golang-github-acme-lego
state: present
tags:
- install
- name: ensure haproxy is configured for domain controllers
template:
src: samba-dc.haproxy.cfg
dest: /etc/haproxy/conf.d/40-samba-dc.cfg
owner: root
group: root
mode: u=rw,go=r
notify:
- reload haproxy
tags:
- haproxy
- name: flush handlers
meta: flush_handlers
- name: ensure acme/http port is allowed in firewall
firewalld:
port: '{{ item }}'
state: enabled
loop:
- 80/tcp
- 5000/tcp
when: host_uses_firewalld|d(true)
tags:
- firewalld
- name: wait for dns records to propagate
delegate_to: localhost
become: false
command: 'true'
until: >-
ansible_default_ipv4.address in lookup("dig", krb5_realm | lower) and
ansible_default_ipv4.address in lookup("dig", ansible_fqdn)
delay: 60
retries: 15
changed_when: false
tags:
- wait-for-dns
- name: ensure samba server certificate exists
command:
lego
--path /var/lib/samba/.lego
--accept-tos
--server {{ samba_cert_acme_server }}
--http --http.port :5000
--domains {{ ansible_fqdn }}
--domains {{ krb5_realm | lower }}
--email {{ samba_cert_acme_email }}
run
args:
creates: /var/lib/samba/.lego/certificates/{{ ansible_fqdn }}.json
notify:
- restart samba
tags:
- cert
- name: ensure samba server certificate renewal service is installed
template:
src: samba-cert-renew.service.j2
dest: /etc/systemd/system/samba-cert-renew.service
owner: root
group: root
mode: u=rw,go=r
notify:
- reload systemd
tags:
- systemd
- name: ensure samba server certificate renewal timer is installed
template:
src: samba-cert-renew.timer.j2
dest: /etc/systemd/system/samba-cert-renew.timer
owner: root
group: root
mode: u=rw,go=r
notify:
- reload systemd
- restart samba-cert-renew.timer
tags:
- systemd
- name: flush handlers
meta: flush_handlers
- name: ensure samba-cert-renew timer is running
systemd:
name: samba-cert-renew.timer
state: started
tags:
- service
- name: ensure samba-cert-renew timer starts at boot
systemd:
name: samba-cert-renew.timer
enabled: true
tags:
- service
- name: ensure samba certificate files are linked
file:
path: /etc/samba/{{ item.path }}
src: '{{ item.dest }}'
force: true
state: link
loop:
- path: server.cer
dest: /var/lib/samba/.lego/certificates/{{ ansible_fqdn }}.crt
- path: server.key
dest: /var/lib/samba/.lego/certificates/{{ ansible_fqdn }}.key
- path: ca.crt
dest: /dev/null
notify:
- restart samba
tags:
- cert

View File

@ -0,0 +1,18 @@
[Unit]
Description=Renew Samba LDAP server certificate
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/lego \
--path /var/lib/samba/.lego \
--accept-tos \
--server {{ samba_cert_acme_server }} \
--http --http.port :5000 \
--domains {{ ansible_fqdn }} \
--domains {{ krb5_realm | lower }} \
--email {{ samba_cert_acme_email }} \
renew \
--renew-hook 'systemctl restart samba'
CapabilityBoundingSet=

View File

@ -0,0 +1,9 @@
[Unit]
Description=Samba LDAP server certificate renewal
[Timer]
OnCalendar=daily
RandomizedDelaySec=12h
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,30 @@
frontend http
bind *:80
acl acme_challenge path_beg /.well-known/acme-challenge
# Proxy ACME challenge requests to Lego
use_backend lego if acme_challenge
#default_backend web
# Lego listens on port 5000 when it is requresting a certificate via
# ACME. Only one DC can be requesting a certificate at a time, or
# requests may be forwarded to the wrong machine.
#
# It is imperative that the `check` option is NOT enabled for any
# server/template in this back-end, or challenge requests may get lost
# if they are initiated between HAProxy health check intervals.
backend lego
balance roundrobin
server-template dc {{ groups["samba-dc"] | length + 3 }} {{ krb5_realm|lower }}:5000 resolvers local init-addr none
retries 10
option redispatch
retry-on all-retryable-errors 404
# Although there is not currently a use case for it, it is possible to run a
# web server on the apex domain, but it has to listen on an alternate port.
#backend web
# balance roundrobin
# server-template dc 5 {{ krb5_realm|lower }}:8080 resolvers local init-addr none

View File

@ -4,6 +4,8 @@
- kerberos
- dch-selinux
- samba-dc
- role: samba-cert
tags: samba-cert
tasks:
- name: set samba configuration facts
set_fact: