Table of Contents
Overview
This guide provides a complete setup for deploying CoreDNS and Smallstep Certificate Authority (StepCA) on Fedora CoreOS using Podman Quadlet. This approach offers a lightweight, systemd-integrated solution for DNS and PKI infrastructure without the complexity of Kubernetes.
Architecture Overview
graph TB subgraph "Fedora CoreOS Host" subgraph "systemd Services" A[container-coredns.service] B[container-stepca.service] end
subgraph "Podman Containers" C[CoreDNS Container] D[StepCA Container] end
subgraph "Storage" E[CoreDNS Config Volume] F[StepCA Data Volume] end
subgraph "Network" G[Podman Network] H[Host Network] end end
A --> C B --> D C --> E D --> F C --> G D --> G G --> H
style A fill:#ffd43b,stroke:#fab005,stroke-width:2px style B fill:#ffd43b,stroke:#fab005,stroke-width:2px style C fill:#4ecdc4,stroke:#087f5b,stroke-width:2px style D fill:#74c0fc,stroke:#1971c2,stroke-width:2px
Initial CoreOS Setup
1. Verify CoreOS Environment
# Check CoreOS versionrpm-ostree status
# Verify Podman installationpodman --version
# Check systemd versionsystemctl --version
2. Create Required Directories
# Create directories for configurationssudo mkdir -p /etc/containers/systemdsudo mkdir -p /etc/containers/corednssudo mkdir -p /etc/containers/stepca
CoreDNS Configuration Files
CoreDNS Corefile
Create /etc/containers/coredns/Corefile
:
.:53 { hosts { 192.168.122.16 coredns.invinsense 192.168.122.76 ca.invinsense 192.168.122.236 nginx.invinsense fallthrough } forward . 8.8.8.8 9.9.9.9 { max_concurrent 1000 } cache 300 log errors}
invinsense:53 { file /etc/coredns/invinsense.db log errors}
DNS Zone File
Create /etc/containers/coredns/invinsense.db
:
$ORIGIN invinsense.@ 3600 IN SOA coredns.invinsense. admin.invinsense. ( 2024010101 ; serial 7200 ; refresh (2 hours) 3600 ; retry (1 hour) 1209600 ; expire (2 weeks) 3600 ; minimum (1 hour) )
3600 IN NS coredns.invinsense.
coredns IN A 192.168.122.16ca IN A 192.168.122.76nginx IN A 192.168.122.236*.apps IN A 192.168.122.100
StepCA Configuration
StepCA Environment File
Create /etc/containers/stepca.env
:
STEPCA_PASSWORD=your_secure_password_here
Secure the file:
sudo chmod 600 /etc/containers/stepca.envsudo chown root:root /etc/containers/stepca.env
Quadlet Configuration Files
CoreDNS Network Configuration
Create /etc/containers/systemd/dns-ca.network
:
[Network]NetworkName=dns-ca-networkSubnet=10.89.0.0/24Gateway=10.89.0.1DNS=10.89.0.10
CoreDNS Volume Configuration
Create /etc/containers/systemd/coredns-config.volume
:
[Volume]VolumeName=coredns-configCopyFiles=/etc/containers/coredns:/etc/coredns
StepCA Volume Configuration
Create /etc/containers/systemd/stepca-data.volume
:
[Volume]VolumeName=stepca-data
CoreDNS Container Configuration
Create /etc/containers/systemd/coredns.container
:
[Unit]Description=CoreDNS DNS ServerAfter=network-online.target dns-ca.network.serviceWants=network-online.target dns-ca.network.service
[Container]Image=docker.io/coredns/coredns:1.11.1ContainerName=corednsNetwork=dns-ca.networkPublishPort=53:53/udpPublishPort=53:53/tcpVolume=coredns-config.volume:/etc/coredns:ro,zEnvironment=COREDNS_CONFIG=/etc/coredns/CorefileExec=-conf /etc/coredns/Corefile
# Security settingsSecurityLabelType=spc_tReadOnly=falseNoNewPrivileges=true
# Resource limitsMemoryLimit=512MCPUQuota=50%
[Service]Restart=alwaysRestartSec=30TimeoutStartSec=900
[Install]WantedBy=default.target
StepCA Container Configuration
Create /etc/containers/systemd/stepca.container
:
[Unit]Description=Smallstep Certificate AuthorityAfter=network-online.target dns-ca.network.serviceWants=network-online.target dns-ca.network.service
[Container]Image=docker.io/smallstep/step-ca:0.24.0ContainerName=stepcaNetwork=dns-ca.networkPublishPort=443:443Volume=stepca-data.volume:/home/step:zEnvironmentFile=/etc/containers/stepca.envEnvironment=DOCKER_STEPCA_INIT_NAME=Invinsense CAEnvironment=DOCKER_STEPCA_INIT_DNS_NAMES=ca.invinsense,localhostEnvironment=DOCKER_STEPCA_INIT_ADDRESS=:443
# Security settingsSecurityLabelType=spc_tReadOnly=falseNoNewPrivileges=true
# Resource limitsMemoryLimit=512MCPUQuota=50%
[Service]Restart=alwaysRestartSec=30TimeoutStartSec=900
[Install]WantedBy=default.target
Deployment Process
1. Deploy the Services
# Reload systemd to detect new Quadlet filessudo systemctl daemon-reload
# Start and enable the networksudo systemctl enable --now dns-ca.network
# Start and enable volumessudo systemctl enable --now coredns-config.volumesudo systemctl enable --now stepca-data.volume
# Start and enable containerssudo systemctl enable --now coredns.containersudo systemctl enable --now stepca.container
2. Verify Services
# Check service statussudo systemctl status coredns.containersudo systemctl status stepca.container
# Check container statuspodman ps
# View logssudo journalctl -u coredns.containersudo journalctl -u stepca.container
Post-Deployment Configuration
Configure System DNS
# Update system DNS to use CoreDNSsudo nmcli connection modify "System eth0" ipv4.dns "127.0.0.1"sudo nmcli connection up "System eth0"
# Verify DNS resolutiondig @localhost ca.invinsensenslookup nginx.invinsense
Initialize StepCA Client
# Get CA fingerprintsudo podman exec stepca step certificate fingerprint /home/step/certs/root_ca.crt
# Bootstrap the clientstep ca bootstrap --ca-url https://ca.invinsense --fingerprint <FINGERPRINT>
# Request a test certificatestep ca certificate test.invinsense test.crt test.key
Advanced Configuration
High Availability Setup
graph TB subgraph "HA Architecture" subgraph "Node 1" A1[CoreDNS Primary] B1[StepCA Primary] end
subgraph "Node 2" A2[CoreDNS Secondary] B2[StepCA Standby] end
subgraph "Node 3" A3[CoreDNS Secondary] B3[StepCA Standby] end
C[Load Balancer] D[Shared Storage] end
C --> A1 C --> A2 C --> A3
B1 --> D B2 --> D B3 --> D
style C fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px style D fill:#74c0fc,stroke:#1971c2,stroke-width:2px
DNS Performance Tuning
Add to CoreDNS Corefile:
.:53 { # Performance optimizations bufsize 1232 cache { success 9984 300 denial 9984 5 }
# Health checks health { lameduck 5s } ready
# Prometheus metrics prometheus :9153}
Certificate Auto-Renewal Script
Create /usr/local/bin/cert-renewal.sh
:
#!/bin/bashset -euo pipefail
CERT_DIR="/etc/ssl/certs"KEY_DIR="/etc/ssl/private"DOMAINS=("nginx.invinsense" "app1.invinsense" "app2.invinsense")
for domain in "${DOMAINS[@]}"; do echo "Checking certificate for $domain..."
if step certificate needs-renewal "$CERT_DIR/$domain.crt"; then echo "Renewing certificate for $domain..." step ca renew "$CERT_DIR/$domain.crt" "$KEY_DIR/$domain.key" --force
# Reload services that use this certificate systemctl reload nginx || true fidone
Monitoring Configuration
# prometheus-config.yaml for monitoringglobal: scrape_interval: 15s
scrape_configs: - job_name: "coredns" static_configs: - targets: ["localhost:9153"]
- job_name: "stepca" static_configs: - targets: ["localhost:9000"]
Security Hardening
SELinux Configuration
# Create custom SELinux policy for containerscat > coredns-stepca.te << 'EOF'module coredns-stepca 1.0;
require { type container_t; type dns_port_t; type http_port_t; class tcp_socket name_bind; class udp_socket name_bind;}
#============= container_t ==============allow container_t dns_port_t:tcp_socket name_bind;allow container_t dns_port_t:udp_socket name_bind;allow container_t http_port_t:tcp_socket name_bind;EOF
# Compile and install the policycheckmodule -M -m -o coredns-stepca.mod coredns-stepca.tesemodule_package -o coredns-stepca.pp -m coredns-stepca.modsudo semodule -i coredns-stepca.pp
Firewall Rules
# Configure firewallsudo firewall-cmd --add-service=dns --permanentsudo firewall-cmd --add-service=https --permanentsudo firewall-cmd --reload
Maintenance Operations
Backup Procedures
#!/bin/bashBACKUP_DIR="/var/backups/dns-ca"DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directorymkdir -p "$BACKUP_DIR"
# Backup CoreDNS configurationpodman volume export coredns-config > "$BACKUP_DIR/coredns-config-$DATE.tar"
# Backup StepCA datapodman volume export stepca-data > "$BACKUP_DIR/stepca-data-$DATE.tar"
# Backup Quadlet configurationstar -czf "$BACKUP_DIR/quadlet-configs-$DATE.tar.gz" /etc/containers/systemd/
# Keep only last 7 days of backupsfind "$BACKUP_DIR" -name "*.tar*" -mtime +7 -delete
Update Procedures
# Update container imagessudo podman pull docker.io/coredns/coredns:latestsudo podman pull docker.io/smallstep/step-ca:latest
# Update Quadlet files with new image tagssudo sed -i 's/coredns:1.11.1/coredns:latest/g' /etc/containers/systemd/coredns.containersudo sed -i 's/step-ca:0.24.0/step-ca:latest/g' /etc/containers/systemd/stepca.container
# Restart servicessudo systemctl restart coredns.containersudo systemctl restart stepca.container
Troubleshooting Guide
Common Issues and Solutions
-
Container Fails to Start
Terminal window # Check for port conflictssudo ss -tlnp | grep -E ':53|:443'# Verify SELinux contextls -Z /etc/containers/systemd/ -
DNS Resolution Failures
Terminal window # Test CoreDNS directlydig @localhost invinsense# Check CoreDNS logssudo podman logs coredns -
Certificate Issues
Terminal window # Verify StepCA is initializedsudo podman exec stepca step ca health# Check certificate chainopenssl s_client -connect ca.invinsense:443 -showcerts
Debug Commands
# Enable debug logging for CoreDNSsudo podman exec coredns kill -USR1 1
# View detailed container inspectsudo podman inspect coredns stepca
# Check systemd unit statussystemctl status container-*.service
Performance Metrics
graph LR subgraph "Performance Monitoring" A[CoreDNS Metrics] --> B[Query Rate] A --> C[Cache Hit Ratio] A --> D[Response Time]
E[StepCA Metrics] --> F[Certificate Issued] E --> G[Request Latency] E --> H[Error Rate] end
style A fill:#4ecdc4,stroke:#087f5b,stroke-width:2px style E fill:#74c0fc,stroke:#1971c2,stroke-width:2px
Conclusion
This comprehensive setup provides a production-ready DNS and PKI infrastructure on Fedora CoreOS using Podman Quadlet. The configuration offers:
- Seamless Integration: Native systemd integration through Quadlet
- High Security: SELinux policies, firewall rules, and container isolation
- Easy Maintenance: Automated updates and backup procedures
- Scalability: Ready for high-availability configurations
- Monitoring: Built-in metrics and health checks
Key advantages:
- No Kubernetes overhead
- Immutable infrastructure approach
- Declarative configuration
- Automatic service management
- Production-grade reliability
By following this guide, you can deploy a robust DNS and certificate infrastructure that’s both secure and maintainable, perfect for internal networks and development environments.