找回密码
 立即注册
首页 业界区 业界 通过Kube-rbac-proxy保护 Kubernetes 工作负载中的应用 ...

通过Kube-rbac-proxy保护 Kubernetes 工作负载中的应用容器

矛赓宁 2025-6-4 21:48:43
 1、概述

  kube-rbac-proxy 是 Kubernetes 生态中一个专注于“基于角色的访问控制(RBAC)”的轻量级代理组件,通常以 Sidecar 容器的形式部署在 Pod 中,为服务提供细粒度的请求鉴权能力。它尤其适用于保护 /metrics、/debug 等敏感端点,通过将 RBAC 策略直接应用到应用层,弥补了 Kubernetes 原生网络策略的不足,成为服务安全的关键防线。
  在使用 Prometheus 监控 Kubernetes 集群时,一个常见的问题是 Prometheus 检索的指标可能包含敏感信息(例如,Prometheus 节点导出器暴露了主机的内核版本),这些信息可能被潜在入侵者利用。虽然 Prometheus 中验证和授权指标端点的默认方法是使用 TLS 客户端证书,但由于发行、验证和轮换客户端证书的复杂性,Prometheus 请求在大多数情况下并未经过验证和授权。为了解决这一问题,kube-rbac-proxy 应运而生,它是一个针对单一上游的小型 HTTP 代理,能够使用 SubjectAccessReviews 对 Kubernetes API 执行 RBAC 鉴权,从而确保只有经过授权的请求(如来自 Prometheus 的请求)能够从 Pod 中运行的应用程序中检索指标。本文将详细解释 kube-rbac-proxy 如何利用 Kubernetes RBAC 实现这一功能。  项目地址:https://github.com/brancz/kube-rbac-proxy
2、RBAC是如何在幕后工作的

  Kubernetes基于角色的访问控制(RBAC)本身只解决了一半的问题。顾名思义,它只涉及访问控制,意味着授权,而不是认证。在一个请求能够被授权之前,它需要被认证。简单地说:我们需要找出谁在执行这个请求。在Kubernetes中,服务自我认证的机制是ServiceAccount令牌。
  Kubernetes API公开了验证ServiceAccount令牌的能力,使用所谓的TokenReview。TokenReview的响应仅仅是ServiceAccount令牌是否被成功验证,以及指定的令牌与哪个用户有关。kube-rbac-proxy期望ServiceAccount令牌在Authorization HTTP头中被指定,然后使用TokenReview对其进行验证。
  在这一点上,一个请求已经被验证,但还没有被授权。与TokenReview平行,Kuberenetes有一个SubjectAccessReview,它是授权API的一部分。在SubjectAccessReview中,指定了一个预期的行动以及想要执行该行动的用户。在Prometheus请求度量的具体案例中,/metrics HTTP端点被请求。不幸的是,在Kubernetes中这不是一个完全指定的资源,然而,SubjectAccessReview资源也能够授权所谓的 "非资源请求"。
  当用Prometheus监控Kubernetes时,那么Prometheus服务器可能已经拥有访问/metrics非资源url的权限,因为从Kubernetes apiserver检索指标需要同样的RBAC角色。
注意 1:TokenReview详解参见《Kubernetes身份认证资源 —— TokenReview详解》这篇博文,SubjectAccessReview详解参见《Kubernetes鉴权资源 —— SubjectAccessReview详解》这篇博文。
3、kube-rbac-proxy原理及示例

3.1 原理

  现在已经解释了所有必要的部分,让我们看看kube-rbac-proxy是如何具体地验证和授权一个请求的,案例在本博文的开头就已经说明了。普罗米修斯从节点输出器中请求度量。
  当Prometheus对node-exporter执行请求时,kube-rbac-proxy在它前面,kube-rbac-proxy用提供的ServiceAccount令牌执行TokenReview,如果TokenReview成功,它继续使用SubjectAccessReview来验证,ServiceAccount被授权访问/metrics HTTP端点。
  可见,从Prometheus验证和授权请求的整个流程是这样的:
1.png

3.2 示例

通过node-exporter的servicemonitors资源对象配置可知,prometheus访问node-expoter指标用的是/var/run/secrets/kubernetes.io/serviceaccount/token。
  1. [root@xxx]# kubectl get servicemonitors.monitoring.coreos.com -n=xxxx node-exporter -o yaml
  2. apiVersion: monitoring.coreos.com/v1
  3. kind: ServiceMonitor
  4. metadata:
  5.     .....
  6. spec:
  7.   endpoints:
  8.   - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
  9.     interval: 1m
  10.     metricRelabelings:
  11.     - action: keep
  12.       regex: node_(uname|network)_info|node_cpu_.+|node_memory_Mem.+_bytes|node_memory_SReclaimable_bytes|node_memory_Cached_bytes|node_memory_Buffers_bytes|node_network_(.+_bytes_total|up)|node_network_.+_errs_total|node_nf_conntrack_entries.*|node_disk_.+_completed_total|node_disk_.+_bytes_total|node_filesystem_files|node_filesystem_files_free|node_filesystem_avail_bytes|node_filesystem_size_bytes|node_filesystem_free_bytes|node_filesystem_readonly|node_load.+|node_timex_offset_seconds
  13.       sourceLabels:
  14.       - __name__
  15.     port: https
  16.     relabelings:
  17.     - action: labeldrop
  18.       regex: (service|endpoint)
  19.     - action: replace
  20.       regex: (.*)
  21.       replacement: $1
  22.       sourceLabels:
  23.       - __meta_kubernetes_pod_node_name
  24.       targetLabel: instance
  25.     scheme: https
  26.     tlsConfig:
  27.       insecureSkipVerify: true
  28.   jobLabel: app.kubernetes.io/name
  29.   selector:
  30.     matchLabels:
  31.       app.kubernetes.io/name: node-exporter
复制代码
进入prometheus容器内部获取并解析token。
  1. [root@x]# kubectl exec -it -n=xxxx prometheus-k8s-0 /bin/sh
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. Defaulted container "prometheus" out of: prometheus, config-reloader
  4. /prometheus # cd /var/run/secrets/kubernetes.io/serviceaccount/
  5. /var/run/secrets/kubernetes.io/serviceaccount # ls
  6. ca.crt     namespace  token
  7. /var/run/secrets/kubernetes.io/serviceaccount # cat token
  8. eyJhbGciOiJSUzI1NiIsImtpZCI6ImpyaFRNMDRFR0h5a2JpSUY2Vk5jM2lZYnRYY2Fwcl9yTmhDV04tTkdzdnMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzczMTA4NDgwLCJpYXQiOjE3NDE1NzI0ODAsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJjbG91ZGJhc2VzLW1vbml0b3Jpbmctc3lzdGVtIiwicG9kIjp7Im5hbWUiOiJwcm9tZXRoZXVzLWs4cy0wIiwidWlkIjoiZDhmMDJmZDgtNGVjNS00M2VlLWIyYzQtMzY3MWViMTEyOWViIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJwcm9tZXRoZXVzLWs4cyIsInVpZCI6IjE4NDRjNzcxLTkyMjctNDYzOS1iY2FlLTQ3NTQ0NmU5MDU0OCJ9LCJ3YXJuYWZ0ZXIiOjE3NDE1NzYwODd9LCJuYmYiOjE3NDE1NzI0ODAsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpjbG91ZGJhc2VzLW1vbml0b3Jpbmctc3lzdGVtOnByb21ldGhldXMtazhzIn0.lBPR2j1Ad_zzRH98nk35DFIKhBXPCLN4KcnqzZA1i8tOwVEkMY4nGUIXT8par1AWDKNm2S6wpJUH7WPh3VM4k-KOrD-gFC8lovPj67NEY__6cW0X6VHTSBC2euAr4uVYSoL4tCW0EzPoDajoXrqmcOAqwzNSZb7ecLaN5yv5VyEUK79zbJvZ2-n-T0y2nYBe3qP1wH2XIrhcWB2Vam4_9YICeJ6WmGwc16rH_phQu8Zu58EJ7CDt_oiQ7Iz/var/run/secrets/kubernetes.io/serviceaccount #
复制代码
2.png

查看node-exporter服务配置:
  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4.   ......
  5. spec:
  6.   clusterIP: None
  7.   clusterIPs:
  8.   - None
  9.   internalTrafficPolicy: Cluster
  10.   ipFamilies:
  11.   - IPv4
  12.   ipFamilyPolicy: SingleStack
  13.   ports:
  14.   - name: https
  15.     port: 9100
  16.     protocol: TCP
  17.     targetPort: https
  18.   selector:
  19.     app.kubernetes.io/name: node-exporter
  20.   sessionAffinity: None
  21.   type: ClusterIP
复制代码
查看node-exporter守护进程集配置,可以看到node-exporter应用容器本身是没有开放容器端口的,所有外部进入流量都走kube-rbac-proxy,进入流量kube-rbac-proxy先认证(TokenReview),认证并获取用户信息prometheus-k8s,然后再鉴权(SubjectAccessReview,查看是否有/metrics访问权限),鉴权通过后再把流量代理到node-exporter容器(http://127.0.0.1:9100/):
  1. apiVersion: apps/v1
  2. kind: DaemonSet
  3. metadata:
  4.   ......
  5. spec:
  6.   revisionHistoryLimit: 10
  7.   selector:
  8.     matchLabels:
  9.       app.kubernetes.io/name: node-exporter
  10.   template:
  11.     metadata:
  12.       creationTimestamp: null
  13.       labels:
  14.         app.kubernetes.io/name: node-exporter
  15.         app.kubernetes.io/version: v0.18.1
  16.     spec:
  17.       affinity:
  18.         nodeAffinity:
  19.           requiredDuringSchedulingIgnoredDuringExecution:
  20.             nodeSelectorTerms:
  21.             - matchExpressions:
  22.               - key: node-role.kubernetes.io/edge
  23.                 operator: DoesNotExist
  24.       containers:
  25.       - args:
  26.         - --web.listen-address=127.0.0.1:9100
  27.         - --path.procfs=/host/proc
  28.         - --path.sysfs=/host/sys
  29.         - --path.rootfs=/host/root
  30.         - --no-collector.wifi
  31.         - --no-collector.hwmon
  32.         - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
  33.         - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
  34.         image: 192.168.137.94:80/cscec_big_data-cloudbases/node-exporter:v0.18.1
  35.         imagePullPolicy: IfNotPresent
  36.         name: node-exporter
  37.         resources:
  38.           limits:
  39.             cpu: "1"
  40.             memory: 500Mi
  41.           requests:
  42.             cpu: 102m
  43.             memory: 180Mi
  44.         terminationMessagePath: /dev/termination-log
  45.         terminationMessagePolicy: File
  46.         volumeMounts:
  47.         - mountPath: /host/proc
  48.           name: proc
  49.           readOnly: true
  50.         - mountPath: /host/sys
  51.           name: sys
  52.           readOnly: true
  53.         - mountPath: /host/root
  54.           mountPropagation: HostToContainer
  55.           name: root
  56.           readOnly: true
  57.       - args:
  58.         - --logtostderr
  59.         - --secure-listen-address=[$(IP)]:9100
  60.         - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  61.         - --upstream=http://127.0.0.1:9100/
  62.         env:
  63.         - name: IP
  64.           valueFrom:
  65.             fieldRef:
  66.               apiVersion: v1
  67.               fieldPath: status.podIP
  68.         image: 192.168.137.94:80/cscec_big_data-cloudbases/kube-rbac-proxy:v0.8.0
  69.         imagePullPolicy: IfNotPresent
  70.         name: kube-rbac-proxy
  71.         ports:
  72.         - containerPort: 9100
  73.           hostPort: 9100
  74.           name: https
  75.           protocol: TCP
  76.         resources:
  77.           limits:
  78.             cpu: "1"
  79.             memory: 100Mi
  80.           requests:
  81.             cpu: 10m
  82.             memory: 20Mi
  83.         securityContext:
  84.           runAsGroup: 65532
  85.           runAsNonRoot: true
  86.           runAsUser: 65532
  87.         terminationMessagePath: /dev/termination-log
  88.         terminationMessagePolicy: File
  89.       dnsPolicy: ClusterFirst
  90.       hostNetwork: true
  91.       hostPID: true
  92.       nodeSelector:
  93.         kubernetes.io/os: linux
  94.       restartPolicy: Always
  95.       schedulerName: default-scheduler
  96.       securityContext:
  97.         runAsNonRoot: true
  98.         runAsUser: 65534
  99.       serviceAccount: node-exporter
  100.       serviceAccountName: node-exporter
  101.       terminationGracePeriodSeconds: 30
  102.       tolerations:
  103.       - operator: Exists
  104.       volumes:
  105.       - hostPath:
  106.           path: /proc
  107.           type: ""
  108.         name: proc
  109.       - hostPath:
  110.           path: /sys
  111.           type: ""
  112.         name: sys
  113.       - hostPath:
  114.           path: /
  115.           type: ""
  116.         name: root
  117.   updateStrategy:
  118.     rollingUpdate:
  119.       maxSurge: 0
  120.       maxUnavailable: 1
  121.     type: RollingUpdate
  122. status:
  123.   currentNumberScheduled: 1
  124.   desiredNumberScheduled: 1
  125.   numberAvailable: 1
  126.   numberMisscheduled: 0
  127.   numberReady: 1
  128.   observedGeneration: 1
  129.   updatedNumberScheduled: 1
复制代码
注意 1: clusterrolebinding:
  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: ClusterRoleBinding
  3. metadata:
  4.     ......
  5. roleRef:
  6.   apiGroup: rbac.authorization.k8s.io
  7.   kind: ClusterRole
  8.   name: xxxx-prometheus-k8s
  9. subjects:
  10. - kind: ServiceAccount
  11.   name: prometheus-k8s
  12.   namespace: xxxxx
复制代码
clusterrole:
  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: ClusterRole
  3. metadata:
  4.    ......
  5. rules:
  6. - apiGroups:
  7.   - ""
  8.   resources:
  9.   - nodes/metrics
  10.   - nodes
  11.   - services
  12.   - endpoints
  13.   - pods
  14.   verbs:
  15.   - get
  16.   - list
  17.   - watch
  18. - nonResourceURLs:
  19.   - /metrics
  20.   verbs:
  21.   - get
复制代码
5、总结

    kube-rbac-proxy 作为 Kubernetes RBAC 的扩展组件,通过将权限控制能力延伸至应用层,为服务端点提供细粒度权限控制。特别适用于敏感接口防护、多租户资源隔离等场景(如 Prometheus 安全采集 node-exporter/kube-state-metrics 指标)。尽管会增加少量部署复杂度,但通过强化 API 访问审计、身份验证和权限校验,显著提升集群安全防护能力,已成为云原生环境中保障关键业务安全的核心组件。
主要参考:https://juejin.cn/post/7217644586868801596

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册