--- title: "Cómo crear una CA privada con step-ca en Ubuntu 24.04" description: "Instala step-ca de Smallstep en Ubuntu 24.04, ejecútalo con systemd y emite certificados TLS internos con el CLI step y por ACME con Certbot y renovación." category: "SSL/TLS y Certificados" language: es source: https://cubepath.com/es/docs/ssl-tls-y-certificados/step-ca-autoridad-de-certificados-privada updated: 2026-09-25 --- # Cómo crear una CA privada con step-ca en Ubuntu 24.04 step-ca es una autoridad de certificados (CA) de código abierto de Smallstep pensada para emitir certificados TLS internos de forma automatizada. Incluye un servidor ACME, el mismo protocolo que usa Let's Encrypt, así que herramientas como Certbot pueden pedir y renovar certificados para nombres internos que ninguna CA pública firmaría. En esta guía instalarás step-ca en Ubuntu 24.04, lo ejecutarás como servicio systemd, emitirás un certificado con el CLI `step` y configurarás Certbot en otro servidor para obtener certificados de tu CA por ACME. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS para la CA, por ejemplo un VPS de CubePath, con un usuario no root con privilegios `sudo`. Con 1 GB de RAM es suficiente. - Un nombre DNS interno para la CA que resuelva a su IP privada. En los ejemplos se usa `ca.example.internal`. - Para la parte de ACME, un segundo servidor con Ubuntu 24.04 y Nginx, con un nombre que la CA pueda resolver (`app.example.internal` en los ejemplos) y el puerto 80 accesible desde la CA. - Una red privada entre ambos servidores. Sustituye `10.10.0.0/24` por tu rango privado. Sustituye `ca.example.internal`, `app.example.internal` y `admin@example.com` por tus propios valores. ## Paso 1: Instalar step-ca y el CLI step Smallstep publica un repositorio APT firmado con ambos paquetes: `step-ca` (el servidor) y `step-cli` (el cliente, que se usa con el comando `step`). Descarga la clave del repositorio: ```bash sudo apt update sudo apt install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/keyrings/smallstep.asc ``` Añade el repositorio en formato deb822: ```bash sudo tee /etc/apt/sources.list.d/smallstep.sources > /dev/null <<'EOF' Types: deb URIs: https://packages.smallstep.com/stable/debian Suites: debs Components: main Signed-By: /etc/apt/keyrings/smallstep.asc EOF ``` Instala los paquetes: ```bash sudo apt update sudo apt install step-cli step-ca ``` Comprueba las versiones y la ruta del binario del servidor, que usarás en la unidad de systemd: ```bash step version step-ca version command -v step-ca ``` ```output Smallstep CLI/0.28.7 (linux/amd64) Release Date: 2026-07-10 18:12 UTC Smallstep CA/0.28.4 (linux/amd64) Release Date: 2026-07-02 21:40 UTC /usr/bin/step-ca ``` Tus números de versión pueden ser distintos. ## Paso 2: Crear el usuario de servicio y la contraseña step-ca no necesita privilegios de root. Crea un usuario de sistema `step` cuyo directorio será `/etc/step-ca`, donde vivirán la configuración, las claves y la base de datos: ```bash sudo useradd --system --user-group --home-dir /etc/step-ca --shell /usr/sbin/nologin step sudo install -d -m 0700 -o step -g step /etc/step-ca ``` Genera una contraseña aleatoria para cifrar las claves privadas de la CA. El servicio la leerá de este archivo al arrancar: ```bash openssl rand -base64 32 | sudo -u step tee /etc/step-ca/password.txt > /dev/null sudo chmod 400 /etc/step-ca/password.txt ``` ## Paso 3: Inicializar la CA `step ca init` crea una CA raíz, una CA intermedia (que es la que firma los certificados) y la configuración del servidor. Ejecútalo como el usuario `step`, con `STEPPATH` apuntando a `/etc/step-ca`: ```bash sudo -u step env STEPPATH=/etc/step-ca step ca init \ --deployment-type standalone \ --name "Example Internal CA" \ --dns ca.example.internal \ --address :9000 \ --provisioner admin@example.com \ --password-file /etc/step-ca/password.txt \ --acme ``` Qué significa cada opción: - `--name`: nombre que aparecerá en los certificados raíz e intermedio. - `--dns`: nombres (o IPs) con los que los clientes contactarán con la CA. Debe coincidir con la URL que usarás después. - `--address :9000`: la CA escucha en el puerto 9000 de todas las interfaces. - `--provisioner`: crea un provisioner JWK con ese nombre, protegido con la misma contraseña. Los provisioners son los métodos autorizados para pedir certificados. - `--acme`: crea además un provisioner ACME llamado `acme`. Al final verás la huella (fingerprint) del certificado raíz. Apúntala, los clientes la necesitan para confiar en la CA: ```output Root certificate: /etc/step-ca/certs/root_ca.crt Root private key: /etc/step-ca/secrets/root_ca_key Root fingerprint: 2a8f1c0e9b7d4c3e... Intermediate certificate: /etc/step-ca/certs/intermediate_ca.crt Intermediate private key: /etc/step-ca/secrets/intermediate_ca_key Database folder: /etc/step-ca/db Default configuration: /etc/step-ca/config/defaults.json Certificate Authority configuration: /etc/step-ca/config/ca.json ``` Si necesitas consultarla más tarde: ```bash sudo step certificate fingerprint /etc/step-ca/certs/root_ca.crt ``` ## Paso 4: Ajustar la validez de los certificados ACME Por defecto step-ca emite certificados de 24 horas. Es una buena práctica para el CLI `step`, que renueva con frecuencia, pero Certbot está pensado para certificados de 90 días y los renovaría en cada ejecución. Amplía la validez solo para el provisioner ACME. ```bash sudo -u step nano /etc/step-ca/config/ca.json ``` Busca el provisioner de tipo `ACME` dentro de `authority.provisioners` y añádele el bloque `claims`: ```json { "type": "ACME", "name": "acme", "claims": { "defaultTLSCertDuration": "2160h", "maxTLSCertDuration": "2160h" } } ``` `2160h` equivale a 90 días. Comprueba que el archivo sigue siendo JSON válido: ```bash sudo python3 -m json.tool /etc/step-ca/config/ca.json > /dev/null && echo "JSON OK" ``` ```output JSON OK ``` ## Paso 5: Ejecutar step-ca como servicio systemd Crea la unidad de systemd: ```bash sudo nano /etc/systemd/system/step-ca.service ``` ```ini [Unit] Description=step-ca certificate authority Documentation=https://smallstep.com/docs/step-ca After=network-online.target Wants=network-online.target ConditionFileNotEmpty=/etc/step-ca/config/ca.json ConditionFileNotEmpty=/etc/step-ca/password.txt [Service] Type=simple User=step Group=step Environment=STEPPATH=/etc/step-ca WorkingDirectory=/etc/step-ca ExecStart=/usr/bin/step-ca config/ca.json --password-file password.txt ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure RestartSec=5 NoNewPrivileges=yes ProtectSystem=full ProtectHome=yes PrivateTmp=yes ReadWritePaths=/etc/step-ca/db [Install] WantedBy=multi-user.target ``` `ProtectSystem=full` monta `/etc` como solo lectura para el servicio; `ReadWritePaths` deja escribir en la base de datos, que es lo único que step-ca modifica en funcionamiento. Arranca y habilita el servicio: ```bash sudo systemctl daemon-reload sudo systemctl enable --now step-ca sudo systemctl status step-ca --no-pager ``` ```output ● step-ca.service - step-ca certificate authority Loaded: loaded (/etc/systemd/system/step-ca.service; enabled; preset: enabled) Active: active (running) since Fri 2026-09-25 10:00:00 UTC; 3s ago ``` Permite el acceso al puerto 9000 solo desde tu red privada: ```bash sudo ufw allow from 10.10.0.0/24 to any port 9000 proto tcp ``` Comprueba el endpoint de salud. La CA siempre sirve HTTPS con un certificado firmado por su propia raíz, así que indica a `curl` en qué raíz confiar: ```bash curl --cacert /etc/step-ca/certs/root_ca.crt https://ca.example.internal:9000/health ``` ```output {"status":"ok"} ``` ## Paso 6: Configurar un cliente y confiar en la CA En el servidor de aplicación (`app.example.internal`), instala `step-cli` añadiendo el mismo repositorio que en el paso 1 y ejecutando `sudo apt install step-cli`. Configura el CLI para usar tu CA. `bootstrap` descarga el certificado raíz y comprueba que su huella coincide con la que anotaste en el paso 3, así no confías en una CA suplantada: ```bash step ca bootstrap --ca-url https://ca.example.internal:9000 --fingerprint your_root_fingerprint ``` ```output The root certificate has been saved in /home/your_user/.step/certs/root_ca.crt. The authority configuration has been saved in /home/your_user/.step/config/defaults.json. ``` Instala la raíz en el almacén de confianza del sistema para que `curl`, Certbot y el resto de programas confíen en los certificados de tu CA: ```bash sudo step certificate install "$(step path)/certs/root_ca.crt" ``` Compruébalo sin `--cacert`: ```bash curl https://ca.example.internal:9000/health ``` ```output {"status":"ok"} ``` ## Paso 7: Emitir un certificado con el CLI step Para certificados puntuales (un servicio interno, una prueba) puedes usar directamente el provisioner JWK. Te pedirá la contraseña del provisioner, que es la de `/etc/step-ca/password.txt`: ```bash step ca certificate app.example.internal app.crt app.key ``` Inspecciona el resultado: ```bash step certificate inspect app.crt --short ``` ```output X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2841...9173] Subject: app.example.internal Issuer: Example Internal CA Intermediate CA Provisioner: admin@example.com [ID: 7Rh3...Qe0k] Valid from: 2026-09-25T10:05:12Z to: 2026-09-26T10:06:12Z ``` El certificado dura 24 horas. Se renueva con el propio certificado como credencial, sin volver a pedir la contraseña: ```bash step ca renew --force app.crt app.key ``` Para uso continuado es más cómodo ACME, que es lo que configuras a continuación. ## Paso 8: Obtener certificados por ACME con Certbot En el servidor de aplicación, instala Certbot con el plugin de Nginx desde los repositorios de Ubuntu: ```bash sudo apt install certbot python3-certbot-nginx ``` Pide el certificado a tu CA indicando la URL del directorio ACME. El formato es `https:///acme//directory`: ```bash sudo certbot --nginx \ --server https://ca.example.internal:9000/acme/acme/directory \ -d app.example.internal \ --register-unsafely-without-email --agree-tos ``` step-ca valida el dominio con el desafío HTTP-01: se conecta a `http://app.example.internal/.well-known/acme-challenge/...`, así que la CA debe resolver ese nombre y llegar al puerto 80 del servidor de aplicación. ```output Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/app.example.internal/fullchain.pem ... Congratulations! You have successfully enabled HTTPS on https://app.example.internal ``` Certbot guarda la URL del servidor ACME en `/etc/letsencrypt/renewal/app.example.internal.conf`, y el temporizador `certbot.timer` renovará el certificado con tu CA cuando le queden menos de 30 días. Comprueba que la renovación funciona: ```bash sudo certbot renew --dry-run ``` ```output Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/app.example.internal/fullchain.pem (success) ``` Y comprueba el sitio desde cualquier máquina que confíe en tu raíz: ```bash curl -sI https://app.example.internal | head -n 1 ``` ```output HTTP/1.1 200 OK ``` > Nota: el Certbot de los repositorios de Ubuntu usa el almacén de confianza del sistema, por eso basta con haber instalado la raíz en el paso 6. Si usas Certbot instalado como snap, trae su propio almacén y debes indicarle la raíz con la variable `REQUESTS_CA_BUNDLE`. ## Solución de problemas Consulta siempre primero el log del servicio en el servidor de la CA: ```bash sudo journalctl -u step-ca -n 50 --no-pager ``` **El servicio no arranca y el log muestra un error al descifrar la clave intermedia.** El archivo `password.txt` no es el que se usó en `step ca init`, o se ha modificado. Debe contener exactamente la contraseña original. **`certificate signed by unknown authority` o `SSL certificate problem`.** El cliente no confía en tu raíz. Repite `step ca bootstrap` y `step certificate install` en ese equipo. **Certbot falla con `Connection refused` o timeout en el desafío.** La CA no llega al puerto 80 del servidor de aplicación. Comprueba desde la CA con `curl -I http://app.example.internal` y revisa DNS y firewall. **Certbot recibe un 404 al pedir el directorio ACME.** El nombre del provisioner en la URL no coincide con el de `ca.json`. Lista los que existen con `step ca provisioner list`. ## Conclusión Tienes una CA privada funcionando con step-ca como servicio systemd, clientes que confían en su raíz, emisión manual con el CLI `step` y certificados ACME renovados automáticamente por Certbot. La clave raíz (`/etc/step-ca/secrets/root_ca_key`) solo hace falta para firmar una nueva CA intermedia, así que el siguiente paso recomendado es hacer una copia cifrada fuera del servidor y eliminarla de él. También puedes usar la misma CA para autenticación mTLS entre servicios o para certificados SSH con step-ca.