Habilitar HTTPS automático con Caddy en un contenedor sidecar
En este artículo se describe cómo Caddy se puede usar como un contenedor sidecar en un grupo de contenedores y actuar como un proxy inverso para proporcionar un punto de conexión HTTPS administrado automáticamente para la aplicación.
Caddy es un potente servidor web de código abierto, preparado para empresas, con HTTPS automático, escrito en Go y, además, constituye una alternativa a Nginx.
La automatización de certificados es posible porque Caddy admite la API ACMEv2 (RFC 8555) que interactúa con Let's Encrypt para emitir certificados.
En este ejemplo, solo el contenedor Caddy se expone en los puertos 80/TCP y 443/TCP. La aplicación detrás del proxy inverso permanece privada. La comunicación de red entre Caddy y la aplicación se produce a través de localhost.
Nota
Esto contrasta con la comunicación intragrupo de contenedores conocida de Docker Compose, donde se puede hacer referencia a los contenedores mediante su nombre.
En el ejemplo se monta Caddyfile, necesario para configurar el proxy inverso, desde un recurso compartido de archivos hospedado en una cuenta de Azure Storage.
Nota
Para las implementaciones de producción, la mayoría de los usuarios querrán simular mediante "bake" el Caddyfile en una imagen Docker personalizada basada en caddy. De este modo, no es necesario montar archivos en el contenedor.
Prerrequisitos
Use el entorno de Bash en Azure Cloud Shell. Para más información, consulte Inicio rápido para Bash en Azure Cloud Shell.
Si prefiere ejecutar comandos de referencia de la CLI localmente, instale la CLI de Azure. Si utiliza Windows o macOS, considere la posibilidad de ejecutar la CLI de Azure en un contenedor Docker. Para más información, vea Ejecución de la CLI de Azure en un contenedor de Docker.
Si usa una instalación local, inicie sesión en la CLI de Azure mediante el comando az login. Siga los pasos que se muestran en el terminal para completar el proceso de autenticación. Para ver otras opciones de inicio de sesión, consulte Inicio de sesión con la CLI de Azure.
En caso de que se le solicite, instale las extensiones de la CLI de Azure la primera vez que la use. Para más información sobre las extensiones, consulte Uso de extensiones con la CLI de Azure.
Ejecute az version para buscar cuál es la versión y las bibliotecas dependientes que están instaladas. Para realizar la actualización a la versión más reciente, ejecute az upgrade.
- En este artículo se necesita la versión 2.0.55, o versiones posteriores, de la CLI de Azure. Si usa Azure Cloud Shell, ya está instalada la versión más reciente.
Preparar Caddyfile
Cree un archivo denominado Caddyfile
y pegue la siguiente configuración. Esta configuración crea una configuración de proxy inverso que apunta al contenedor de aplicaciones que escucha en 5000/TCP.
my-app.westeurope.azurecontainer.io {
reverse_proxy http://localhost:5000
}
Es importante tener en cuenta que la configuración hace referencia a un nombre de dominio en lugar de a una dirección IP. Caddy necesita ser accesible mediante esta URL para llevar a cabo el paso de desafío que requiere el protocolo ACME y para recuperar con éxito un certificado de Let's Encrypt.
Nota
Para la implementación de producción, es posible que los usuarios quieran usar un nombre de dominio que controlen, por ejemplo, api.company.com
y crear un registro CNAME que apunte, por ejemplo, a my-app.westeurope.azurecontainer.io
. Si es así, es necesario asegurarse de que el nombre de dominio personalizado también se utiliza en Caddyfile, en lugar del asignado por Azure (por ejemplo, *.westeurope.azurecontainer.io
). Además, se debe hacer referencia al nombre de dominio personalizado en la configuración de YAML de ACI descrita más adelante en este ejemplo.
Preparación de la cuenta de almacenamiento
Crear una cuenta de almacenamiento
az storage account create \
--name <storage-account> \
--resource-group <resource-group> \
--location westeurope
Almacene la cadena de conexión en una variable de entorno
AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name <storage-account> --resource-group <resource-group> --output tsv)
Cree los recursos compartidos de archivos necesarios para almacenar el estado del contenedor y la configuración de caddy.
az storage share create \
--name proxy-caddyfile \
--account-name <storage-account>
az storage share create \
--name proxy-config \
--account-name <storage-account>
az storage share create \
--name proxy-data \
--account-name <storage-account>
Recupere las claves de la cuenta de almacenamiento y tome nota para su uso posterior
az storage account keys list -g <resource-group> -n <storage-account>
Implementar un grupo de contenedores
Crear un archivo YAML
Cree un archivo denominado ci-my-app.yaml
y pegue el contenido siguiente. Asegúrese de reemplazar <account-key>
por una de las claves de acceso recibidas anteriormente y <storage-account>
en consecuencia.
Este archivo YAML define dos contenedores reverse-proxy
y my-app
. El contenedor reverse-proxy
monta los tres recursos compartidos de archivos creados anteriormente. La configuración también expone el puerto 80/TCP y 443/TCP del contenedor reverse-proxy
. La comunicación entre ambos contenedores solo se produce en localhost.
Nota
Es importante tener en cuenta que la clave dnsNameLabel
, que define el nombre DNS público con el que se podrá acceder al grupo de instancias de contenedor, debe coincidir con el FQDN definido en Caddyfile
name: ci-my-app
apiVersion: "2021-10-01"
location: westeurope
properties:
containers:
- name: reverse-proxy
properties:
image: caddy:2.6
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
resources:
requests:
memoryInGB: 1.0
cpu: 1.0
limits:
memoryInGB: 1.0
cpu: 1.0
volumeMounts:
- name: proxy-caddyfile
mountPath: /etc/caddy
- name: proxy-data
mountPath: /data
- name: proxy-config
mountPath: /config
- name: my-app
properties:
image: mcr.microsoft.com/azuredocs/aci-helloworld
ports:
- port: 5000
protocol: TCP
environmentVariables:
- name: PORT
value: 5000
resources:
requests:
memoryInGB: 1.0
cpu: 1.0
limits:
memoryInGB: 1.0
cpu: 1.0
ipAddress:
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
type: Public
dnsNameLabel: my-app
osType: Linux
volumes:
- name: proxy-caddyfile
azureFile:
shareName: proxy-caddyfile
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
- name: proxy-data
azureFile:
shareName: proxy-data
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
- name: proxy-config
azureFile:
shareName: proxy-config
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
Implementación del grupo de contenedores
Cree un grupo de recursos con el comando az group create:
az group create --name <resource-group> --location westeurope
Implemente el grupo de contenedores con el comando az container create y pase el archivo YAML como un argumento.
az container create --resource-group <resource-group> --file ci-my-app.yaml
Visualizar el estado de la implementación
Para ver el estado de la implementación, use el siguiente comando az container show:
az container show --resource-group <resource-group> --name ci-my-app --output table
Comprobación de la conexión TLS
Antes de comprobar si todo ha ido bien, dale un poco de tiempo al grupo de contenedores para que se inicie por completo y para que Caddy solicite un certificado.
OpenSSL
Para ello, podemos usar el subcomando s_client
de OpenSSL.
echo "Q" | openssl s_client -connect my-app.westeurope.azurecontainer.io:443
CONNECTED(00000188)
---
Certificate chain
0 s:CN = my-app.westeurope.azurecontainer.io
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEgTCCA2mgAwIBAgISAxxidSnpH4vVuCZk9UNG/pd2MA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA0MDYxODAzMzNaFw0yMzA3MDUxODAzMzJaMC4xLDAqBgNVBAMT
I215LWFwcC53ZXN0ZXVyb3BlLmF6dXJlY29udGFpbmVyLmlvMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEaaN/wGyFcimM+1O4WzbFgO6vIlXxXqp9vgmLZHpFrNwV
aO8JbaB7hE+M5EAg34LDY80RyHgY+Ff4vTh2Z96rVqOCAl4wggJaMA4GA1UdDwEB
/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
BAIwADAdBgNVHQ4EFgQUoL5DP+4PWiyE79hL5o+v8uymHdAwHwYDVR0jBBgwFoAU
FC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzAB
hhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5p
LmxlbmNyLm9yZy8wLgYDVR0RBCcwJYIjbXktYXBwLndlc3RldXJvcGUuYXp1cmVj
b250YWluZXIuaW8wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEw
KDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEEBgor
BgEEAdZ5AgQCBIH1BIHyAPAAdgC3Pvsk35xNunXyOcW6WPRsXfxCz3qfNcSeHQmB
Je20mQAAAYdX8+CQAAAEAwBHMEUCIQC9Ztqd3DXoJhOIHBW+P7ketGrKlVA6nPZl
9CiOrn6t8gIgXHcrbBqItemndRMv+UJ3DaBfTkYOqECecOJCgLhSYNUAdgDoPtDa
PvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYdX8+CAAAAEAwBHMEUCIBJ1
24z44vKFUOLCi1a7ymVuWErkmLb/GtysvcxILaj0AiEAr49hyKfen4BbSTwC8Fg4
/LgZnn2F3uHI+9p+ZMO9xTAwDQYJKoZIhvcNAQELBQADggEBACqxa21eiW3JrZwk
FHgpd6SxhUeecrYXxFNva1Y6G//q2qCmGeKK3GK+ZGPqDtcoASH5t5ghV4dIT4WU
auVDLFVywXzR8PT6QUu3W8QxU+W7406twBf23qMIgrF8PIWhStI5mn1uCpeqlnf5
HpRaj2f5/5n19pcCZcrRx94G9qhPYdMzuy4mZRhxXRqrpIsabqX3DC2ld8dszCvD
pkV61iuARgm3MIQz1yL/x5Bn4nywjnhYZA4KFktC0Ti55cPRh1mkzGQAsYQDdWrq
dVav+U9dOLQ4Sq4suaDmzDzApr+hpQSJhwgRN16+tLMyZ6INAU2JWKDxiyDTdOuH
jz456og=
-----END CERTIFICATE-----
subject=CN = my-app.westeurope.azurecontainer.io
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4208 bytes and written 401 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_128_GCM_SHA256
Session-ID: 85F1A4290F99A0DD28C8CB21EF4269E7016CC5D23485080999A8548057729B24
Session-ID-ctx:
Resumption PSK: 752D438C19A5DBDBF10781F863D5E5D9A8859230968A9EAFFF7BBA86937D004F
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 604800 (seconds)
TLS session ticket:
0000 - 2f 25 98 90 9d 46 9b 01-03 78 db bd 4d 64 b3 a6 /%...F...x..Md..
0010 - 52 c0 7a 8a b6 3d b8 4b-c0 d7 fc 04 e8 63 d4 bb R.z..=.K.....c..
0020 - 15 b3 25 b7 be 64 3d 30-2b d7 dc 7a 1a d1 22 63 ..%..d=0+..z.."c
0030 - 42 30 90 65 6b b5 e1 83-a3 6c 76 c8 f6 ae e9 31 B0.ek....lv....1
0040 - 45 91 33 57 8e 9f 4b 6a-2e 2c 9b f9 87 5f 71 1d E.3W..Kj.,..._q.
0050 - 5a 84 59 50 17 31 1f 62-2b 0e 1e e5 70 03 d9 e9 Z.YP.1.b+...p...
0060 - 50 1c 5d 1f a4 3c 8a 0e-f4 c5 7d ce 9e 5c 98 de P.]..<....}..\..
0070 - e5 .
Start Time: 1680808973
Timeout : 7200 (sec)
Verify return code: 20 (unable to get local issuer certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
Explorador Chrome
Vaya a https://my-app.westeurope.azurecontainer.io
y compruebe el certificado haciendo clic en el candado situado junto a la dirección URL.
Para ver los detalles del certificado, seleccione "La conexión es segura" seguida de "El certificado es válido".