An open API service indexing awesome lists of open source software.

https://github.com/fdeantoni/knot-step-acme

An ACME setup using knot and step-ca
https://github.com/fdeantoni/knot-step-acme

acme-dns knot-dns step-ca

Last synced: 10 months ago
JSON representation

An ACME setup using knot and step-ca

Awesome Lists containing this project

README

          

# Knot DNS + Step CA ACME Development Environment

A Docker Compose setup that provides a local DNS server (Knot DNS) with ACME certificate authority (Step CA) for development and testing.

## Overview

This project sets up:

- **Knot DNS Server**: Authoritative DNS server for the `.test` domain
- **Step CA**: ACME-enabled certificate authority for issuing TLS certificates
- **Custom Network**: Isolated Docker network for service communication

## Architecture

```text
┌─────────────────┐ ┌─────────────────┐
│ Knot DNS │ │ Step CA │
│ 10.0.0.10:53 │◄───┤ 10.0.0.11:9000 │
│ │ │ │
│ • test. zone │ │ • ACME endpoint │
│ • ca.test → CA │ │ • ca.test cert │
└─────────────────┘ └─────────────────┘
```

## Quick Start

1. **Start the services:**

```bash
docker-compose up -d
# or rebuild everything with:
# docker compose up --build --force-recreate -d
```

2. **Wait for services to be healthy:**

```bash
docker-compose ps
```

3. **Test DNS resolution:**

```bash
dig @localhost -p 9053 ca.test A
```

4. **Access Step CA:**
- ACME directory: `https://ca.test:9000/acme/acme/directory`
- Root certificate: `https://ca.test:9000/roots.pem`

## Services

### Knot DNS (`knot`)

- **Port**: `9053` (mapped from container port 53)
- **IP**: `10.0.0.10` (internal network)
- **Zone file**: [`knot/test.zone`](knot/test.zone)
- **Config**: [`knot/knot.conf`](knot/knot.conf)

**DNS Records:**

- `ca.test.` → `10.0.0.11` (Step CA)
- `ns1.test.` → `10.0.0.10` (DNS server)

### Step CA (`step-ca`)

- **Port**: `9000`
- **IP**: `10.0.0.11` (internal network)
- **Domain**: `ca.test`
- **ACME Endpoint**: `/acme/acme/directory`

### Step Secrets (`step-secrets`)

- One-time service that generates CA password
- Creates `/home/step/secrets/password` with random password

## Configuration

### Default DNS Configuration

The Knot DNS server is configured in [`knot/knot.conf`](knot/knot.conf) with:

- Authority for `test.` domain
- HMAC-SHA256 key for dynamic updates automatically generated
- Forwarding to upstream DNS (1.1.1.1, 9.9.9.9) for other domains

### Default Step CA Configuration

- Automatically initialized on first run
- ACME provisioner enabled
- Certificate for `ca.test` domain
- Remote management enabled

### Enable Remote Access

By default everything runs on its own Docker network with DNS mapped to 0.0.0.0:9053 and step-ca mapped to 0.0.0.0:9000 so these are accessble on the hosts LAN IP. However, to make Knot DNS return the correct LAN IP address when queried for `ca.test`, you will need to reconfigure the test.zone file. You can do this as follows:

```bash
# First extract the tsig.key from Knot
./extract-tsig.sh

# Now switch to using the LAN IP for ca.test
./enable-remote.sh
```

### Configuring K3D

If you will run your K3D cluster on the same machine, you can tell it to use the knot and step-ca service:

```bash
k3d cluster create my-cluster \
--k3s-arg "--cluster-dns=10.0.0.10@server:*" \
--k3s-arg "--cluster-domain=cluster.local@server:*" \
--network knot-step-acme_lab \
--wait
```

If your K3D is running on another machine, you can instead tell K3D's CoreDNS to use your remote Knot instance instead. You can do so as follows:

```bash
# Create a config file pointing .test to your Knot instance
DNS_SERVER=""
cat > coredns_custom.yaml < -s
# Example:
./add-subdomain.sh -k ./tsig.key -s myapp
```
This creates: *.myapp.test → in Knot.

4) Test
```bash
dig @localhost -p 9053 app..test A
```

### Using with curl/ACME clients

1. **Get the tsig.key and CA root certificate:**

```bash
./extract-tsig.sh
```

2. **Use with certbot:**

```bash
docker run --rm -it \
--network knot-step-acme_lab \
--dns 10.0.0.10 \
-v $(pwd)/dev_root_ca.pem:/etc/certs/dev_root_ca.pem \
-e REQUESTS_CA_BUNDLE="/etc/certs/dev_root_ca.pem" \
certbot/certbot certonly \
--manual \
--server https://ca.test:9000/acme/acme/directory \
--preferred-challenges dns \
--work-dir /tmp --logs-dir /tmp --config-dir /etc/letsencrypt \
-d "example.test"
```

3. **Use nsupdate with TSIG key:**

```bash
# Create nsupdate script
cat > update.txt << EOF
server localhost 9053
zone test.
update add _acme-challenge.example.test. 60 IN TXT "your-acme-challenge-token"
send
quit
EOF

# Apply the update
nsupdate -k ./tsig.key update.txt

# Clean up
rm update.txt
```

### DNS Testing

```bash
# Test DNS resolution
dig @localhost -p 9053 test SOA
dig @localhost -p 9053 ca.test A
dig @localhost -p 9053 anything.test A

# Test from container network
docker run --rm --network knot-step-acme_lab alpine:latest \
nslookup ca.test 10.0.0.10
```

## Volumes

- `knot-db`: Persistent storage for Knot DNS zone files
- `step-data`: Persistent storage for Step CA configuration and certificates

## Network

- **Name**: `knot-step-acme_lab`
- **Subnet**: `10.0.0.0/24`
- **Gateway**: `10.0.0.1`

## Health Checks

Both services include health checks:

- **Knot**: Verifies DNS SOA response for `test.` domain
- **Step CA**: Verifies HTTPS endpoint accessibility

## Troubleshooting

### Check service logs

```bash
docker-compose logs knot
docker-compose logs step-ca
```

### Verify DNS resolution

```bash
# From host
dig @localhost -p 9053 ca.test A

# From container network
docker exec knot dig @127.0.0.1 ca.test A
```

### Test Step CA

```bash
# Check if CA is responding
curl -sk https://ca.test:9000/health

# Get CA roots
curl -sk https://ca.test:9000/roots.pem
```

### Reset everything

```bash
docker-compose down -v
docker-compose up -d
```

## File Structure

```text
.
├── docker-compose.yml # Main orchestration
├── knot/
│ ├── Dockerfile # Knot DNS container
│ ├── knot.conf # Knot DNS configuration
│ └── test.zone # DNS zone file
└── step-ca/
├── Dockerfile # Step CA container
└── start-step-ca.sh # Step CA initialization script
```

## Requirements

- Docker
- Docker Compose
- (Optional) `dig` command for testing

## Notes

- The `.test` TLD is reserved for testing (RFC 6761)
- Change IP addresses in [`knot/test.zone`](knot/test.zone) if needed for your environment
- Step CA generates a random password on first run, stored in the `step-data` volume
- Services depend on each other: Step CA waits for Knot DNS to be healthy