En esta página, se muestra cómo inhabilitar el puerto de solo lectura de kubelet no seguro en clústeres de Google Kubernetes Engine (GKE) para reducir el riesgo de acceso no autorizado a kubelet y cómo migrar aplicaciones a un puerto más seguro.
En los clústeres de Kubernetes, incluido GKE, el proceso de kubelet
que se ejecuta en los nodos entrega una API de solo lectura que usa el puerto no seguro 10255
.
Kubernetes no realiza ninguna verificación de autenticación ni de autorización en este puerto. Kubelet entrega los mismos extremos en el puerto 10250
autenticado y más seguro.
Inhabilita el puerto de solo lectura de kubelet y cambia las cargas de trabajo que usan el puerto 10255
para usar el puerto más seguro 10250
en su lugar.
Antes de comenzar
Antes de comenzar, asegúrate de haber realizado las siguientes tareas:
- Habilita la API de Google Kubernetes Engine. Habilitar la API de Google Kubernetes Engine
- Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta
gcloud components update
para obtener la versión más reciente.
Requisitos
- Solo puedes inhabilitar el puerto de solo lectura no seguro de kubelet en la versión 1.26.4-gke.500 de GKE o versiones posteriores.
Verifica el uso de puertos no seguros y migra las aplicaciones
Antes de inhabilitar el puerto de solo lectura no seguro, migra cualquiera de las aplicaciones en ejecución que usen el puerto al puerto de solo lectura más seguro. Las cargas de trabajo que podrían necesitar migración incluyen canalizaciones de métricas personalizadas y cargas de trabajo que acceden a extremos de kubelet.
- Para las cargas de trabajo que necesitan acceso a la información que entrega la API de kubelet en el nodo, como las métricas, usa el puerto
10250
. - En el caso de las cargas de trabajo que obtienen información de Kubernetes con la API de kubelet en el nodo, como enumerar Pods en el nodo, usa la API de Kubernetes.
Verifica si las aplicaciones usan el puerto de solo lectura no seguro de kubelet
En esta sección, se muestra cómo verificar si hay un uso inseguro de puertos en tu clúster.
Verifica el uso de puertos en el modo Autopilot
Para verificar el uso de puertos en un clúster de Autopilot, asegúrate de tener al menos una carga de trabajo que no sea un DaemonSet en ejecución en el clúster. Si realizas los siguientes pasos en un clúster de Autopilot vacío, es posible que los resultados no sean válidos.
Guarda el siguiente manifiesto como
read-only-port-metrics.yaml
:apiVersion: v1 kind: Namespace metadata: name: node-metrics-printer-namespace --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-metrics-printer-role rules: - apiGroups: - "" resources: - nodes/metrics verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: node-metrics-printer-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: node-metrics-printer-role subjects: - kind: ServiceAccount name: node-metrics-printer-sa namespace: node-metrics-printer-namespace --- apiVersion: v1 kind: ServiceAccount metadata: name: node-metrics-printer-sa namespace: node-metrics-printer-namespace --- apiVersion: apps/v1 kind: DaemonSet metadata: name: node-metrics-printer namespace: node-metrics-printer-namespace spec: selector: matchLabels: app: node-metrics-printer template: metadata: labels: app: node-metrics-printer spec: serviceAccountName: node-metrics-printer-sa containers: - name: metrics-printer image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest command: ["sh", "-c"] args: - 'while true; do curl -s --cacert "${CA_CERT}" -H "Authorization: Bearer $(cat ${TOKEN_FILE})" "https://${NODE_ADDRESS}:10250/metrics"|grep kubelet_http_requests_total; sleep 20; done' env: - name: CA_CERT value: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt - name: TOKEN_FILE value: /var/run/secrets/kubernetes.io/serviceaccount/token - name: NODE_ADDRESS valueFrom: fieldRef: fieldPath: status.hostIP
Este manifiesto hace lo siguiente:
- Crea un espacio de nombres y configura roles de RBAC para permitir la lectura de métricas de nodos.
- Implementa un DaemonSet que verifica las métricas de kubelet en busca del puerto de solo lectura no seguro.
Implementa el manifiesto:
kubectl create -f read-only-port-metrics.yaml
Verifica los registros de DaemonSet:
kubectl logs --namespace=node-metrics-printer-namespace \ --all-containers --prefix \ --selector=app=node-metrics-printer
Si el resultado tiene algún resultado que contenga la cadena
server_type=readonly
, una aplicación está usando el puerto de solo lectura no seguro.
Verifica el uso de puertos en el modo estándar
Ejecuta el siguiente comando en, al menos, un nodo de cada grupo de nodos de tu clúster:
kubectl get --raw /api/v1/nodes/NODE_NAME/proxy/metrics | grep http_requests_total | grep readonly
Reemplaza NODE_NAME
por el nombre del conjunto de datos.
Si el resultado contiene entradas con la cadena server_type="readonly"
, pueden ocurrir las siguientes situaciones:
- Las cargas de trabajo en el nodo usan el puerto de solo lectura no seguro de kubelet.
- Después de inhabilitar el puerto no seguro, el comando aún muestra la cadena
server_type="readonly"
. Esto se debe a que la métricakubelet_http_requests_total
representa la cantidad acumulada de solicitudes HTTP que recibió el servidor de kubelet desde su último reinicio. Este número no se restablece cuando se inhabilita el puerto no seguro. Este número se restablece después de que GKE reinicia el servidor de kubelet, por ejemplo, durante una actualización de nodo. Para obtener más información, consulta la Referencia de métricas de Kubernetes.
Si el resultado está vacío, ninguna carga de trabajo en ese nodo usa el puerto de solo lectura no seguro.
Identifica las cargas de trabajo que usan el puerto de solo lectura no seguro de kubelet
Para identificar las cargas de trabajo que usan el puerto no seguro, revisa los archivos de configuración de la carga de trabajo, como los ConfigMaps y los pods.
Ejecute los siguientes comandos:
kubectl get pods --all-namespaces -o yaml | grep 10255
kubectl get configmaps --all-namespaces -o yaml | grep 10255
Si el resultado del comando no está vacío, usa la siguiente secuencia de comandos para identificar los nombres de los ConfigMaps o Pods que usan el puerto no seguro:
# This function checks if a Kubernetes resource is using the insecure port 10255.
#
# Arguments:
# $1 - Resource type (e.g., pod, configmap, )
# $2 - Resource name
# $3 - Namespace
#
# Output:
# Prints a message indicating whether the resource is using the insecure port.
isUsingInsecurePort() {
resource_type=$1
resource_name=$2
namespace=$3
config=$(kubectl get $resource_type $resource_name -n $namespace -o yaml)
# Check if kubectl output is empty
if [[ -z "$config" ]]; then
echo "No configuration file detected for $resource_type: $resource_name (Namespace: $namespace)"
return
fi
if echo "$config" | grep -q "10255"; then
echo "Warning: The configuration file ($resource_type: $namespace/$resource_name) is using insecure port 10255. It is recommended to migrate to port 10250 for enhanced security."
else
echo "Info: The configuration file ($resource_type: $namespace/$resource_name) is not using insecure port 10255."
fi
}
# Get the list of ConfigMaps with their namespaces
configmaps=$(kubectl get configmaps -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')
# Iterate over each ConfigMap
for configmap in $configmaps; do
namespace=$(echo $configmap | cut -d/ -f1)
configmap_name=$(echo $configmap | cut -d/ -f2)
isUsingInsecurePort "configmap" "$configmap_name" "$namespace"
done
# Get the list of Pods with their namespaces
pods=$(kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')
# Iterate over each Pod
for pod in $pods; do
namespace=$(echo $pod | cut -d/ -f1)
pod_name=$(echo $pod | cut -d/ -f2)
isUsingInsecurePort "pod" "$pod_name" "$namespace"
done
Una vez que hayas identificado las cargas de trabajo relevantes, mígralas para que usen el puerto seguro 10250. Para ello, completa los pasos que se indican en la siguiente sección.
Migra desde el puerto de solo lectura no seguro de kubelet
Por lo general, migrar una aplicación al puerto seguro implica los siguientes pasos:
Actualiza las URLs o los extremos que hacen referencia al puerto de solo lectura no seguro para usar el puerto de solo lectura seguro. Por ejemplo, cambia
http://203.0.113.104:10255
ahttp://203.0.113.104:10250
.Configura el certificado de la autoridad certificadora (AC) del cliente HTTP como el certificado de AC del clúster. Para encontrar este certificado, ejecuta el siguiente comando:
gcloud container clusters describe CLUSTER_NAME \ --location=LOCATION \ --format="value(masterAuth.clusterCaCertificate)"
Reemplaza lo siguiente:
CLUSTER_NAME
: El nombre de tu clúster.LOCATION
: Es la ubicación de tu clúster.
El puerto autenticado 10250
requiere que otorgues los roles de RBAC adecuados al sujeto para acceder a los recursos específicos. Para obtener más información, consulta Autorización de kubelet en la documentación de Kubernetes.
/pods
en el puerto de solo lectura no seguro de kubelet, debes otorgar el permiso de RBAC nodes/proxy
para acceder al extremo en el puerto seguro de kubelet. nodes/proxy
es un permiso potente que no puedes otorgar en los clústeres de GKE Autopilot y que no deberías otorgar en los clústeres de GKE Standard. En su lugar, usa la API de Kubernetes con un fieldSelector
para el nombre del nodo.
Si usas aplicaciones de terceros que dependen del puerto de solo lectura no seguro de kubelet, consulta al proveedor de la aplicación para obtener instrucciones para migrar al puerto seguro 10250
.
Ejemplo de migración
Considera un Pod que consulta métricas desde el puerto de solo lectura no seguro de kubelet.
apiVersion: v1
kind: Pod
metadata:
name: kubelet-readonly-example
spec:
restartPolicy: Never
containers:
- name: kubelet-readonly-example
image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
command:
- curl
- http://$(NODE_ADDRESS):10255/metrics
env:
- name: NODE_ADDRESS
valueFrom:
fieldRef:
fieldPath: status.hostIP
Esta aplicación hace lo siguiente:
- Usa la cuenta de servicio
default
en el espacio de nombresdefault
. - Ejecuta el comando
curl
en el extremo/metrics
del nodo.
Para actualizar este Pod y que use el puerto seguro 10250
, sigue estos pasos:
Crea un ClusterRole con acceso para obtener métricas de nodo:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: curl-authenticated-role rules: - apiGroups: - "" resources: - nodes/metrics verbs: - get
Vincula el ClusterRole a la identidad de tu aplicación:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: curl-authenticated-role-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: curl-authenticated-role subjects: - kind: ServiceAccount name: default namespace: default
Actualiza el comando
curl
para usar el extremo de puerto seguro con los encabezados de autorización correspondientes:apiVersion: v1 kind: Pod metadata: name: kubelet-authenticated-example spec: restartPolicy: Never containers: - name: kubelet-readonly-example image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest env: - name: NODE_ADDRESS valueFrom: fieldRef: fieldPath: status.hostIP command: - sh - -c - 'curl -s --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://${NODE_ADDRESS}:10250/metrics'
Modifica las reglas de firewall de VPC
Si actualizas las cargas de trabajo para usar el puerto 10250
, crea reglas de firewall para que los Pods del clúster puedan alcanzar el puerto en los rangos de direcciones IP de tu nodo. Las reglas del firewall deben hacer lo siguiente:
- Permite el tráfico entrante al puerto TCP
10250
en los rangos de direcciones IP de tu nodo desde los rangos de direcciones IP internos del Pod. - Rechaza el tráfico entrante al puerto TCP
10250
en los rangos de direcciones IP de tu nodo desde Internet pública.
Puedes usar las siguientes reglas de firewall predeterminadas de GKE como plantilla para los parámetros que especifiques en tus reglas nuevas:
gke-[cluster-name]-[cluster-hash]-inkubelet
gke-[cluster-name]-[cluster-hash]-exkubelet
Inhabilita el puerto de solo lectura no seguro en los clústeres de Autopilot
Puedes inhabilitar el puerto de solo lectura no seguro de kubelet para clústeres de Autopilot nuevos y existentes.
Inhabilita el puerto de solo lectura no seguro en clústeres de Autopilot nuevos
Para inhabilitar el puerto de solo lectura de kubelet no seguro cuando creas un clúster de Autopilot nuevo, usa la marca --no-autoprovisioning-enable-insecure-kubelet-readonly-port
, como en el siguiente comando:
gcloud container clusters create-auto CLUSTER_NAME \
--location=LOCATION \
--no-autoprovisioning-enable-insecure-kubelet-readonly-port
Reemplaza lo siguiente:
CLUSTER_NAME
: Es el nombre del clúster nuevo de Autopilot.LOCATION
: Es la ubicación del clúster nuevo de Autopilot.
Inhabilita el puerto de solo lectura no seguro en los clústeres de Autopilot existentes
Para inhabilitar el puerto de solo lectura de kubelet no seguro en un clúster de Autopilot existente, usa la marca --no-autoprovisioning-enable-insecure-kubelet-readonly-port
, como en el siguiente comando. Todos los nodos nuevos y existentes del clúster dejan de usar el puerto.
gcloud container clusters update CLUSTER_NAME \
--location=LOCATION \
--no-autoprovisioning-enable-insecure-kubelet-readonly-port
Reemplaza lo siguiente:
CLUSTER_NAME
: Es el nombre del clúster existente.LOCATION
: Es la ubicación de tu clúster existente.
Inhabilita el puerto de solo lectura no seguro en clústeres estándar
Puedes inhabilitar el puerto de solo lectura no seguro de kubelet para clústeres estándar completos o para grupos de nodos individuales. Te recomendamos que inhabilites el puerto para todo el clúster.
Si usas el aprovisionamiento automático de nodos, los grupos de nodos aprovisionados automáticamente heredan el parámetro de configuración de puerto que especificas a nivel del clúster. De manera opcional, puedes especificar un parámetro de configuración diferente para los grupos de nodos aprovisionados automáticamente, pero te recomendamos que inhabilites el puerto en todos los nodos del clúster.
También puedes usar un archivo de configuración del sistema de nodos para inhabilitar de forma declarativa el puerto de solo lectura no seguro de kubelet. Si usas este archivo, no podrás usar los comandos de las siguientes secciones para controlar la configuración de kubelet.
Inhabilita el puerto de solo lectura no seguro en clústeres estándar nuevos
Para inhabilitar el puerto de solo lectura de kubelet no seguro en un clúster estándar nuevo, usa la marca --no-enable-insecure-kubelet-readonly-port
como en el siguiente comando:
gcloud container clusters create CLUSTER_NAME \
--location=LOCATION \
--no-enable-insecure-kubelet-readonly-port
Reemplaza lo siguiente:
CLUSTER_NAME
: es el nombre del clúster estándar nuevo.LOCATION
: es la ubicación del nombre del clúster estándar nuevo.
De forma opcional, puedes agregar la marca --no-autoprovisioning-enable-insecure-kubelet-readonly-port
para controlar por separado la configuración de aprovisionamiento automático de nodos, pero no recomendamos este enfoque.
Esta marca inicia una actualización progresiva de tus grupos de nodos aprovisionados de forma automática, lo que puede causar interrupciones en tus cargas de trabajo en ejecución.
Inhabilita el puerto de solo lectura no seguro en los clústeres estándar existentes
Para inhabilitar el puerto de solo lectura de kubelet no seguro en un clúster estándar existente, usa la marca --no-enable-insecure-kubelet-readonly-port
como en el siguiente comando. Los grupos de nodos nuevos no usarán el puerto no seguro.
GKE no actualiza automáticamente los grupos de nodos existentes.
gcloud container clusters update CLUSTER_NAME \
--location=LOCATION \
--no-enable-insecure-kubelet-readonly-port
Reemplaza lo siguiente:
CLUSTER_NAME
: Es el nombre de tu clúster estándar existente.LOCATION
: Es la ubicación de tu clúster estándar existente.
Inhabilita el puerto de solo lectura no seguro en los grupos de nodos estándar
Te recomendamos que configures el puerto de solo lectura a nivel del clúster en todos los casos. Si inhabilitaste el puerto de solo lectura en un clúster existente que ya tenía grupos de nodos en ejecución, usa el siguiente comando para inhabilitar el puerto en esos grupos de nodos.
gcloud container node-pools update NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=LOCATION \
--no-enable-insecure-kubelet-readonly-port
Reemplaza lo siguiente:
NODE_POOL_NAME
: es el nombre de tu grupo de nodos.CLUSTER_NAME
: el nombre del clústerLOCATION
: Es la ubicación del clúster.
Verifica que el puerto esté inhabilitado
Para verificar que el puerto de solo lectura no seguro de kubelet esté inhabilitado, describe el recurso de GKE.
Verifica el estado de los puertos en los clústeres de Autopilot
Ejecuta el siguiente comando:
gcloud container clusters describe CLUSTER_NAME \
--location=LOCATION \
--flatten=nodePoolAutoConfig \
--format="value(nodeKubeletConfig)"
Reemplaza lo siguiente:
CLUSTER_NAME
: Es el nombre de tu clúster de Autopilot.LOCATION
: Es la ubicación de tu clúster de Autopilot.
Si el puerto está inhabilitado, el resultado es el siguiente:
insecureKubeletReadonlyPortEnabled: false
Verifica el estado de los puertos en los clústeres estándar
El estado del puerto está disponible en el campo nodePoolDefaults.nodeConfigDefaults.nodeKubeletConfig
cuando describes tu clúster con la API de GKE.
En los clústeres estándar, también verás un campo nodeConfig
que establece un valor para el estado del puerto de solo lectura de kubelet. El campo nodeConfig
está obsoleto y solo se aplica al grupo de nodos predeterminado que GKE crea cuando creas un clúster nuevo en modo estándar. El estado del puerto en el campo nodeConfig
obsoleto no se aplica a otros grupos de nodos del clúster.
Ejecuta el siguiente comando:
gcloud container clusters describe CLUSTER_NAME \
--location=LOCATION \
--flatten=nodePoolDefaults.nodeConfigDefaults \
--format="value(nodeKubeletConfig)"
Reemplaza lo siguiente:
CLUSTER_NAME
: es el nombre de tu clúster estándar.LOCATION
: es la ubicación de tu clúster estándar.
Si el puerto está inhabilitado, el resultado es el siguiente:
insecureKubeletReadonlyPortEnabled: false
Verifica el estado de los puertos en los grupos de nodos estándar
Ejecuta el siguiente comando:
gcloud container node-pools describe NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=LOCATION \
--flatten=config \
--format="value(kubeletConfig)"
Reemplaza lo siguiente:
NODE_POOL_NAME
: es el nombre de tu grupo de nodos.CLUSTER_NAME
: el nombre del clústerLOCATION
: Es la ubicación del clúster.
Si el puerto está inhabilitado, el resultado es el siguiente:
insecureKubeletReadonlyPortEnabled: false