Smallstep + Caddy ACME Automated Certs
Smallstep ACME server + Caddy
Introducción al lab
Este proyecto muestra cómo montar una infraestructura de certificados automatizada usando smallstep‑ca y Caddy, con la que puedes emitir y renovar de forma segura los certificados TLS de tus servicios web. La idea es tener una Autoridad de Certificación privada, gestionada por ti, que se integra vía ACME con Caddy para que todo el proceso sea lo más transparente posible.
¿Para qué sirve?
Con esta solución puedes controlar totalmente la emisión de certificados dentro de tu red o dominio, sin depender exclusivamente de servicios públicos. Esto permite reforzar la seguridad, reducir costes a largo plazo, y aplicar políticas internas sobre la validez, revocación y distribución de los certificados.
¿Qué ventajas aporta?
-
Mayor control de tu infraestructura de confianza: defines quién puede emitir, cuándo expiran los certificados y cómo se revocan.
-
Automatización real: al integrar smallstep con Caddy vía ACME, los certificados se renuevan sin intervención manual.
-
Flexibilidad para entornos internos y públicos: tanto para servicios internos (“intranets”, APIs privadas) como para servicios accesibles desde el exterior.
-
Escalabilidad: puedes extender esta base para otros usos (SSH, servicios internos, IoT) más adelante.
Configuraciones iniciales y consideraciones
Para poder realizar solicitudes via ACME, debemos tener un DNS funcional y con las entradas DNS antes de solicitar el certificado.
Al menos debemos tener:
- entrada DNS de la CA (ej: ca.glmbx.home)
- Entrada DNS del servicio a certificar (apuntando nombre a la maquina donde está alojado el servicio / web)(en caso de usar caddy tiene que apuntar a caddy)
- Si usamos caddy, deben estar en lxc o vm distintas, ya que ambas usan el 80 y el 443, modificar esto complica aún mas el lab
La solicitud ACME debe ser realizada desde el equipo el cual se quiere certificar, para que el challenge pueda verificar que, el nombre asociado a la IP, es el mismo que está solicitando y tiene levantado el puerto 80 para resolver el challenge (en caso de http-01 challenge, que es el default). (salvo si usamos caddy, que debe apuntar a caddy)
Instalar e iniciar CA
Instalar en Alpine linux
apk update && apk upgrade
apk add step-cli step-certificates ca-certificates
Iniciar CA
Lanzamos el comando y rellenamos la info:
~ # step ca init
✔ Deployment Type: Standalone
What would you like to name your new PKI?
✔ (e.g. Smallstep): Glmbx Home CA
✔ (e.g. ca.example.com[,10.1.2.3,etc.]): ca.glmbx.home
What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)
✔ (e.g. :443 or 127.0.0.1:443): :443
What would you like to name the CA's first provisioner?
✔ (e.g. you@smallstep.com): eddygalamba@glmbx.home
Importar los certificados root e intermediate_ca al s.o:
apk add ca-certificates
cp .step/certs/* /usr/local/share/ca-certificates/
update-ca-certificates
# Iniciar por primera vez la CA
step-ca .step/config/ca.json
Agregar Provisioner ACME
step ca provisioner add acme-glmbx-home --type ACME
Prueba ACME
Ejemplo certificar Adguard
Desde adguard con step-cli instalado, teniendo los certificados root e intermediate importados(arriba se explica como), y la entrada DNS correctamente registrada (este caso asociando adguard.glmbx.home a la 192.168.1.102):
step ca certificate adguard.glmbx.home adguard.crt adguard.key --acme https://ca.glmbx.home:443/acme/acme-glmbx-home/directory
Caddy Proxy Server + ACME
En este apartado no se explica como instalar caddy, directamente vamos a la configuracion, para usar Caddy como proxy inverso, y automatizar la solicitud y renovacion de certificados automaticamente.
Certificado accesible para caddy
Debemos descargar el root_ca.crt de la CA y pasarlo a Caddy
mkdir -p /etc/ssl/step
cp ./root_ca.crt /etc/ssl/step/
chown caddy:caddy /etc/ssl/step/root_ca.crt
chmod 644 /etc/ssl/step/root_ca.crt
Caddyfile
El caddyfile es donde agergaremos las entradas para nuestros sitios web
# /etc/caddy/Caddyfile
{
email eddygalamba@glmbx.home
acme_ca https://ca.glmbx.home:443/acme/acme-glmbx-home/directory
acme_ca_root /etc/ssl/step/root_ca.crt
http_port 80
https_port 443
}
adguard.glmbx.home {
reverse_proxy 192.168.1.102:80
}
cloud.glmbx.home {
reverse_proxy 192.168.1.103:80
}
Lanzar Caddy
Para lanzar por primera vez y ver el output, detectar posibles problemas:
caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
Iniciar servicios automaticamente
Step CA
Creamos el fichero /etc/step-ca/password.txt con la clave que pusimos al crear la CA
touch /etc/step-ca/password.txt
echo "Micontraseña" > /etc/step-ca/password.txt
Creamos el fichero de servicio /etc/init.d/step-ca, si existe, lo sobreescribimos con el siguiente contenido:
#!/sbin/openrc-run
description="Smallstep Certificate Authority"
command="/usr/bin/step-ca"
command_args="/root/.step/config/ca.json --password-file /etc/step-ca/password.txt"
command_background="yes"
pidfile="/run/step-ca.pid"
name="step-ca"
command_user="root:root"
depend() {
need net
}
start_pre() {
checkpath --directory /var/log/step-ca --mode 0755
}
start() {
ebegin "Starting Step CA"
start-stop-daemon --start --quiet \
--background \
--make-pidfile \
--pidfile "${pidfile}" \
--exec ${command} -- ${command_args}
eend $?
}
stop() {
ebegin "Stopping Step CA"
start-stop-daemon --stop --quiet --pidfile "${pidfile}"
eend $?
}
Iniciamos y lo establecemos al inicio
rc-update add step-ca default
rc-service start step-ca
Caddy
Creamos el fichero /etc/init.d/caddy (o sobreescribimos su contenido) con:
#!/sbin/openrc-run
/etc/init.d # cat caddy
#!/sbin/openrc-run
description="Caddy Web Server"
command="/usr/sbin/caddy"
command_args="run --config /etc/caddy/Caddyfile --adapter caddyfile"
command_background="yes"
pidfile="/run/caddy.pid"
name="caddy"
depend() {
need net
use dns logger
}
start_pre() {
checkpath --directory /var/log/caddy --mode 0755
}
start() {
ebegin "Starting Caddy"
start-stop-daemon --start --quiet \
--background \
--make-pidfile \
--pidfile "${pidfile}" \
--exec ${command} -- ${command_args}
eend $?
}
stop() {
ebegin "Stopping Caddy"
start-stop-daemon --stop --quiet --pidfile "${pidfile}"
eend $?
}
Iniciamos y lo establecemos al inicio
rc-update add caddy default
rc-service start caddy