Add bind-external namespace for externally-reachable zones (#329)
We self-delegate `_acme-challenge.unkin.net` into an `acme.unkin.net` zone we serve ourselves, so cert-manager can solve Let's Encrypt DNS-01 over RFC2136/TSIG. That needs a publicly-reachable authoritative BIND, separate from the internal estate. - Add app `bind-external` (base + au-syd1 overlay); register it in the platform ApplicationSet and AppProject destinations (bind-operator already watches all namespaces). - Add BindCluster `bind-external`: authoritative-only, recursion off, no forwarding, transfers denied except the keyed catalog/zone AXFR; 2 replicas; primaryService is a dmz-pinned PureLB LoadBalancer at `198.18.199.53`. - Add BindZone `acme.unkin.net` (primary, dynamicUpdate) and BindTSIGKey `certmanager` (hmac-sha256), whose Secret `certmanager-tsig` reflects into the `cert-manager` namespace for the rfc2136 solver. Pairs with argocd-apps #327 (the ClusterIssuers) and a one-time Google Cloud DNS delegation + NAT of the public IP :53 to `198.18.199.53`. --------- Co-authored-by: Ben Vincent <neotheo@gmail.com> Reviewed-on: #329 Co-authored-by: Ben Vincent <ben@unkin.net> Co-committed-by: Ben Vincent <ben@unkin.net>
This commit was merged in pull request #329.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
---
|
||||
# Externally-reachable authoritative BIND for zones we delegate to ourselves.
|
||||
# First tenant: acme.unkin.net, the DNS-01 challenge zone Let's Encrypt validates
|
||||
# via a one-time _acme-challenge.unkin.net CNAME. Authoritative-only, recursion
|
||||
# off, no forwarding, no open transfers -- the primaryService is the single
|
||||
# dmz-pinned LoadBalancer that public NAT targets and that cert-manager writes to.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCluster
|
||||
metadata:
|
||||
name: bind-external
|
||||
namespace: bind-external
|
||||
spec:
|
||||
mode: authoritative
|
||||
recursion: false
|
||||
replicas: 2
|
||||
storageClassName: cephrbd-fast-delete
|
||||
storageSize: 1Gi
|
||||
# Public server: answer queries from anywhere (Let's Encrypt validates over the
|
||||
# internet), deny recursion and open zone transfers. localhost + pod net are
|
||||
# implied by "any" and cover in-pod nsupdate and secondary SOA refresh; per-zone
|
||||
# allow-transfer (catalog + acme zone) still permits key-authenticated AXFR.
|
||||
extraOptions:
|
||||
- "allow-query { any; }"
|
||||
- "allow-transfer { none; }"
|
||||
service:
|
||||
type: ClusterIP
|
||||
primaryService:
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: Local
|
||||
annotations:
|
||||
purelb.io/service-group: dmz
|
||||
purelb.io/addresses: 198.18.199.53
|
||||
external-dns.alpha.kubernetes.io/hostname: bind-external-primary.k8s.syd1.au.unkin.net
|
||||
resources:
|
||||
requests:
|
||||
cpu: 20m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
---
|
||||
# Catalog zone so the acme zone replicates onto the secondary (AXFR/IXFR keyed
|
||||
# with the certmanager TSIG key, reused here as the transfer key).
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindCatalogZone
|
||||
metadata:
|
||||
name: bind-external-catalog
|
||||
namespace: bind-external
|
||||
spec:
|
||||
clusterRef: bind-external
|
||||
zoneName: catalog.external
|
||||
transferKeyRef: certmanager
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- cluster.yaml
|
||||
- tsigkey.yaml
|
||||
- zones.yaml
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: bind-external
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
# TSIG key cert-manager uses to send RFC2136 dynamic updates (the DNS-01 TXT
|
||||
# records) to the primary, and that the secondary reuses for AXFR. The operator
|
||||
# generates the material into Secret certmanager-tsig in this namespace;
|
||||
# secretTemplate stamps emberstack reflector hints so the Secret is mirrored into
|
||||
# the cert-manager namespace, where the rfc2136 solver reads its "secret" key.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindTSIGKey
|
||||
metadata:
|
||||
name: certmanager
|
||||
namespace: bind-external
|
||||
spec:
|
||||
clusterRef: bind-external
|
||||
algorithm: hmac-sha256
|
||||
secretTemplate:
|
||||
annotations:
|
||||
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
|
||||
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "cert-manager"
|
||||
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
|
||||
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "cert-manager"
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# Self-delegated ACME challenge zone. Google Cloud DNS holds a one-time
|
||||
# _acme-challenge.unkin.net CNAME -> _acme-challenge.acme.unkin.net and an
|
||||
# acme.unkin.net NS delegation pointing here; cert-manager writes the challenge
|
||||
# TXT records via RFC2136 authenticated with the certmanager key.
|
||||
apiVersion: bind.unkin.net/v1alpha1
|
||||
kind: BindZone
|
||||
metadata:
|
||||
name: acme-unkin-net
|
||||
namespace: bind-external
|
||||
spec:
|
||||
clusterRef: bind-external
|
||||
zoneName: acme.unkin.net
|
||||
type: primary
|
||||
defaultTTL: 60
|
||||
dynamicUpdate: true
|
||||
updateKeyRef: certmanager
|
||||
allowTransfer:
|
||||
- key certmanager
|
||||
Reference in New Issue
Block a user