A partir de la versión 1.23, Kubernetes ya no admite la validación de identidad del servidor mediante el campo Nombre común (CN) de X.509 en los certificados. En su lugar, Kubernetes solo se basará en la información en los campos de nombre alternativo (SAN) del sujeto X.509.
A fin de evitar el impacto en tus clústeres, debes reemplazar los certificados incompatibles sin SAN para backends de webhooks y servidores de API agregados antes de actualizar tus clústeres a la versión 1.23 de Kubernetes.
Por qué Kubernetes ya no admite certificados de backend sin SAN
GKE opera con Kubernetes de código abierto, que usa el componente kube-apiserver para comunicarse con los backends agregados del servidor de la API y el webhook mediante la seguridad de la capa de transporte (TLS). El componente kube-apiserver se escribe en el lenguaje de programación Go.
Antes de Go 1.15, los clientes de TLS validan la identidad de los servidores a los que se conectaron mediante un proceso de dos pasos:
- Verifica si el nombre de DNS (o la dirección IP) del servidor está presente como uno de los SAN en el certificado del servidor.
- Como resguardo, verifica si el nombre de DNS (o la dirección IP) del servidor es igual a la CN en el certificado del servidor.
RFC 6125 dejó completamente obsoleta la validación de identidad de servidor basada en el campo CN en 2011. Los navegadores y otras aplicaciones esenciales de seguridad ya no usan el campo.
Para alinearse con el ecosistema de TLS más amplio, Go 1.15 quitó el Paso 2 de su proceso de validación, pero dejó un interruptor de depuración (x509ignoreCN=0
) para habilitar el comportamiento anterior a fin de facilitar el proceso de migración. La versión 1.19 de Kubernetes fue la primera versión compilada con Go 1.15. Los clústeres de GKE en las versiones de la 1.19 a la 1.22 habilitaron el interruptor de depuración de forma predeterminada a fin de proporcionar a los clientes más tiempo para reemplazar los certificados de los backends agregados del servidor de la API y el webhook afectados.
La versión 1.23 de Kubernetes se compila con Go 1.17, que quita el interruptor de depuración. Una vez que GKE actualice tus clústeres a la versión 1.23, las llamadas no se podrán conectar desde el plano de control de tu clúster a webhooks o servicios de API agregados que no proporcionen un certificado X.509 válido con un SAN apropiado.
Identifica los clústeres afectados
Para los clústeres que ejecutan versiones de parche 1.21.9 o 1.22.3 como mínimo
Para los clústeres con versiones de parche 1.21.9 y 1.22.3 o posteriores con Cloud Logging habilitado, GKE proporciona un registro de Registros de auditoría de Cloud para identificar las llamadas a los backends afectados desde tu clúster. Puedes usar el siguiente filtro para buscar los registros:
logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"
Si tus clústeres no llamaron a los backends con certificados afectados, no verás ningún registro. Si ves un registro de auditoría de este tipo, incluirá el nombre de host del backend afectado.
El siguiente es un ejemplo de la entrada de registro para un backend de webhook alojado por un servicio llamado example-webhook en el espacio de nombres default:
{
...
resource {
type: "k8s_cluster",
"labels": {
"location": "us-central1-c",
"cluster_name": "example-cluster",
"project_id": "example-project"
}
},
labels: {
invalid-cert.webhook.gke.io/example-webhook.default.svc: "No subjectAltNames returned from example-webhook.default.svc:8443",
...
},
logName: "projects/example-project/logs/cloudaudit.googleapis.com%2Factivity",
operation: {
...
producer: "k8s.io",
...
},
...
}
Los nombres de host de los servicios afectados (p. ej., example-webhook.default.svc
) se incluyen como sufijos en los nombres de las etiquetas que comienzan con invalid-cert.webhook.gke.io/
. También puedes obtener el nombre del clúster que realizó la llamada desde la etiqueta resource.labels.cluster_name
, que tiene el valor example-cluster
en este ejemplo.
Estadísticas de baja
Puedes obtener información sobre qué clústeres usan certificados incompatibles con las estadísticas de baja. Las estadísticas están disponibles para los clústeres que ejecutan la versión 1.22.6-gke.1000 o una posterior.
Otras versiones de clústeres
Si tienes un clúster en una versión de parche anterior a la 1.22.3 en la versión secundaria 1.22 o cualquier versión de parche anterior a 1.21.9, tienes dos opciones para determinar si tu clúster se ve afectado por esta baja:
Opción 1 (recomendado): Actualiza tu clúster a una versión de parche que admita la identificación de certificados afectados con registros.. Asegúrate de que Cloud Logging esté habilitado para tu clúster. Después de actualizar el clúster, se producirán los registros de auditoría de identificación de Cloud Audit Logging cada vez que el clúster intente llamar a un servicio que no proporcione un certificado con un SAN adecuado. Como los registros solo se producirán en un intento de llamada, recomendamos esperar 30 días después de una actualización para que haya tiempo suficiente para que se invoquen todas las rutas de llamada.
Se recomienda usar registros para identificar los servicios afectados, ya que este enfoque minimiza el esfuerzo manual mediante la producción automática de registros para mostrar los servicios afectados.
Opción 2: Inspecciona todos los certificados que usan los webhooks o los servicios agregados de la API en los clústeres para determinar si se ven afectados debido a que no tienen SAN:
- Obtén la lista de webhooks y servidores de la API agregados en tu clúster e identifica sus backends (Services o URL).
- Inspecciona los certificados que usan los servicios de backend.
Dado el esfuerzo manual que se necesita para inspeccionar todos los certificados de esta manera, este método solo debe seguirse si necesitas evaluar el impacto de las bajas en la versión 1.23 de Kubernetes antes de actualizar tu clúster a la versión 1.21. Si puedes actualizar tu clúster a la versión 1.21, primero debes actualizarlo y, luego, seguir las instrucciones de la Opción 1 para evitar el esfuerzo manual.
Identifica los servicios de backend que se inspeccionarán
Para identificar los backends que podrían verse afectados por la baja, obtén la lista de Webhooks y servicios de API agregados y sus backends asociados en el clúster.
Para obtener una lista de todos los webhooks relevantes en el clúster, usa los siguientes comandos kubectl
:
kubectl get mutatingwebhookconfigurations -A # mutating admission webhooks
kubectl get validatingwebhookconfigurations -A # validating admission webhooks
Puedes obtener un servicio de backend o una URL asociados para un webhook determinado si examinas el campo clientConfig.service
o el campo webhooks.clientConfig.url
en la configuración del webhook.
kubectl get mutatingwebhookconfigurations example-webhook -o yaml
El resultado de este comando es similar al siguiente:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
clientConfig:
service:
name: example-service
namespace: default
port: 443
Ten en cuenta que clientConfig puede especificar su backend como un Service de Kubernetes (clientConfig.service
) o como una URL (clientConfig.url
).
Para enumerar todos los servicios de API agregados relevantes en el clúster, usa el siguiente comando kubectl
:
kubectl get apiservices -A |grep -v Local # aggregated API services
El resultado de este comando es similar al siguiente:
NAME SERVICE AVAILABLE AGE
v1beta1.metrics.k8s.io kube-system/metrics-server True 237d
En este ejemplo, se muestra el servicio metric-server
del espacio de nombres kube-system
.
Puedes obtener un servicio asociado para una determinada API agregada si examinas el campo spec.service
:
kubectl get apiservices v1beta1.metrics.k8s.io -o yaml
El resultado de este comando es similar al siguiente:
...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
service:
name: metrics-server
namespace: kube-system
port: 443
Inspecciona el certificado de un servicio
Una vez que identificaste servicios de backend relevantes para inspeccionar, puedes inspeccionar el certificado de cada servicio específico, como example-service
:
Busca el selector y el puerto de destino del servicio:
kubectl describe service example-service
El resultado de este comando es similar al siguiente:
Name: example-service Namespace: default Labels: run=nginx Selector: run=nginx Type: ClusterIP IP: 172.21.xxx.xxx Port: 443 TargetPort: 444
En este ejemplo,
example-service
tiene el selectorrun=nginx
y el puerto de destino444
.Busca un pod que coincida con el selector:
kubectl get pods --selector=run=nginx
El resultado del comando es similar al siguiente:
NAME READY STATUS RESTARTS AGE example-pod 1/1 Running 0 21m
Configura una redirección de puertos
desde tu localhost
kubectl
al Pod.kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
Reemplaza lo siguiente en el comando:
LOCALHOST_PORT
es la dirección en la que se escuchará.TARGET_PORT
es elTargetPort
del paso 1.
Usa
openssl
para imprimir el certificado que usa el Service:openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
En este resultado de ejemplo, se muestra un certificado válido (con entradas SAN):
Subject: CN = example-service.default.svc X509v3 extensions: X509v3 Subject Alternative Name: DNS:example-service.default.svc
En este resultado de ejemplo, se muestra un certificado en el que falta un SAN:
Subject: CN = example-service.default.svc X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Authority Key Identifier: keyid:1A:5F:29:D8:E9:3C:54:3C:35:CC:D8:AB:D1:21:FD:C3:56:25:C0:74
Quita el puerto de redirección para que se ejecute en segundo plano con los siguientes comandos:
$ jobs [1]+ Running kubectl port-forward pods/example-pod 8888:444 & $ kill %1 [1]+ Terminated kubectl port-forward pods/example 8888:444
Inspecciona el certificado de un backend de URL
Si el webhook usa un backend de url
, conéctate de forma directa al nombre de host especificado en la URL. Por ejemplo, si la URL es https://example.com:123/foo/bar
, usa el siguiente comando openssl
para imprimir el certificado que usa el backend:
openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text
Mitiga el riesgo de la actualización 1.23
Una vez que identificaste los clústeres afectados y sus servicios de backend mediante certificados sin SAN, debes actualizar los webhooks y los backends del servidor de la API agregados para usar certificados con SAN adecuados antes de la actualización de los clústeres a la versión 1.23.
GKE no actualizará automáticamente los clústeres en las versiones 1.22.6-gke.1000 o posteriores con backends que usen certificados incompatibles hasta que reemplaces los certificados o hasta que la versión 1.22 alcance el final de la asistencia.
Si tu clúster se encuentra en una versión de GKE anterior a la 1.22.6-gke.1000, puedes evitar las actualizaciones automáticas de forma temporal si configuras una exclusión de mantenimiento para evitar actualizaciones menores.
Recursos
Consulta los siguientes recursos para obtener más información sobre este cambio:
- Notas de la versión de Kubernetes 1.23
- Kubernetes se compila con Go 1.17. Esta versión de Go quita la capacidad de usar una configuración de entorno
GODEBUG=x509ignoreCN=0
para volver a habilitar el comportamiento heredado obsoleto de tratar el CN de certificados de entrega X.509 como un nombre de host.
- Kubernetes se compila con Go 1.17. Esta versión de Go quita la capacidad de usar una configuración de entorno
- Notas de la versión de Kubernetes 1.19 y Kubernetes 1.20
- El comportamiento heredado y obsoleto de tratar el campo CN en los certificados de entrega X.509 como un nombre de host cuando no hay SAN ahora está inhabilitado de forma predeterminada.
- Notas de la versión de Go 1.17
- Se quitó la marca temporal
GODEBUG=x509ignoreCN=0
.
- Se quitó la marca temporal
- Notas de la versión de Go 1.15
- El comportamiento heredado obsoleto de tratar el campo CN en los certificados X.509 como un host cuando no hay SAN ahora está inhabilitado de forma predeterminada.
- RFC 6125 (página 46)
- Aunque el uso del valor de CN es una práctica existente, está obsoleto y se recomienda a las autoridades certificadoras que proporcionen valores
subjectAltName
en su lugar.
- Aunque el uso del valor de CN es una práctica existente, está obsoleto y se recomienda a las autoridades certificadoras que proporcionen valores
- Webhooks de admisión