Table of Contents
Overview
This guide demonstrates how to deploy CoreDNS and Smallstep Certificate Authority (StepCA) on Kubernetes using Podman Quadlet. This approach provides a robust DNS and PKI infrastructure for Kubernetes clusters, enabling secure internal communications with automated certificate management.
Architecture Overview
graph TB subgraph "Kubernetes Infrastructure" subgraph "DNS Namespace" A[CoreDNS Deployment] B[CoreDNS Service] C[ConfigMap] end
subgraph "PKI Namespace" D[StepCA Deployment] E[StepCA Service] F[Secret] G[PVC] end end
subgraph "Quadlet Integration" H[DNS Quadlet File] I[PKI Quadlet File] J[systemd Services] end
H --> A I --> D J --> H J --> I
style A fill:#4ecdc4,stroke:#087f5b,stroke-width:2px style D fill:#74c0fc,stroke:#1971c2,stroke-width:2px style J fill:#ffd43b,stroke:#fab005,stroke-width:2px
Complete Quadlet Configuration Files
DNS Deployment Quadlet
Create /etc/containers/systemd/dns-deployment.kube
:
## CoreDNS Kubernetes Deployment via Quadlet#[Unit]Description=CoreDNS Kubernetes DeploymentAfter=network-online.targetWants=network-online.target
[Kube]# Namespace for DNS servicesNamespace=dns
# The manifest for CoreDNSYaml='''apiVersion: v1kind: Namespacemetadata: name: dns---apiVersion: v1kind: ConfigMapmetadata: name: coredns-config namespace: dnsdata: Corefile: | .:53 { forward . 8.8.8.8 8.8.4.4 log errors } invinsense:53 { file /etc/coredns/invinsense.db log errors } invinsense.db: | $ORIGIN invinsense. @ 3600 IN SOA coredns.invinsense. admin.invinsense. ( 2023062001 ; serial 7200 ; refresh 3600 ; retry 1209600 ; expire 3600 ; minimum ) @ 3600 IN NS coredns.invinsense. coredns IN A 192.168.122.16 ca IN A 192.168.122.76---apiVersion: apps/v1kind: Deploymentmetadata: name: coredns namespace: dnsspec: replicas: 1 selector: matchLabels: app: coredns template: metadata: labels: app: coredns spec: containers: - name: coredns image: docker.io/coredns/coredns:1.11.1 args: ["-conf", "/etc/coredns/Corefile"] ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP volumeMounts: - name: config-volume mountPath: /etc/coredns volumes: - name: config-volume configMap: name: coredns-config---apiVersion: v1kind: Servicemetadata: name: coredns namespace: dnsspec: selector: app: coredns ports: - name: dns port: 53 protocol: UDP - name: dns-tcp port: 53 protocol: TCP type: LoadBalancer'''
[Install]WantedBy=default.target
PKI Deployment Quadlet
Create /etc/containers/systemd/pki-deployment.kube
:
## StepCA Kubernetes Deployment via Quadlet#[Unit]Description=StepCA Kubernetes DeploymentAfter=network-online.targetWants=network-online.target
[Kube]# Namespace for PKI servicesNamespace=pki
# The manifest for StepCAYaml='''apiVersion: v1kind: Namespacemetadata: name: pki---apiVersion: v1kind: Secretmetadata: name: stepca-secret namespace: pkitype: Opaquedata: password: ${STEPCA_PASSWORD_BASE64} # This will be replaced during setup---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: stepca-data namespace: pkispec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi---apiVersion: apps/v1kind: Deploymentmetadata: name: stepca namespace: pkispec: replicas: 1 selector: matchLabels: app: stepca template: metadata: labels: app: stepca spec: containers: - name: stepca image: smallstep/step-ca:0.24.0 ports: - containerPort: 443 env: - name: STEPCA_INIT_NAME value: "Invinsense CA" - name: STEPCA_INIT_DNS_NAMES value: "ca.invinsense" - name: STEPCA_INIT_ADDRESS value: ":443" - name: STEPCA_PASSWORD valueFrom: secretKeyRef: name: stepca-secret key: password volumeMounts: - name: stepca-data mountPath: /home/step volumes: - name: stepca-data persistentVolumeClaim: claimName: stepca-data---apiVersion: v1kind: Servicemetadata: name: stepca namespace: pkispec: selector: app: stepca ports: - port: 443 targetPort: 443 type: LoadBalancer'''
[Install]WantedBy=default.target
Setup Process
1. Prerequisites
# Check CoreOS version and kubectlrpm-ostree statuskubectl version
# Install kubectl if not presentrpm-ostree install kubectl
2. Create Configuration Directory
sudo mkdir -p /etc/containers/systemd
3. Generate StepCA Password
# Generate password and encodeSTEPCA_PASSWORD=$(openssl rand -base64 32)STEPCA_PASSWORD_BASE64=$(echo -n "$STEPCA_PASSWORD" | base64)
# Save password securelyecho "$STEPCA_PASSWORD" | sudo tee /etc/containers/stepca.passwordsudo chmod 600 /etc/containers/stepca.password
4. Create Quadlet Files
# Replace password in PKI deploymentsed "s/\${STEPCA_PASSWORD_BASE64}/$STEPCA_PASSWORD_BASE64/" pki-deployment.kube | \ sudo tee /etc/containers/systemd/pki-deployment.kube
# Copy CoreDNS deploymentsudo cp dns-deployment.kube /etc/containers/systemd/
5. Set Permissions
sudo chmod 644 /etc/containers/systemd/*.kube
6. Enable and Start Services
# Reload systemd to detect new Quadlet filessudo systemctl daemon-reload
# Enable and start CoreDNSsudo systemctl enable --now kube-dns-deployment
# Enable and start StepCAsudo systemctl enable --now kube-pki-deployment
Verification and Testing
Check Service Status
# Check systemd servicessudo systemctl status kube-dns-deploymentsudo systemctl status kube-pki-deployment
# Check Kubernetes resourceskubectl get all -n dnskubectl get all -n pki
# Check podskubectl get pods -n dnskubectl get pods -n pki
Configure DNS Resolution
# Get CoreDNS service IPCOREDNS_IP=$(kubectl get svc -n dns coredns -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# Configure systemd-resolvedsudo mkdir -p /etc/systemd/resolved.conf.d/sudo bash -c "cat > /etc/systemd/resolved.conf.d/dns.conf << EOF[Resolve]DNS=$COREDNS_IPDomains=~invinsenseEOF"
# Restart resolvedsudo systemctl restart systemd-resolved
Initialize StepCA Client
# Install step CLI if neededsudo rpm-ostree install step-cli
# Get StepCA service IPSTEPCA_IP=$(kubectl get svc -n pki stepca -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# Get CA fingerprintCA_POD=$(kubectl get pods -n pki -l app=stepca -o jsonpath='{.items[0].metadata.name}')CA_FINGERPRINT=$(kubectl exec -n pki $CA_POD -- step certificate fingerprint /home/step/certs/root_ca.crt)
# Bootstrap with CAstep ca bootstrap --ca-url https://$STEPCA_IP --fingerprint $CA_FINGERPRINT
Test the Setup
# Test DNS resolutiondig @$COREDNS_IP ca.invinsensedig @$COREDNS_IP google.com
# Test certificate issuancestep ca certificate test.invinsense test.crt test.key
Advanced Configuration
Custom DNS Zones
graph LR subgraph "DNS Configuration" A[Corefile] --> B[Zone Files] B --> C[invinsense.db] B --> D[internal.db] B --> E[custom.db] end
subgraph "Resolution Flow" F[Client Query] --> G[CoreDNS] G --> H{Zone Match?} H -->|Yes| I[Local Resolution] H -->|No| J[Forward to Upstream] end
style A fill:#4ecdc4,stroke:#087f5b,stroke-width:2px style G fill:#74c0fc,stroke:#1971c2,stroke-width:2px
Certificate Management Flow
sequenceDiagram participant C as Client participant S as StepCA participant K as Kubernetes
C->>S: Request Certificate S->>S: Validate Request S->>C: Issue Certificate C->>K: Deploy with Certificate K->>S: Validate Certificate S->>K: Certificate Valid
Note over C,K: Automatic renewal before expiry
Maintenance Operations
View Logs
# CoreDNS logskubectl logs -n dns -l app=coredns
# StepCA logskubectl logs -n pki -l app=stepca
Restart Deployments
# Restart CoreDNSkubectl rollout restart deployment -n dns coredns
# Restart StepCAkubectl rollout restart deployment -n pki stepca
Update Container Images
# Update CoreDNSkubectl set image deployment/coredns -n dns \ coredns=docker.io/coredns/coredns:1.11.1
# Update StepCAkubectl set image deployment/stepca -n pki \ stepca=smallstep/step-ca:0.24.0
Backup Configuration
# Backup Kubernetes resourceskubectl get all -n dns -o yaml > dns-backup.yamlkubectl get all -n pki -o yaml > pki-backup.yaml
# Backup configurationssudo tar -czf k8s-quadlet-backup.tar.gz \ /etc/containers/systemd/*.kube \ /etc/containers/stepca.password
Security Best Practices
Network Policies
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: dns-network-policy namespace: dnsspec: podSelector: matchLabels: app: coredns policyTypes: - Ingress - Egress ingress: - from: - podSelector: {} - namespaceSelector: {} ports: - protocol: UDP port: 53 - protocol: TCP port: 53 egress: - to: - podSelector: {} ports: - protocol: UDP port: 53 - protocol: TCP port: 53
Certificate Security
graph TD A[Certificate Security] --> B[Secure Storage] A --> C[Access Control] A --> D[Rotation Policy]
B --> E[PVC Encryption] B --> F[Secret Management]
C --> G[RBAC Policies] C --> H[Network Policies]
D --> I[Automatic Renewal] D --> J[Audit Logging]
style A fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px style B fill:#74c0fc,stroke:#1971c2,stroke-width:2px style D fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
Troubleshooting
Common Issues
-
Service Not Starting
Terminal window # Check Quadlet syntaxsystemd-analyze verify /etc/containers/systemd/*.kube# View detailed logsjournalctl -u kube-dns-deployment -n 50 -
DNS Resolution Failures
Terminal window # Test CoreDNS directlykubectl exec -n dns deployment/coredns -- nslookup ca.invinsense# Check CoreDNS configurationkubectl describe configmap -n dns coredns-config -
Certificate Issues
Terminal window # Check StepCA statuskubectl exec -n pki deployment/stepca -- step ca health# View certificate detailsstep certificate inspect test.crt
Integration Examples
Application Deployment with Certificates
apiVersion: apps/v1kind: Deploymentmetadata: name: secure-appspec: template: spec: initContainers: - name: get-cert image: smallstep/step-cli command: - sh - -c - | step ca certificate ${HOSTNAME} /certs/tls.crt /certs/tls.key \ --ca-url https://stepca.pki.svc.cluster.local \ --root /certs/root_ca.crt volumeMounts: - name: certs mountPath: /certs containers: - name: app image: myapp:latest volumeMounts: - name: certs mountPath: /etc/ssl/certs readOnly: true volumes: - name: certs emptyDir: {}
Conclusion
Using Quadlet to deploy CoreDNS and StepCA on Kubernetes provides a clean, maintainable approach to managing DNS and PKI infrastructure. This setup offers:
- Simplified deployment through declarative Quadlet files
- Integrated certificate management with automatic issuance and renewal
- Secure DNS resolution for internal services
- Easy maintenance with systemd integration
Key benefits:
- No manual container management required
- Automatic restart on failure
- Integration with systemd logging
- Version-controlled infrastructure
- Scalable and production-ready
By following this guide, you can establish a robust DNS and certificate infrastructure for your Kubernetes cluster, enabling secure service-to-service communication with minimal operational overhead.