A partir de la versión 1.23, Kubernetes ya no admite la validación de la identidad del servidor mediante el campo Nombre común (CN) X.509 de los certificados. En su lugar, Kubernetes solo se basará en la información de los campos Nombre alternativo del asunto (SAN) X.509.
Para evitar que esto afecte a tus clústeres, debes sustituir los certificados incompatibles sin SANs por los back-ends de los webhooks y los servidores de la 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 SANs
GKE utiliza Kubernetes de código abierto, que usa el componente kube-apiserver para ponerse en contacto con los back-ends de tu webhook y del servidor de APIs agregadas mediante Seguridad en la capa de transporte (TLS). El componente kube-apiserver está escrito en el lenguaje de programación Go.
Antes de Go 1.15, los clientes de TLS validaban la identidad de los servidores a los que se conectaban mediante un proceso de dos pasos:
- Comprueba si el nombre DNS (o la dirección IP) del servidor figura como uno de los SANs del certificado del servidor.
- Como alternativa, comprueba si el nombre DNS (o la dirección IP) del servidor es igual al nombre común del certificado del servidor.
En el 2011, la RFC 6125 dejó de usar por completo la validación de la identidad del servidor basada en el campo CN. Los navegadores y otras aplicaciones críticas para la seguridad ya no usan este campo.
Para adaptarse al ecosistema de TLS en general, Go 1.15 ha eliminado el paso 2 de su proceso de validación, pero ha dejado un interruptor de depuración (x509ignoreCN=0
) para habilitar el comportamiento antiguo y facilitar el proceso de migración. La versión 1.19 de Kubernetes fue la primera versión creada con Go 1.15. En los clústeres de GKE con versiones de 1.19 a 1.22, el interruptor de depuración estaba habilitado de forma predeterminada para dar a los clientes más tiempo para sustituir los certificados de los back-ends de webhook y de servidor de API agregados afectados.
Kubernetes versión 1.23 se ha creado con Go 1.17, que elimina 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 los webhooks o a los servicios de API agregados que no proporcionen un certificado X.509 válido con SAN adecuado.
Identificar los clústeres afectados
En el caso de los clústeres que ejecutan versiones de parche 1.21.9 o 1.22.3 (o posteriores)
En los clústeres con las versiones de parche 1.21.9 y 1.22.3 o posteriores con Cloud Logging habilitado, GKE proporciona un registro de auditoría de Cloud para identificar las llamadas a los back-ends 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 han llamado a back-ends 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.
A continuación, se muestra un ejemplo de entrada de registro de 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 (por ejemplo, example-webhook.default.svc
) se incluyen como sufijos en los nombres de las etiquetas que empiezan por invalid-cert.webhook.gke.io/
. También puedes obtener el nombre del clúster que ha hecho la llamada desde la etiqueta resource.labels.cluster_name
, que tiene el valor example-cluster
en este ejemplo.
Estadísticas de discontinuación
Puedes consultar qué clústeres usan certificados incompatibles en estadísticas de obsolescencia. Las estadísticas están disponibles en los clústeres que ejecutan la versión 1.22.6-gke.1000 o posterior.
Otras versiones del clúster
Si tienes un clúster con 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 la 1.21.9, tienes dos opciones para determinar si tu clúster se ve afectado por esta discontinuación:
Opción 1 (recomendada): Actualiza tu clúster a una versión de parche que admita la identificación de los certificados afectados con registros. Asegúrate de que Cloud Logging esté habilitado en tu clúster. Una vez que se haya actualizado el clúster, los registros de Registros de auditoría de Cloud identificativos se generarán 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 generarán cuando se intente hacer una llamada, te recomendamos que esperes 30 días después de una actualización para que haya tiempo suficiente para invocar todas las rutas de llamadas.
Se recomienda usar los registros para identificar los servicios afectados, ya que este enfoque minimiza el esfuerzo manual al generar automáticamente registros que muestran los servicios afectados.
Opción 2: Inspecciona los certificados que usan los webhooks o los servidores de APIs agregadas de tus clústeres para determinar si se ven afectados por no tener SANs:
- Obtén la lista de webhooks y servidores de APIs agregados de tu clúster e identifica sus back-ends (servicios o URLs).
- Inspecciona los certificados que usan los servicios backend.
Dado el esfuerzo manual que se requiere para inspeccionar todos los certificados de esta forma, este método solo se debe seguir si necesitas evaluar el impacto de las obsolescencias 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, deberías hacerlo primero y, después, seguir las instrucciones de la opción 1 para evitar el esfuerzo manual.
Identificar los servicios de backend que se van a inspeccionar
Para identificar los back-ends que pueden verse afectados por la discontinuación, obtén la lista de webhooks y servicios de API agregados, así como sus back-ends asociados en el clúster.
Para obtener una lista de todos los webhooks relevantes del clúster, utiliza los siguientes comandos kubectl
:
kubectl get mutatingwebhookconfigurations -A # mutating admission webhooks
kubectl get validatingwebhookconfigurations -A # validating admission webhooks
Para obtener un servicio o una URL de backend asociados a un webhook determinado, consulta el clientConfig.service
campo
o el webhooks.clientConfig.url
campo
de la configuración del webhook:
kubectl get mutatingwebhookconfigurations example-webhook -o yaml
El resultado debe ser 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 servicio de Kubernetes (clientConfig.service
) o como una URL (clientConfig.url
).
Para enumerar todos los servicios de API agregados relevantes del clúster, usa el siguiente comando kubectl
:
kubectl get apiservices -A |grep -v Local # aggregated API services
El resultado debe ser similar al siguiente:
NAME SERVICE AVAILABLE AGE
v1beta1.metrics.k8s.io kube-system/metrics-server True 237d
Este ejemplo devuelve el servicio metric-server
del espacio de nombres kube-system
.
Para obtener un servicio asociado a una API agregada determinada, consulta el campo spec.service
:
kubectl get apiservices v1beta1.metrics.k8s.io -o yaml
El resultado debe ser similar al siguiente:
...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
service:
name: metrics-server
namespace: kube-system
port: 443
Inspeccionar el certificado de un servicio
Una vez que hayas identificado los servicios backend relevantes que quieras 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 debe ser 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
Configurar una redirección de puertos
desde tu
kubectl
localhost al pod.kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
Sustituye lo siguiente en el comando:
LOCALHOST_PORT
: la dirección en la que se va a escuchar.TARGET_PORT
laTargetPort
del paso 1.
Usa
openssl
para imprimir el certificado que usa el servicio:openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
En este ejemplo de salida 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 ejemplo de salida se muestra un certificado al que le 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
Para quitar el reenvío de puertos de la ejecución en segundo plano, usa 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
Inspeccionar el certificado de un backend de URL
Si el webhook usa un url
backend,
conéctate directamente 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
Mitigar el riesgo de la actualización a la versión 1.23
Una vez que hayas identificado los clústeres afectados y sus servicios backend mediante certificados sin SANs, debes actualizar los webhooks y los backends del servidor de APIs agregadas para que usen certificados con SANs adecuados antes de actualizar los clústeres a la versión 1.23.
GKE no actualizará automáticamente los clústeres de las versiones 1.22.6-gke.1000 o posteriores con back-ends que usen certificados incompatibles hasta que sustituyas los certificados o hasta que la versión 1.22 llegue al final del periodo de asistencia estándar.
Si tu clúster tiene una versión de GKE anterior a 1.22.6-gke.1000, puedes evitar temporalmente las actualizaciones automáticas configurando una exclusión de mantenimiento para evitar las actualizaciones secundarias.
Recursos
Consulta los siguientes recursos para obtener más información sobre este cambio:
- Notas de la versión 1.23 de Kubernetes
- Kubernetes se ha creado con Go 1.17. Esta versión de Go elimina la posibilidad de usar el ajuste de entorno
GODEBUG=x509ignoreCN=0
para volver a habilitar el comportamiento antiguo obsoleto de tratar el CN de los certificados de servicio X.509 como un nombre de host.
- Kubernetes se ha creado con Go 1.17. Esta versión de Go elimina la posibilidad de usar el ajuste de entorno
- Notas de las versiones Kubernetes 1.19 y Kubernetes 1.20
- El comportamiento antiguo y obsoleto de tratar el campo CN de los certificados de servicio X.509 como un nombre de host cuando no hay SANs presentes ahora está inhabilitado de forma predeterminada.
- Notas de la versión 1.17 de Go
- Se ha quitado la marca temporal
GODEBUG=x509ignoreCN=0
.
- Se ha quitado la marca temporal
- Notas de la versión 1.15 de Go
- El comportamiento antiguo y obsoleto de tratar el campo CN de los certificados X.509 como un host cuando no hay SANs presentes ahora está inhabilitado de forma predeterminada.
- RFC 6125
(página 46)
- Aunque el uso del valor CN es una práctica habitual, está obsoleto y se recomienda que las autoridades de certificación proporcionen valores
subjectAltName
.
- Aunque el uso del valor CN es una práctica habitual, está obsoleto y se recomienda que las autoridades de certificación proporcionen valores
- Webhooks de admisión