Configuración del controlador CSI del almacén de secretos para habilitar el controlador de entrada NGINX con TLS
Este artículo le guiará por el proceso de protección de un controlador de entrada NGINX con TLS con un clúster de Azure Kubernetes Service (AKS) y una instancia de Azure Key Vault (AKV). Para más información, consulte TLS en Kubernetes.
Puede importar el certificado TLS de entrada al clúster mediante uno de los métodos siguientes:
- Aplicación: el manifiesto de implementación de la aplicación declara y monta el volumen del proveedor. Solo cuando se implementa la aplicación el certificado está disponible en el clúster. Al quitar la aplicación, también se quita el secreto. Este escenario se adapta a los equipos de desarrollo responsables de la infraestructura de seguridad de la aplicación y su integración con el clúster.
- Controlador de entrada: la implementación de entrada se modifica para declarar y montar el volumen del proveedor. El secreto se importa cuando se crean pods de entrada. Los pods de la aplicación no tienen acceso al certificado TLS. Este escenario se adapta a aquellos en los que un equipo (por ejemplo, TI) administra y crea componentes de infraestructura y redes (incluidos los certificados TLS HTTPS), y otros equipos administran el ciclo de vida de las aplicaciones.
Prerrequisitos
- Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.
- Antes de empezar, asegúrese de que la versión de la CLI de Azure sea >=
2.30.0
, o bien instale la versión más reciente. - Un clúster de AKS con el controlador CSI del almacén de secretos configurado.
- Una instancia de Azure Key Vault.
Generación de un certificado TLS
Generar un certificado TLS mediante el siguiente comando.
export CERT_NAME=aks-ingress-cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -out aks-ingress-tls.crt \ -keyout aks-ingress-tls.key \ -subj "/CN=demo.azure.com/O=aks-ingress-tls"
Importación del certificado en AKV
Exporte el certificado a un archivo PFX mediante el siguiente comando.
export AKV_NAME="[YOUR AKV NAME]" openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx # skip Password prompt
Importar el certificado mediante el
az keyvault certificate import
comando .az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
Implementación de una clase SecretProviderClass
Exportar un nuevo espacio de nombres mediante el siguiente comando.
export NAMESPACE=ingress-basic
Crear el espacio de nombres mediante el comando
kubectl create namespace
.kubectl create namespace $NAMESPACE
Seleccione un método para proporcionar una identidad de acceso y configurar la clase YAML secretProviderClass en consecuencia.
- Asegúrese de usar
objectType=secret
, la única manera de obtener la clave privada y el certificado de AKV. - Establezca
kubernetes.io/tls
comotype
en la secciónsecretObjects
.
Consulte el ejemplo siguiente para obtener un ejemplo del aspecto que podría tener la clase SecretProviderClass:
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-tls spec: provider: azure secretObjects: # secretObjects defines the desired state of synced K8s secret objects - secretName: ingress-tls-csi type: kubernetes.io/tls data: - objectName: $CERT_NAME key: tls.key - objectName: $CERT_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: <client id> keyvaultName: $AKV_NAME # the name of the AKV instance objects: | array: - | objectName: $CERT_NAME objectType: secret tenantId: $TENANT_ID # the tenant ID of the AKV instance
- Asegúrese de usar
Aplicación de la clase SecretProviderClass al clúster de Kubernetes mediante el comando
kubectl apply
.kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
Implementar el controlador de entrada
Adición del repositorio oficial de gráficos de entrada
Agregue el repositorio oficial de gráficos de entrada mediante los siguientes comandos
helm
.helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
Configuración e implementación de la entrada NGINX
En función de su escenario, puede elegir enlazar el certificado a la aplicación o al controlador de entrada. Siga las instrucciones que se indican a continuación según su selección:
Enlace del certificado a la aplicación
Enlazar el certificado a la aplicación mediante el comando
helm install
. La implementación de la aplicación hace referencia al proveedor de Azure Key Vault del controlador CSI del almacén de secretos.helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
Enlace del certificado al controlador de entrada
Enlazar el certificado al controlador de entrada mediante el comando
helm install
. La implementación del controlador de entrada hace referencia al proveedor de Azure Key Vault del controlador CSI del almacén de secretos.Nota:
Si no usa la identidad administrada por pods de Microsoft Entra como método de acceso, quite la línea con
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
.Además, es necesario enlazar SecretProviderClass a un pod para que el controlador CSI del almacén de secretos lo monte y genere el secreto de Kubernetes. Vea Contenido montado de sincronización con un secreto de Kubernetes .
helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \ -f - <<EOF controller: extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true EOF
Compruebe que el secreto de Kubernetes se creó mediante el comando
kubectl get secret
.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Implementación de la aplicación
De nuevo, las instrucciones cambian ligeramente en función de su escenario. Siga las instrucciones correspondientes al escenario seleccionado.
Implementación de la aplicación mediante una referencia de aplicación
Cree un archivo llamado
aks-helloworld-one.yaml
con el siguiente contenido.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
Cree un archivo llamado
aks-helloworld-two.yaml
con el siguiente contenido.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
Aplica los archivos YAML al clúster con el comando
kubectl apply
.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Compruebe que el secreto de Kubernetes se creó mediante el comando
kubectl get secret
.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Implementación de la aplicación mediante una referencia de controlador de entrada
Cree un archivo llamado
aks-helloworld-one.yaml
con el siguiente contenido.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
Cree un archivo llamado
aks-helloworld-two.yaml
con el siguiente contenido.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
Aplica los archivos YAML al clúster con el comando
kubectl apply
.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Implementación de un recurso de entrada que haga referencia al secreto
Ahora podemos implementar un recurso de entrada de Kubernetes que haga referencia al secreto.
Cree un archivo llamado
hello-world-ingress.yaml
con el siguiente contenido.apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-tls annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx tls: - hosts: - demo.azure.com secretName: ingress-tls-csi rules: - host: demo.azure.com http: paths: - path: /hello-world-one(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80 - path: /hello-world-two(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-two port: number: 80 - path: /(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80
Tome nota de la sección
tls
que hace referencia al secreto creado anteriormente y aplique el archivo al clúster mediante el comandokubectl apply
.kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
Obtención de la dirección IP externa del controlador de entrada
Obtenga la dirección IP externa del controlador de entrada mediante el comando
kubectl get service
.kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 EXTERNAL_IP 80:31293/TCP,443:31265/TCP 19m nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
Prueba de la entrada protegida con TLS
Compruebe que la entrada está configurada correctamente con TLS mediante el siguiente comando
curl
. Use la dirección IP externa del paso anterior.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
No proporcionó ninguna ruta de acceso adicional con la dirección, por lo que el controlador de entrada se establece de manera predeterminada en la ruta /. Se devuelve la primera aplicación de demostración, tal como se muestra en la siguiente salida de ejemplo reducido:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>Welcome to Azure Kubernetes Service (AKS)</title> [...]
El parámetro -v en el comando
curl
genera información detallada, incluyendo el certificado TLS recibido. A mitad de la salida de cURL, puede comprobar que se ha utilizado su propio certificado TLS. El parámetro -k continúa cargando la página, aunque se esté usando un certificado autofirmado. El ejemplo siguiente muestra que se ha usado el certificado issuer: CN=demo.azure.com; O=ingress-aks-tls:[...] * Server certificate: * subject: CN=demo.azure.com; O=aks-ingress-tls * start date: Oct 22 22:13:54 2021 GMT * expire date: Oct 22 22:13:54 2022 GMT * issuer: CN=demo.azure.com; O=aks-ingress-tls * SSL certificate verify result: self signed certificate (18), continuing anyway. [...]
Agregue la ruta de acceso /hello-world-two a la dirección, como
https://demo.azure.com/hello-world-two
, y compruebe que la segunda aplicación de demostración está configurada correctamente.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
Se devuelve la segunda aplicación de demostración con el título personalizado, tal como se muestra en la siguiente salida de ejemplo reducido:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>AKS Ingress Demo</title> [...]
Azure Kubernetes Service