feat(cert-manager): Add Cloudns issuer and DNS-01 challenge support

- Introduced a new Cloudns issuer configuration for cert-manager.
- Created separate tasks for DNS-01 and HTTP-01 challenge issuers.
- Updated cert-manager tasks to include Cloudns provider and manage secrets.
- Refactored existing LetsEncrypt issuer registration to use new task structure.
- Added necessary Kubernetes resources for Cloudns integration, including RBAC and certificates.
- Updated Terraform configurations to support new DNS records and service changes.
- Adjusted deployment strategies for CoreDNS and Open WebUI applications.
This commit is contained in:
2025-06-07 20:39:38 +02:00
parent 3cda0b5624
commit 01bf71f8d2
25 changed files with 590 additions and 17396 deletions
-3
View File
@@ -1,3 +0,0 @@
fwknopd_keys_dir: /etc/fwknop
fwknopd_key_base64: "<REPLACE_WITH_YOUR_KEY>"
fwknopd_hmac_key_base64: "<REPLACE_WITH_YOUR_HMAC>"
-39
View File
@@ -1,39 +0,0 @@
---
galaxy_info:
author: Alexandre Pires
description: Manage fwknopd on Linux
company: A13Labs
role_name: fwknopd
namespace: a13labs
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: MIT
min_ansible_version: "2.1"
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags:
[]
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies:
[]
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.
@@ -1,8 +0,0 @@
---
- name: Converge
hosts: all
gather_facts: false
tasks:
- name: Include role fwknopd
ansible.builtin.include_role:
name: fwknopd
@@ -1,23 +0,0 @@
---
dependency:
name: galaxy
driver:
name: podman
platforms:
- name: instance
image: nmusatti/ubuntu2204-pys-systemd:latest
pre_build_image: true
privileged: true
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
provisioner:
name: ansible
options:
vvv: true
env:
ANSIBLE_ROLES_PATH: ../../../
verifier:
name: ansible
@@ -1,30 +0,0 @@
---
- name: Prepare
hosts: all
gather_facts: false
tasks:
- name: Update cache # noqa no-changed-when
ansible.builtin.raw: apt update
- name: Install required packages # noqa no-changed-when
ansible.builtin.raw: apt install -y python3 sudo
- name: Install required packages # noqa no-changed-when
ansible.builtin.shell: |
set -o pipefail
apt install -y systemd
find /etc/systemd/system/*.wants /lib/systemd/system/multi-user.target.wants /lib/systemd/system/local-fs.target.wants /lib/systemd/system/sockets.target.wants -type f -name '*initctl*' -delete
find /lib/systemd/system/sysinit.target.wants -type f ! -name '*systemd-tmpfiles-setup*' -delete
find /lib/systemd -type f -name systemd-update-utmp-runlevel.service -delete
rm -vf /usr/share/systemd/tmp.mount
sed -ri '/^IPAddressDeny/d' /lib/systemd/system/systemd-journald.service
for MATCH in plymouth-start.service plymouth-quit-wait.service syslog.socket syslog.service display-manager.service systemd-sysusers.service tmp.mount systemd-udevd.service; do \
grep -rn --binary-files=without-match ${MATCH} /lib/systemd/ | cut -d: -f1 | xargs -r sed -ri 's/(.*=.*)'${MATCH}'(.*)/\1\2/'; \
done
systemctl disable ondemand.service
systemctl set-default multi-user.target
become: true
args:
executable: /bin/bash
environment:
DEBIAN_FRONTEND: noninteractive
-25
View File
@@ -1,25 +0,0 @@
---
- name: Install fwknop
ansible.builtin.package:
name: fwknop-server
state: present
update_cache: true
- name: Enable and start fwknopd
ansible.builtin.systemd:
name: fwknopd
enabled: true
state: started
- name: Generate fwknop key pair
ansible.builtin.command: fwknop --key-gen
args:
creates: "{{ fwknopd_keys_dir }}/access.conf"
- name: Copy access.conf
ansible.builtin.template:
src: access.conf.j2
dest: "{{ fwknopd_keys_dir }}/access.conf"
owner: root
group: root
mode: '0600'
@@ -1,6 +0,0 @@
SOURCE ANY
KEY_BASE64 {{ fwknopd_key_base64 }}
HMAC_KEY_BASE64 {{ fwknopd_hmac_key_base64 }}
ALLOW_IP ANY
OPEN_PORTS tcp/22
FW_ACCESS_TIMEOUT 30
+7 -3
View File
@@ -9,9 +9,13 @@ microk8s_lb_https_port: 443
microk8s_metallb_version: 0.14.9
# certificate manager
microk8s_issuer_email: webmaster@localhost.localdomain
microk8s_certmgr_letsencrypt_issuer_email: webmaster@localhost.localdomain
microk8s_certmgr_version: 1.14.5
microk8s_lets_encrypt_issuer: true
microk8s_certmgr_letsencrypt_http01: true
microk8s_certmgr_letsencrypt_dns01: false
microk8s_certmgr_letsencrypt_dns01_provider: "cloudns"
microk8s_cloudns_auth_id:
microk8s_cloudns_auth_password:
# microk8s specific
microk8s_channel: "{{ microk8s_k8s_version }}/stable"
@@ -38,6 +42,6 @@ microk8s_allowed_hosts: []
microk8s_iac_user: "provision"
microk8s_encryption_secret: "a13labs"
microk8s_encryption_secret: "UGIzZ0w5UENaOVp2YkttWDdDNlNtaDdNYUJVd0ttUTY="
microk8s_encryption_cfg: "/etc/microk8s_encryption.yaml"
microk8s_encryption_kms_socket: ""
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,322 @@
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: cert-manager-webhook-cloudns
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
# Grant cert-manager permission to validate using our apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-webhook-cloudns:domain-solver
labels:
app: cert-manager-webhook-cloudns
rules:
- apiGroups:
- acme.ixon.cloud
resources:
- "*"
verbs:
- "create"
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-webhook-cloudns:flowcontrol-solver
labels:
app: cert-manager-webhook-cloudns
chart: cert-manager-webhook-cloudns-1.1.1
release: cert-manager-webhook-cloudns
heritage: Helm
rules:
- apiGroups:
- "flowcontrol.apiserver.k8s.io"
resources:
- "prioritylevelconfigurations"
- "flowschemas"
verbs:
- "list"
- "watch"
---
# Source: cert-manager-webhook-cloudns/templates/secret-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-webhook-cloudns:cloudns-api-secret-access
labels:
app: cert-manager-webhook-cloudns
rules:
- apiGroups: [""]
resources:
- secrets
resourceNames:
- cert-manager-webhook-cloudns-api-secret
verbs:
- "get"
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
# apiserver gets the auth-delegator role to delegate auth decisions to
# the core apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-cloudns:auth-delegator
labels:
app: cert-manager-webhook-cloudns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager-webhook-cloudns
namespace: cert-manager
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-cloudns:domain-solver
labels:
app: cert-manager-webhook-cloudns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cert-manager-webhook-cloudns:domain-solver
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager
namespace: cert-manager
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-cloudns:flowcontrol-solver
labels:
app: cert-manager-webhook-cloudns
chart: cert-manager-webhook-cloudns-1.1.1
release: cert-manager-webhook-cloudns
heritage: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cert-manager-webhook-cloudns:flowcontrol-solver
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager-webhook-cloudns
namespace: "cert-manager"
---
# Source: cert-manager-webhook-cloudns/templates/secret-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-cloudns:api-secret-access
labels:
app: cert-manager-webhook-cloudns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cert-manager-webhook-cloudns:api-secret-access
subjects:
- apiGroup: ""
kind: ServiceAccount
namespace: default
name: cert-manager-webhook-cloudns
---
# Source: cert-manager-webhook-cloudns/templates/rbac.yaml
# Grant the webhook permission to read the ConfigMap containing the Kubernetes
# apiserver's requestheader-ca-certificate.
# This ConfigMap is automatically created by the Kubernetes apiserver.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cert-manager-webhook-cloudns:webhook-authentication-reader
namespace: kube-system
labels:
app: cert-manager-webhook-cloudns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager-webhook-cloudns
namespace: cert-manager
---
# Source: cert-manager-webhook-cloudns/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: cert-manager-webhook-cloudns
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
type: ClusterIP
ports:
- port: 443
targetPort: https
protocol: TCP
name: https
selector:
app: cert-manager-webhook-cloudns
---
# Source: cert-manager-webhook-cloudns/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cert-manager-webhook-cloudns
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
replicas: 1
selector:
matchLabels:
app: cert-manager-webhook-cloudns
template:
metadata:
labels:
app: cert-manager-webhook-cloudns
spec:
serviceAccountName: cert-manager-webhook-cloudns
containers:
- name: cert-manager-webhook-cloudns
image: "mschirrmeister/cert-manager-webhook-cloudns:latest-alpine"
imagePullPolicy: IfNotPresent
args:
- --tls-cert-file=/certs/tls.crt
- --tls-private-key-file=/certs/tls.key
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: GROUP_NAME
value: "acme.ixon.cloud"
- name: CLOUDNS_AUTH_ID_FILE
value: "/creds/auth_id"
- name: CLOUDNS_AUTH_PASSWORD_FILE
value: "/creds/auth_password"
- name: CLOUDNS_AUTH_ID_TYPE
value: auth-id
ports:
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
readinessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
volumeMounts:
- name: certs
mountPath: /certs
readOnly: true
- name: creds
mountPath: /creds
readOnly: true
resources: {}
volumes:
- name: certs
secret:
secretName: cert-manager-webhook-cloudns-webhook-tls
- name: creds
secret:
secretName: cert-manager-webhook-cloudns-api-secret
---
# Source: cert-manager-webhook-cloudns/templates/apiservice.yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.acme.ixon.cloud
labels:
app: cert-manager-webhook-cloudns
annotations:
cert-manager.io/inject-ca-from: "cert-manager/cert-manager-webhook-cloudns-webhook-tls"
spec:
group: acme.ixon.cloud
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: cert-manager-webhook-cloudns
namespace: cert-manager
version: v1alpha1
---
# Source: cert-manager-webhook-cloudns/templates/pki.yaml
# Generate a CA Certificate used to sign certificates for the webhook
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cert-manager-webhook-cloudns-ca
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
secretName: cert-manager-webhook-cloudns-ca
duration: 43800h # 5y
issuerRef:
name: cert-manager-webhook-cloudns-selfsign
commonName: "ca.cert-manager-webhook-cloudns.cert-manager"
isCA: true
---
# Source: cert-manager-webhook-cloudns/templates/pki.yaml
# Finally, generate a serving certificate for the webhook to use
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cert-manager-webhook-cloudns-webhook-tls
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
secretName: cert-manager-webhook-cloudns-webhook-tls
duration: 8760h # 1y
issuerRef:
name: cert-manager-webhook-cloudns-ca
dnsNames:
- cert-manager-webhook-cloudns
- cert-manager-webhook-cloudns.cert-manager
- cert-manager-webhook-cloudns.cert-manager.svc
---
# Source: cert-manager-webhook-cloudns/templates/pki.yaml
# Create a selfsigned Issuer, in order to create a root CA certificate for
# signing webhook serving certificates
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cert-manager-webhook-cloudns-selfsign
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
selfSigned: {}
---
# Source: cert-manager-webhook-cloudns/templates/pki.yaml
# Create an Issuer that uses the above generated CA certificate to issue certs
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cert-manager-webhook-cloudns-ca
namespace: "cert-manager"
labels:
app: cert-manager-webhook-cloudns
spec:
ca:
secretName: cert-manager-webhook-cloudns-ca
+6 -60
View File
@@ -15,64 +15,10 @@
src: "{{ k8s_etc }}/k8s-certmanager.yaml"
wait: true
- name: CertManager | Register LetsEncrypt (prod)
when: microk8s_lets_encrypt_issuer is true
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: public
- name: CertManager | LetsEncrypt DNS-01 issuer
ansible.builtin.include_tasks: issuers/dns-01.yml
when: microk8s_certmgr_letsencrypt_dns01 is true
- name: CertManager | Register LetsEncrypt (staging)
when: microk8s_lets_encrypt_issuer is true
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: public
- name: CertManager | LetsEncrypt HTTP-01 issuer
ansible.builtin.include_tasks: issuers/http-01.yml
when: microk8s_certmgr_letsencrypt_http01 is true
@@ -0,0 +1,64 @@
- name: CertManager | LetsEncrypt DNS-01 provider
ansible.builtin.include_tasks: "providers/{{ microk8s_certmgr_letsencrypt_dns01_provider }}.yml"
- name: CertManager | Register LetsEncrypt (prod)
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_certmgr_letsencrypt_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- dns01:
webhook:
groupName: acme.ixon.cloud
solverName: cloudns
- name: CertManager | Register LetsEncrypt (staging)
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_certmgr_letsencrypt_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- dns01:
webhook:
groupName: acme.ixon.cloud
solverName: cloudns
@@ -0,0 +1,59 @@
- name: CertManager | Register LetsEncrypt (prod)
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_certmgr_letsencrypt_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: public
- name: CertManager | Register LetsEncrypt (staging)
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
wait: true
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: "{{ microk8s_certmgr_letsencrypt_issuer_email }}"
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: public
@@ -0,0 +1,35 @@
- name: Cermanager | Create cloudns credentials
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
definition:
apiVersion: v1
kind: Secret
metadata:
name: cert-manager-webhook-cloudns-api-secret
namespace: cert-manager
type: Opaque
data:
auth_id: "{{ microk8s_cloudns_auth_id | b64encode }}"
auth_password: "{{ microk8s_cloudns_auth_password | b64encode }}"
- name: CertManager | Copy clouDNS issuer manifest to Kubernetes cluster
ansible.builtin.copy:
src: "cert-manager/cloudns-issuer.yaml"
dest: "{{ k8s_etc }}/k8s-certmanager-cloudns.yaml"
mode: "0600"
- name: CertManager | Apply clouDNS issuer manifests
environment:
PATH: "{{ k8s_venv }}/bin:{{ ansible_env.PATH }}"
vars:
ansible_python_interpreter: "{{ k8s_venv }}/bin/python"
kubernetes.core.k8s:
state: present
kubeconfig: "{{ k8s_kubeconfig }}"
src: "{{ k8s_etc }}/k8s-certmanager-cloudns.yaml"
wait: true