Deploying CoreDNS and StepCA on CoreOS using Podman Quadlet
Modern infrastructure requires both reliable DNS resolution and secure certificate management. Fedora CoreOS provides an excellent foundation for running containerized infrastructure services with its focus on security, atomic updates, and minimal footprint. This guide demonstrates how to deploy both CoreDNS (for DNS services) and StepCA (for certificate authority services) on CoreOS using Podman Quadlet, which integrates containers directly with systemd.
Understanding the Components
Before diving into the implementation, let’s understand the key components:
graph TD A[CoreOS] --> B[Podman] B --> C[Quadlet] C --> D[systemd Integration] D --> E[CoreDNS Container] D --> F[StepCA Container]
E --> G[DNS Resolution] F --> H[Certificate Authority]
G --> I[Internal Domain Names] G --> J[External Domain Resolution]
H --> K[Certificate Issuance] H --> L[Certificate Validation]
M[Client System] --> G M --> H
- CoreOS: A minimal container-focused operating system
- Podman: A daemonless container engine
- Quadlet: A tool that integrates containers with systemd
- CoreDNS: A flexible DNS server written in Go
- StepCA: A certificate authority for secure automated certificate management
Prerequisites
To follow this guide, you need:
- A Fedora CoreOS system (version 38 or newer recommended)
- Administrative access (sudo privileges)
- Basic knowledge of containers, DNS, and PKI concepts
Implementation Steps
1. Verifying the Environment
First, ensure you’re running CoreOS with Podman installed:
# Check CoreOS versionrpm-ostree status
# Verify Podman installationpodman --version
Make sure Podman version is 4.0 or higher, which includes Quadlet support.
2. Creating Directory Structure
Set up the necessary directories for our configuration files:
# Create main directoriessudo mkdir -p /etc/containers/systemdsudo mkdir -p /etc/containers/corednssudo mkdir -p /etc/containers/stepca
3. Creating CoreDNS Configuration Files
Create the configuration files needed for CoreDNS:
# Create the Corefile for CoreDNSsudo tee /etc/containers/coredns/Corefile > /dev/null << 'EOF'.:53 { forward . 8.8.8.8 log errors}
invinsense:53 { file /etc/coredns/invinsense.db log errors}EOF
# Create the zone file for your internal domainsudo tee /etc/containers/coredns/invinsense.db > /dev/null << 'EOF'$ORIGIN invinsense.@ 3600 IN SOA coredns.invinsense. admin.invinsense. ( 2024062201 ; serial 7200 ; refresh 3600 ; retry 1209600 ; expire 3600 ; minimum)
@ 3600 IN NS coredns.invinsense.
coredns IN A 127.0.0.1ca IN A 127.0.0.1EOF
4. Setting Up StepCA Environment
Generate a secure password for StepCA and save it in an environment file:
# Generate a secure random passwordPASSWORD=$(openssl rand -base64 32)
# Create environment filesudo bash -c "cat > /etc/containers/stepca.env << EOFSTEPCA_PASSWORD=$PASSWORDEOF"
# Secure the filesudo chmod 600 /etc/containers/stepca.env
# Save the password somewhere secure for referenceecho "Your StepCA password is: $PASSWORD"echo "Make sure to save this password in a secure location!"
5. Creating Quadlet Configuration Files
Now, let’s create the Quadlet files that define our containers as systemd services:
# Create CoreDNS container configurationsudo tee /etc/containers/systemd/coredns.container > /dev/null << 'EOF'[Unit]Description=CoreDNS DNS ServerDocumentation=https://coredns.ioAfter=network-online.targetWants=network-online.target
[Container]Image=docker.io/coredns/coredns:1.11.1Network=hostVolume=/etc/containers/coredns:/etc/coredns:ro,zUserNS=keep-id
[Service]Restart=alwaysTimeoutStartSec=30TimeoutStopSec=30
[Install]WantedBy=multi-user.targetEOF
# Create StepCA container configurationsudo tee /etc/containers/systemd/stepca.container > /dev/null << 'EOF'[Unit]Description=StepCA Certificate AuthorityDocumentation=https://smallstep.com/docs/step-caAfter=network-online.targetWants=network-online.target
[Container]Image=docker.io/smallstep/step-ca:0.24.0Network=hostEnvironmentFile=/etc/containers/stepca.envEnvironment=STEPCA_INIT_NAME=Invinsense CAEnvironment=STEPCA_INIT_DNS_NAMES=ca.invinsenseEnvironment=STEPCA_INIT_ADDRESS=:443Volume=stepca-data:/home/step
[Service]Restart=alwaysTimeoutStartSec=60TimeoutStopSec=30
[Install]WantedBy=multi-user.targetEOF
# Create volume for StepCA datasudo tee /etc/containers/systemd/stepca.volume > /dev/null << 'EOF'[Volume]Driver=localDevice=tmpfsOptions=type=tmpfsUID=0GID=0EOF
6. Activating the Services
Now we’ll enable and start our services:
# Reload systemd to detect new quadlet filessudo systemctl daemon-reload
# Start CoreDNSsudo systemctl enable --now container-coredns
# Start StepCAsudo systemctl enable --now container-stepca
7. Configuring Local DNS Resolution
Configure your system to use your local CoreDNS server for DNS resolution:
# Create resolved configurationsudo mkdir -p /etc/systemd/resolved.conf.d/sudo tee /etc/systemd/resolved.conf.d/dns.conf > /dev/null << 'EOF'[Resolve]DNS=127.0.0.1Domains=~invinsenseEOF
# Restart resolvedsudo systemctl restart systemd-resolved
8. Verifying Service Operation
Let’s verify that both services are running properly:
# Check CoreDNS service statussudo systemctl status container-coredns
# Check CoreDNS logspodman logs coredns
# Check StepCA service statussudo systemctl status container-stepca
# Check StepCA logspodman logs stepca
9. Testing DNS Resolution
Test your CoreDNS configuration by resolving both internal and external domains:
# Test internal domain resolutiondig @localhost ca.invinsense
# Test external domain resolutiondig @localhost google.com
10. Setting Up StepCA Client
Install and configure the Step CLI tool to interact with your certificate authority:
# Install step CLI if not already installedsudo rpm-ostree install step-cli
# Get CA fingerprintCA_FINGERPRINT=$(podman exec stepca step certificate fingerprint /home/step/certs/root_ca.crt)
# Bootstrap with CAstep ca bootstrap --ca-url https://ca.invinsense --fingerprint $CA_FINGERPRINT
# Request a test certificatestep ca certificate test.invinsense test.crt test.key
Maintenance and Troubleshooting
Viewing Service Logs
Monitor your services through systemd’s journaling system:
# View CoreDNS logsjournalctl -u container-coredns -f
# View StepCA logsjournalctl -u container-stepca -f
Restarting Services
If you need to restart the services:
# Restart CoreDNSsudo systemctl restart container-coredns
# Restart StepCAsudo systemctl restart container-stepca
Updating Container Images
Keep your services updated with the latest container images:
# Pull new CoreDNS imagepodman pull docker.io/coredns/coredns:latest
# Pull new StepCA imagepodman pull docker.io/smallstep/step-ca:latest
# Restart services to use new imagessudo systemctl restart container-corednssudo systemctl restart container-stepca
Backing Up Configuration
Regularly back up your configuration files:
# Create a comprehensive backupsudo tar -czf coreos-dns-ca-backup-$(date +%Y%m%d).tar.gz \ /etc/containers/systemd \ /etc/containers/coredns \ /etc/containers/stepca.env
# For a more complete backup that includes certificatespodman exec stepca tar -cf - -C /home/step . | sudo tee stepca-data-backup-$(date +%Y%m%d).tar > /dev/null
Common Issues and Solutions
DNS Resolution Not Working
If DNS resolution isn’t working:
# Check if CoreDNS is runningsudo systemctl status container-coredns
# Verify DNS configurationcat /etc/systemd/resolved.conf.d/dns.conf
# Test direct DNS queriesdig @127.0.0.1 ca.invinsense
# Check CoreDNS logs for errorsjournalctl -u container-coredns | grep -i error
Certificate Issuance Problems
If you’re having trouble issuing certificates:
# Check if StepCA is runningsudo systemctl status container-stepca
# Verify CA connectivitycurl -k https://ca.invinsense/health
# Check StepCA logs for errorsjournalctl -u container-stepca | grep -i error
# Re-bootstrap the CA clientstep ca bootstrap --ca-url https://ca.invinsense --fingerprint $CA_FINGERPRINT
Container-Related Issues
For issues with the containers themselves:
# Check container statuspodman ps -a
# Inspect container detailspodman inspect corednspodman inspect stepca
# Check for network conflictssudo ss -tulpn | grep '53\|443'
Advanced Configuration
Persistent Storage for StepCA
The default configuration uses tmpfs for StepCA data, which means certificates are lost on reboot. For a production environment, you’ll want persistent storage:
# Create a persistent directory for StepCA datasudo mkdir -p /var/lib/stepcasudo chown 1000:1000 /var/lib/stepca
# Update the StepCA container configurationsudo tee /etc/containers/systemd/stepca.container > /dev/null << 'EOF'[Unit]Description=StepCA Certificate AuthorityDocumentation=https://smallstep.com/docs/step-caAfter=network-online.targetWants=network-online.target
[Container]Image=docker.io/smallstep/step-ca:0.24.0Network=hostEnvironmentFile=/etc/containers/stepca.envEnvironment=STEPCA_INIT_NAME=Invinsense CAEnvironment=STEPCA_INIT_DNS_NAMES=ca.invinsenseEnvironment=STEPCA_INIT_ADDRESS=:443Volume=/var/lib/stepca:/home/step:z
[Service]Restart=alwaysTimeoutStartSec=60TimeoutStopSec=30
[Install]WantedBy=multi-user.targetEOF
# Reload systemd and restart StepCAsudo systemctl daemon-reloadsudo systemctl restart container-stepca
Adding More DNS Zones
You can add more DNS zones to CoreDNS by updating the Corefile and adding zone files:
# Add a new zone to the Corefilesudo tee -a /etc/containers/coredns/Corefile > /dev/null << 'EOF'
example.com:53 { file /etc/coredns/example.com.db log errors}EOF
# Create the new zone filesudo tee /etc/containers/coredns/example.com.db > /dev/null << 'EOF'$ORIGIN example.com.@ 3600 IN SOA ns1.example.com. admin.example.com. ( 2024062201 ; serial 7200 ; refresh 3600 ; retry 1209600 ; expire 3600 ; minimum)
@ 3600 IN NS ns1.example.com.
ns1 IN A 127.0.0.1www IN A 192.168.1.100app IN A 192.168.1.101EOF
# Restart CoreDNS to apply changessudo systemctl restart container-coredns
Configuring Additional StepCA Provisioners
By default, StepCA creates an admin provisioner for certificate issuance. You can add more provisioners:
# Add a new ACME provisioner for Let's Encrypt-compatible clientspodman exec -it stepca step ca provisioner add acme --type ACME
# Add a new JWK provisioner for service authenticationpodman exec -it stepca step ca provisioner add service --type JWK
# List all provisionerspodman exec -it stepca step ca provisioner list
Setting Up Automatic Certificate Renewal
Configure automatic renewal for certificates:
# Create a renewal scriptcat << 'EOF' > renew-cert.sh#!/bin/bashstep ca renew --force certificate.crt certificate.keychmod 600 certificate.keyEOFchmod +x renew-cert.sh
# Add to user's crontab (runs daily at 2am)(crontab -l 2>/dev/null; echo "0 2 * * * $PWD/renew-cert.sh") | crontab -
Security Considerations
Securing DNS Traffic
For production environments, consider securing DNS traffic:
# Update CoreDNS configuration to enable DNS-over-TLSsudo tee /etc/containers/coredns/Corefile > /dev/null << 'EOF'.:53 { forward . 8.8.8.8 log errors}
.:853 { tls /etc/coredns/cert.pem /etc/coredns/key.pem forward . 8.8.8.8 log errors}
invinsense:53 { file /etc/coredns/invinsense.db log errors}
invinsense:853 { tls /etc/coredns/cert.pem /etc/coredns/key.pem file /etc/coredns/invinsense.db log errors}EOF
# Generate certificates for CoreDNSstep ca certificate coredns.invinsense /etc/containers/coredns/cert.pem /etc/containers/coredns/key.pem
Limiting Access to Services
Restrict access to your DNS and CA services:
# Configure firewall rulessudo firewall-cmd --permanent --add-service=dnssudo firewall-cmd --permanent --add-port=443/tcpsudo firewall-cmd --permanent --add-port=853/tcpsudo firewall-cmd --reload
Regular Backup Schedule
Implement a regular backup schedule:
# Create a backup scriptcat << 'EOF' > /usr/local/bin/backup-infra.sh#!/bin/bashBACKUP_DIR="/var/backups/infra"DATE=$(date +%Y%m%d)
# Create backup directorymkdir -p $BACKUP_DIR
# Backup configurationstar -czf $BACKUP_DIR/configs-$DATE.tar.gz \ /etc/containers/systemd \ /etc/containers/coredns \ /etc/containers/stepca.env
# Backup StepCA datapodman exec stepca tar -cf - -C /home/step . | \ tee $BACKUP_DIR/stepca-data-$DATE.tar > /dev/null
# Cleanup old backups (keep last 30 days)find $BACKUP_DIR -type f -mtime +30 -deleteEOF
# Make executablechmod +x /usr/local/bin/backup-infra.sh
# Add to crontab (weekly backup on Sunday at 1am)(sudo crontab -l 2>/dev/null; echo "0 1 * * 0 /usr/local/bin/backup-infra.sh") | sudo crontab -
Conclusion
In this guide, we’ve successfully deployed CoreDNS and StepCA on Fedora CoreOS using Podman Quadlet for systemd integration. This setup provides a robust foundation for DNS resolution and certificate management in your infrastructure, all while leveraging the benefits of containerization and the security-focused design of CoreOS.
The combination of these technologies offers several advantages:
- Security-focused design with minimal attack surface
- Atomic updates through CoreOS’s immutable design
- Container isolation for services
- Systemd integration for reliable service management
- Lightweight deployment compared to full Kubernetes
- Self-hosted DNS and PKI for complete control over infrastructure
By following the maintenance procedures and security considerations outlined in this guide, you can ensure that your DNS and certificate authority services remain reliable, secure, and properly managed over time.