Añadir una CA propia al almacén de confianza de Ubuntu
Cree una CA privada con openssl, firme un certificado de servidor e instale la raíz en /usr/local/share/ca-certificates para confiar en HTTPS interno.
Añada su propia CA al almacén de confianza de Ubuntu
Para añadir su propia CA al almacén de confianza de Ubuntu, copie el certificado raíz en /usr/local/share/ca-certificates/ con un nombre que termine en .crt y ejecute sudo update-ca-certificates. Una CA (autoridad certificadora) es un par de claves cuyo certificado puede firmar otros certificados. Cuando la máquina confía en su raíz, acepta todos los certificados firmados por esa raíz. Así, HTTPS entre sus propios servicios deja de fallar durante la verificación.
Esta guía crea toda la cadena sin conexión mediante openssl. Creará una clave raíz y un certificado raíz, emitirá un certificado de entidad final para un servidor y, después, instalará la raíz y comprobará cómo cambia la respuesta del mismo comando de verificación. Ese orden es importante: verificar antes y después de la instalación permite comprobar que la instalación es la que cambió el resultado.
Ubuntu 24.04 incluye OpenSSL 3 y el paquete ca-certificates en una imagen predeterminada, por lo que no es necesario instalar nada previamente (comprobado en agosto de 2026).
¿Cuándo debería ejecutar su propia CA?
Una CA pública como Let's Encrypt necesita un nombre en DNS público y un servidor al que pueda acceder. Los nombres internos no cumplen este requisito. Una base de datos en una red privada o un panel de administración asociado a un túnel no puede obtener un certificado público. Tampoco debería exponerse a Internet sólo para conseguirlo.
Un certificado autofirmado en Ubuntu resuelve el problema de un solo host. Cada cliente debe confiar en ese certificado, y el siguiente host requiere repetir el mismo trabajo. Una CA privada eleva la decisión un nivel. Los clientes confían una vez en la raíz y, a partir de entonces, confían en todos los certificados que firma la raíz, incluidos los certificados de hosts que todavía no existen.
El coste es real. La clave raíz puede firmar cualquier cosa que permitan las restricciones. Por tanto, quien lea ca.key puede emitir certificados que sus máquinas aceptarán. Protégela como protege una clave privada en la gestión de claves SSH. Si un servicio tiene un nombre DNS público, omita todo esto y use una CA pública: Certbot con nginx y Let's Encrypt requiere menos trabajo y no necesita instalar nada en el lado del cliente.
Cree la clave de la CA y el certificado raíz
Trabaje en un directorio que sólo su usuario pueda abrir. La clave raíz nunca debe salir de él.
install -d -m 700 ~/ca
cd ~/ca
openssl genrsa -aes256 -out ca.key 4096
chmod 600 ca.key-aes256 cifra la clave con una frase de contraseña que usted elige, y todos los comandos posteriores que firmen con esta clave la solicitan. Si omite -aes256, la clave queda almacenada en disco sin cifrar. En ese caso, una copia de seguridad o una segunda cuenta de administrador bastan para permitir que alguien emita certificados en los que sus máquinas confían.
Ahora cree el certificado raíz, que la clave de la CA firma para sí misma.
openssl req -x509 -new -key ca.key -sha256 -days 3650 \
-subj "/O=Example Internal/CN=Example Internal Root CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-addext "subjectKeyIdentifier=hash" \
-addext "nameConstraints=critical,permitted;DNS:internal.example" \
-out ca.crtSustituya internal.example por el sufijo de nombre que utilice realmente y lea la sección siguiente antes de conservar esa última extensión.
Cada extensión cumple una función.
basicConstraintsconCA:TRUEconvierte este certificado en un certificado de CA. Sin ellos, un cliente rechaza cualquier certificado firmado por esta clave, aunque la firma sea correcta.pathlen:0indica que la CA puede firmar certificados finales, pero no otras CA subordinadas.keyUsagelimita la clave a la firma de certificados y listas de revocación. Así se evita utilizar por error la misma clave como clave de servidor TLS.subjectKeyIdentifierproporciona a la raíz un identificador al que apuntan los certificados finales. Así, un cliente puede encontrar el emisor correcto dentro de un almacén que contiene varios cientos de certificados.nameConstraintslimita los nombres que esta CA puede validar.
Revise lo que ha creado en lugar de asumir que el comando hizo lo que pretendía.
openssl x509 -noout -subject -issuer -serial -dates -in ca.crt
openssl x509 -noout -text -in ca.crtSubject e issuer muestran la misma cadena porque un certificado raíz se firma a sí mismo. El número de serie y las dos fechas proceden del archivo que acaba de crear. Por tanto, obténgalos de esa salida y no de una guía externa.
Limite lo que su CA puede firmar
Una raíz del almacén del sistema es de confianza para cualquier nombre de Internet, salvo que indique lo contrario. Es una autoridad considerable para mantenerla en un solo archivo de un solo servidor. nameConstraints la reduce. Con permitted;DNS:internal.example en la raíz, se rechaza una cadena de esta CA para un nombre fuera de internal.example, aunque la firma sea válida.
Póngalo a prueba en lugar de confiar en ella.
openssl req -new -newkey rsa:2048 -nodes -keyout /tmp/outside.key -out /tmp/outside.csr \
-subj "/CN=www.example.com"
openssl x509 -req -in /tmp/outside.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-days 30 -sha256 \
-extfile <(printf 'subjectAltName=DNS:www.example.com\n') -out /tmp/outside.crt
openssl verify -CAfile ca.crt /tmp/outside.crt
echo $?El certificado se emite porque su CA firma todo lo que le pide. El fallo se produce durante la verificación: el estado de salida es distinto de cero y OpenSSL indica la restricción que se ha incumplido. Ese es el valor de la extensión. Aunque roben la clave de la CA, no podrán generar un certificado funcional para un nombre fuera del subárbol. Cuando termine, elimine los archivos restantes con rm /tmp/outside.*.
Antes de aplicar una restricción, debe conocer cuatro aspectos. Está marcada como critical, por lo que un cliente que no entienda la extensión debe rechazar la cadena en lugar de ignorarla. Es la opción más segura, pero puede causar problemas con una biblioteca TLS antigua. Un subárbol permitido para nombres DNS no restringe los SAN de direcciones IP, porque un tipo de nombre sin un subárbol definido permanece sin restricciones. Por tanto, añada permitted;IP:10.0.0.0/255.255.0.0 en la misma extensión si sus certificados incluyen direcciones IP. El subárbol debe cubrir todos los nombres que pueda emitir, incluidos los nombres de host cortos. Por eso, un certificado para el nombre simple app fallaría con el ejemplo anterior. Además, la restricción queda integrada en la raíz. Si cambia de criterio, necesitará un certificado raíz nuevo y deberá instalarlo de nuevo en todos los clientes.
Emita un certificado leaf firmado por su CA
Un certificado leaf es el certificado que un servidor presenta a los clientes. Empiece por su propia clave y una CSR (solicitud de firma de certificado), que contiene la clave pública y el nombre solicitado. La CSR está firmada con la clave del certificado leaf para demostrar que quien realiza la solicitud posee la parte privada.
openssl req -new -newkey rsa:2048 -nodes \
-keyout app.key -out app.csr \
-subj "/CN=app.internal.example"
chmod 600 app.keyLos nombres relevantes deben ir en un archivo de extensión, no en la CSR. Los clientes comparan el nombre de host con subjectAltName (SAN) e ignoran por completo el nombre común. Por tanto, un certificado con CN pero sin SAN falla la verificación del nombre de host en todos los clientes actuales, independientemente del valor de CN.
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:app.internal.example, DNS:api.internal.example
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:alwaysGuárdelo como app.ext y firme la solicitud con la CA.
openssl x509 -req -in app.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-days 397 -sha256 -extfile app.ext -out app.crt-CAcreateserial escribe ca.srl junto a la CA. Este archivo contiene el siguiente número de serie, para que ningún certificado emitido por esta CA comparta el mismo número. Mantenga el archivo en el directorio de la CA. -days 397 es una elección, no un límite de la herramienta. En este caso, las duraciones cortas son más importantes que con una CA pública, porque una CA privada no tiene infraestructura de revocación. No hay una CRL ni un respondedor OCSP, a menos que configure uno. Por tanto, una clave leaf filtrada sigue siendo utilizable hasta que caduque el certificado.
Compruebe el resultado antes de modificar el almacén de confianza.
openssl x509 -noout -subject -issuer -serial -dates -in app.crt
openssl x509 -noout -ext subjectAltName -in app.crtLa línea issuer ahora identifica la CA en lugar del propio certificado leaf. La línea SAN muestra los nombres para los que es válido el certificado. El cliente compara el nombre únicamente con esa lista.
Verifique con un -CAfile explícito antes de instalar nada
openssl verify -CAfile ca.crt app.crt
echo $?Esto plantea una única pregunta concreta: ¿app.crt forma una cadena válida hasta el certificado de ca.crt? No indica en absoluto en qué confía esta máquina, porque se indicó la raíz a OpenSSL en la línea de comandos. Si la verificación falla, el problema está en los propios certificados. Corríjalo antes de continuar.
Ahora consulte a la máquina.
openssl verify app.crt
echo $?Sin -CAfile, OpenSSL usa el directorio de certificados integrado de forma predeterminada. openssl version -d muestra el directorio base que utiliza la compilación y, en Ubuntu, el directorio certs que se encuentra debajo se resuelve en /etc/ssl/certs. La raíz todavía no está allí, por lo que la verificación falla: la cadena llega a una entidad emisora que el almacén no contiene y ya no queda ningún otro lugar donde buscar. Anote el estado de salida. Es lo que cambiará dentro de dos pasos.
Un cliente real es una prueba mejor que openssl verify, porque comprueba el nombre de host además de la cadena. Sirva el certificado y obténgalo.
openssl s_server -accept 8443 -cert app.crt -key app.key -www &
curl --resolve app.internal.example:8443:127.0.0.1 https://app.internal.example:8443/--resolve dirige la conexión a 127.0.0.1, pero sigue solicitando app.internal.example, por lo que el SAN coincide y la única cuestión pendiente es la confianza. curl falla e imprime el motivo por el que no pudo verificar la cadena. Añada -v para obtener más detalles. Deje el servidor de prueba en ejecución.
Instale el certificado raíz en /usr/local/share/ca-certificates
sudo cp ca.crt /usr/local/share/ca-certificates/example-internal-root.crt
sudo chmod 644 /usr/local/share/ca-certificates/example-internal-root.crt
sudo update-ca-certificatesEstos son los detalles que determinan si el proceso funciona:
- El nombre de archivo debe terminar en
.crt. La página del manual deupdate-ca-certificatesindica que los certificados con extensión.crtencontrados dentro de/usr/local/share/ca-certificatesse incluyen y se consideran confiables implícitamente. Un archivo llamadoroot.pemoroot.cerse omite sin mostrar ningún mensaje. - El contenido debe estar en formato PEM, es decir, el bloque base64 delimitado por las líneas
BEGIN CERTIFICATEyEND CERTIFICATE. Un archivo DER renombrado a.crtsigue siendo binario y no se lee. Conviértalo conopenssl x509 -inform DER -in ca.der -out ca.crt. - Aquí sólo debe instalarse el certificado raíz. La clave privada de la CA y el certificado final no deben estar en un almacén de confianza.
update-ca-certificates muestra cuántos certificados agregó y eliminó. Si no agregó ninguno, la causa es la extensión o el formato del archivo.
Confirme el cambio desde el sistema, no sólo a partir de ese mensaje.
ls -l /etc/ssl/certs/$(openssl x509 -noout -subject_hash -in /usr/local/share/ca-certificates/example-internal-root.crt).0
grep -c 'BEGIN CERTIFICATE' /etc/ssl/certs/ca-certificates.crtEl primer comando construye un nombre de archivo a partir del hash del subject del certificado y lo muestra. update-ca-certificates creó ese enlace simbólico, que apunta de nuevo al archivo instalado. El segundo comando cuenta los certificados del bundle de un solo archivo. Ejecútelo también antes de la instalación para comprobar si el número aumenta en uno.
Cuando copie este certificado raíz a otros equipos, compruebe que la copia llegó intacta antes de instalarla. Un certificado raíz es uno de los archivos más importantes del sistema que se pueden copiar incorrectamente, así que trátelo como cualquier otra descarga que debe verificar con una suma de comprobación antes de usarla.
Vuelva a verificar con el almacén del sistema
openssl verify app.crt
echo $?
curl --resolve app.internal.example:8443:127.0.0.1 https://app.internal.example:8443/Los mismos comandos y los mismos archivos de certificado producen una respuesta diferente. No cambió nada en app.crt y el servidor es el que inició antes. La única diferencia es que ahora la raíz está en el almacén que consultan esos clientes, por lo que la cadena se completa. Este es el mecanismo que conviene recordar: la verificación busca un emisor en el que el cliente ya confía, e instalar una CA incorpora ese emisor al lugar que el cliente consulta.
Detenga el servidor de prueba con kill %1.
Por qué /etc/ssl/certs no es el lugar donde debe poner su archivo
/etc/ssl/certs es una salida generada. update-ca-certificates la llena con enlaces simbólicos a los archivos de certificados reales y escribe el paquete concatenado /etc/ssl/certs/ca-certificates.crt junto a ellos.
Nada encuentra un certificado que copie manualmente en ese directorio. La búsqueda de directorios de OpenSSL sólo abre archivos cuyos nombres se basan en el hash del sujeto del certificado, por lo que un archivo llamado myca.crt no es visible para OpenSSL. En Ubuntu, curl lee el archivo de paquete, que se vuelve a generar a partir de las fuentes registradas. Por tanto, su copia tampoco se incluye en esa ruta. Al ejecutar update-ca-certificates --fresh, se eliminan y se vuelven a crear los enlaces simbólicos del directorio, incluidos los enlaces creados manualmente.
La otra parte de esta separación es /usr/share/ca-certificates, que pertenece al paquete ca-certificates y aparece en /etc/ca-certificates.conf. Las actualizaciones del paquete lo sobrescriben. /usr/local/share/ca-certificates es el directorio reservado para el administrador local, por lo que su CA se conserva durante todas las actualizaciones del paquete que administra el resto.
Qué programas ignoran el almacén de confianza del sistema
Instalar la raíz corrige el problema en todos los programas que solicitan certificados a OpenSSL o leen /etc/ssl/certs. Esto incluye curl, wget, git, el módulo estándar ssl de Python y los programas escritos en Go, que leen los archivos del sistema en Linux. Los entornos de ejecución que incluyen su propia lista de certificados no se ven afectados. De ahí procede gran parte de la confusión después de una instalación correcta.
- Node.js usa una lista compilada en el programa. Indíquele el certificado raíz mediante
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/example-internal-root.crty defínalo en el entorno antes de iniciar el proceso, porque Node lee la variable una sola vez durante el arranque. Las versiones actuales de Node también tienen una opción para leer el almacén del sistema. Ejecutenode --help | grep -i system-capara comprobar si su versión la incluye. - La biblioteca
requestsde Python usa el paquete de certificadoscertifi. DefinaREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crtpara ese proceso o paseverify="/etc/ssl/certs/ca-certificates.crt"a la llamada.pipacepta--certpor el mismo motivo. - Java lee un almacén de claves. En Ubuntu, el paquete
ca-certificates-javainstala un hook en/etc/ca-certificates/update.d/. Por eso, cuando el paquete está instalado,update-ca-certificatestambién actualiza el almacén de claves de Java. Si no está instalado, importe el certificado raíz conkeytool -importcert. - Firefox mantiene su propio almacén y nunca consulta
/etc/ssl/certs. Importe el certificado desde su configuración de certificados. Chromium en Linux lee una base de datos NSS por usuario, que se edita concertutildel paquetelibnss3-tools. - Los contenedores tienen su propio sistema de archivos, por lo que el almacén del host no tiene ningún efecto dentro de ellos. Copie el certificado raíz en la imagen y ejecute
update-ca-certificatesdurante la compilación. Téngalo en cuenta si sus servicios se ejecutan mediante Docker Compose en un VPS.
Si un programa sigue rechazando el certificado después de una instalación correcta, averigüe qué archivos abre antes de cambiar cualquier otra cosa. strace -f -e trace=openat <command> 2>&1 | grep -i cert es una herramienta directa y responde a esa pregunta en una sola ejecución.
Mantener la CA utilizable con el tiempo
Volver a emitir un certificado leaf consiste en repetir los pasos de CSR y de firma con el mismo archivo app.ext. Los clientes no necesitan realizar ninguna acción, porque la raíz en la que confían no ha cambiado. Conserve ca.srl y todos los archivos .ext en el directorio de la CA para que la siguiente emisión consista en repetir un comando que ya funcionó, en lugar de reconstruir el proceso de memoria.
Haga una copia de seguridad de ca.key y ca.crt en una ubicación externa al equipo y manténgala cifrada. Si pierde la clave, no podrá emitir nada nuevo: tendrá que crear una segunda CA e instalar su raíz en todos los lugares donde estaba instalada la primera. Mantenga una lista escrita de cada equipo y cada almacén de aplicaciones que recibió la raíz, porque esa lista es imprescindible para poder rotarla y retirarla.
Cuando la propia raíz se aproxime a su fecha de expiración, genere pronto el reemplazo e instale ambas raíces en paralelo. No hay problema en tener dos raíces en el almacén, y un cliente acepta cualquiera de ellas. Vuelva a emitir los certificados leaf con la nueva raíz y retire la antigua cuando ningún elemento dependa ya de ella.
Eliminar una CA del almacén de confianza
sudo rm /usr/local/share/ca-certificates/example-internal-root.crt
sudo update-ca-certificates --fresh--fresh elimina los enlaces simbólicos de /etc/ssl/certs y los vuelve a crear a partir de las fuentes que siguen presentes. De este modo, la raíz eliminada desaparece tanto del directorio como del paquete. Confirme la eliminación del mismo modo que confirmó la instalación.
openssl verify app.crt
echo $?
grep -c 'BEGIN CERTIFICATE' /etc/ssl/certs/ca-certificates.crt
ls -l /etc/ssl/certs/$(openssl x509 -noout -subject_hash -in ~/ca/ca.crt).0La verificación vuelve a fallar, el recuento de certificados recupera el valor inicial y el enlace simbólico basado en el hash ha desaparecido.
Ese comando modifica únicamente el almacén del sistema. Deshaga manualmente la instalación en cada uno de los demás lugares: vacíe NODE_EXTRA_CA_CERTS, elimine el alias de cualquier almacén de claves de Java, quite la raíz de cada perfil del navegador y vuelva a crear cualquier imagen de contenedor que la haya incluido. Eliminar la raíz tampoco invalida los certificados que firmó. Siguen siendo válidos en todos los equipos que todavía confían en ella. Por eso, en la práctica, una CA privada necesita una lista escrita de todos los lugares donde se instaló la raíz. Una CA que no se puede retirar por completo es una brecha permanente. Pruebe la eliminación en un equipo el mismo día en que configure la CA, mientras la lista todavía sea corta.
FAQ
¿Dónde coloco un certificado de CA en Ubuntu?
Colóquelo en /usr/local/share/ca-certificates/, con un nombre de archivo que termine en .crt y contenido PEM; después ejecute sudo update-ca-certificates. Ese directorio está reservado para el administrador local, por lo que las actualizaciones de paquetes no lo modifican. /usr/share/ca-certificates pertenece al paquete ca-certificates y /etc/ssl/certs se genera a partir de ambos. Por eso, un archivo colocado en cualquiera de esos dos directorios se sobrescribe o se ignora.
¿Por qué curl sigue rechazando el certificado después de ejecutar update-ca-certificates?
Compruebe las causas en este orden. Es posible que el archivo no termine en .crt o que esté en formato DER en lugar de PEM. En ese caso, update-ca-certificates lo omitió y no añadió nada. El certificado puede no tener un subjectAltName que coincida con el nombre de host. Eso es un fallo del nombre de host, no un fallo de confianza; compruébelo con openssl x509 -noout -ext subjectAltName -in app.crt. Es posible que el servidor sólo envíe el certificado final cuando también se necesita un certificado intermedio. curl puede estar configurado para usar otro bundle mediante CURL_CA_BUNDLE o --cacert. Además, un servicio de larga ejecución necesita reiniciarse, porque la mayoría de los programas leen el almacén de confianza una sola vez al iniciarse.
¿El almacén de confianza del sistema también cubre Firefox, Chrome, Node y Java?
No. curl, wget, git, el módulo estándar ssl de Python y los programas de Go leen los archivos del sistema, por lo que funcionan en cuanto se ejecuta update-ca-certificates. Firefox mantiene su propio almacén. Chromium en Linux usa una base de datos NSS por usuario, que se modifica con certutil del paquete libnss3-tools. Node.js necesita NODE_EXTRA_CA_CERTS apuntando al archivo de la CA raíz. Java lee un keystore, que update-ca-certificates actualiza sólo cuando está instalado el paquete ca-certificates-java. requests de Python usa certifi y necesita REQUESTS_CA_BUNDLE.
¿Cómo elimino una CA del almacén de confianza de Ubuntu?
Elimine el archivo de /usr/local/share/ca-certificates/ y ejecute sudo update-ca-certificates --fresh. La opción --fresh elimina los enlaces simbólicos de /etc/ssl/certs y los vuelve a crear, por lo que el certificado desaparece al mismo tiempo de los enlaces simbólicos hash y del bundle ca-certificates.crt. Confírmelo ejecutando openssl verify contra un certificado firmado por esa CA y comprobando el estado de salida. Después repita la eliminación en todos los demás almacenes donde la haya añadido, porque ese comando no modifica ninguno de ellos.
¿Puedo usar una CA privada en lugar de Let's Encrypt para un sitio público?
No. El navegador del visitante no conoce su raíz, por lo que muestra una advertencia a pantalla completa. Además, no puede instalar su raíz en equipos que no controla. Una CA privada se utiliza para nombres que sólo resuelven sus propios equipos y para clientes que administra. Para cualquier sitio que visite una persona externa, obtenga el certificado de una CA pública.