fetchcert: Add script to fetch certs from K8s

Since Fedora CoreOS machines are not managed by Ansible, we need another
way to keep the HTTPS certificate up-to-date.  To that end, I've added
the `fetchcert.sh` script, along with a corresponding systemd service
and timer unit, that will fetch the latest certificate from the Secret
resource managed by the Kubernetes API.  The script authenticates with
a long-lived bearer token associated with a particular Kubernetes
service account and downloads the current Secret to a local file.  If
the certificate in the Secret is different than the one already in
place, the certificate and key files are updated and nginx is reloaded.
This commit is contained in:
2023-09-21 22:23:22 -05:00
parent 222f40426a
commit d907b47db1
7 changed files with 130 additions and 0 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
*.ign
frigate.env
*.token

View File

@@ -20,6 +20,9 @@ $(foreach t,$(wildcard *.yaml),$(eval $(call genrules,$(t))))
%.env: %.env.gpg
gpg2 --decrypt $< > $@
%.token: %.token.gpg
gpg2 --decrypt $< > $@
publish: \
nvr1.ign
rsync -rti $^ files.pyrocufflink.blue:public_html/

36
fetchcert.service Normal file
View File

@@ -0,0 +1,36 @@
[Unit]
Description=Fetch HTTPS certificate from Kubernetes Secret API
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/sh /etc/fetchcert/fetchcert.sh default pyrocufflink-cert
ProtectSystem=strict
ReadWritePaths=/etc/pki/nginx
CapabilityBoundingSet=CAP_CHOWN
DeviceAllow=
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateUsers=yes
PrivateTmp=yes
ProcSubset=pid
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources

54
fetchcert.sh Normal file
View File

@@ -0,0 +1,54 @@
#!/bin/sh
# vim: set sw=4 ts=4 sts=4 et :
namespace=$2
secret=$3
keyout=/etc/pki/nginx/private/server.key
crtout=/etc/pki/nginx/server.crt
tmpdir=$(mktemp -d)
trap 'rm -rf "${tmpdir}"' INT TERM QUIT EXIT
cat > "${tmpdir}"/ca.crt <<EOF
-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTIyMDgwMTAyNTUzM1oXDTMyMDcyOTAyNTUzM1owFTETMBEGA1UE
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMs6
2PUOzIClsAgPv1Mn9CTwzSFMntAn7OppwK5BQ4E5Vd1yMjz3p0uA1ZINv1ORorG0
mLl95C7y+CWUGPx+stHKQr/40sLGyypbX+AfjoPzHiDbIcbZEff8X5RwKqzmT9V7
Yt29KewADod0z+fqNYa62MJDaUunfwaV8kKFU/WJM8IKv2eJxAtWzvK3iHAFhx0j
Xo4TlyINL9V9UMKLf12w6CA3G41uZIBCN3G7aJEm++eGoMdrPZUXlbCpbSztO85/
hbulVs+0hCIxWiI+mRmB5OoWlRYL4jA45oK/RtpEqSwZ95zlGNAChmH7rb0pTtNf
N0/C2wKAEL4POLx9kscCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
/wQFMAMBAf8wHQYDVR0OBBYEFHYActCjEWdtsA+Ju25gxJh/vaLQMBUGA1UdEQQO
MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAAfkYHecXUwyqvMSXmqr
ETqEzDCBini14s89VDhaDHOXBID9TKMVyeePdEYcPAJz3wo8fbx/+TL37K6hEuo+
7bUaamaumznsjg9L0Hth19GvuRKMXJlEpndRmE5K9hnaDLr94MLg9n1qGcEOt6tw
O6X5qqHf9AuuL39vt1+kSw6PeZZFZNMDZ8BdiTssw4btjQ2bsWu0wSiOSz/F8iRf
2vN5An5dheroDsFs4dZ9gnJ69TmqV1YqQxfRWqCxzfNJbgVm6AoBPwhL1JRuAU4N
3nCNoM9n2tLFDojT4un1778UVU91PtcBVdM9Nq+RC2jhXIyLBqsEK0ofOqFYqj3F
0EQ=
-----END CERTIFICATE-----
EOF
curl -fsSL \
-H 'Accept: application/json' \
-H "Authorization: Bearer $(cat /etc/fetchcert/token)" \
--cacert "${tmpdir}"/ca.crt \
https://kubernetes.pyrocufflink.blue:6443/api/v1/namespaces/${namespace}/secrets/${secret} \
-o "${tmpdir}"/secret.json \
|| exit
jq -r '.data["tls.key"]' "${tmpdir}"/secret.json \
| base64 -d > "${tmpdir}"/server.key
jq -r '.data["tls.crt"]' "${tmpdir}"/secret.json | \
base64 -d > "${tmpdir}"/server.crt
if [ "$(b2sum < "${tmpdir}"/server.crt)" != "$(b2sum < "${crtout}")" ]; then
install -m u=rw,go= -o 101 -g 101 "${tmpdir}"/server.key "${keyout}"
install -m u=rw,go=r -o root -g root "${tmpdir}"/server.crt "${crtout}"
chcon -t container_file_t "${keyout}" "${crtout}"
echo 'Certificate updated, reloading nginx ...' >&2
podman exec -it systemd-nginx nginx -s reload
fi

9
fetchcert.timer Normal file
View File

@@ -0,0 +1,9 @@
[Unit]
Description=Periodically fetch certificate from Kubernetes
[Timer]
OnCalendar=*-*-* 0:0:0
RandomizedDelaySec=8h
[Install]
WantedBy=timers.target

22
fetchcert.yaml Normal file
View File

@@ -0,0 +1,22 @@
variant: fcos
version: 1.4.0
storage:
files:
- path: /etc/fetchcert/fetchcert.sh
mode: 0755
contents:
local: fetchcert.sh
- path: /etc/systemd/system/fetchcert.service
mode: 0644
contents:
local: fetchcert.service
- path: /etc/systemd/system/fetchcert.timer
mode: 0644
contents:
local: fetchcert.timer
systemd:
units:
- name: fetchcert.timer
enabled: true

View File

@@ -1,6 +1,11 @@
variant: fcos
version: 1.4.0
ignition:
config:
merge:
- local: fetchcert.ign
storage:
files:
- path: /etc/containers/systemd/nginx.container