(三)Prometheus获取指标的tls认证机制

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
云解析DNS,个人版 1个月
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: 阿里云ACK专有集群的master组件基本都是https监听,那么prometheus server是如何鉴权获取到htts监听的metrics指标呢?Tls认证环节无关operator, 主要是prometheus server的认证处理 ,属于prometheus 监控体系通用的理论。先从prometheus最常见场景- pod (apiserver/scheduler/kcm)的tls认证场景开始介绍,然后单独介绍etcd和kubelet的tls认证 。本文通过curl模拟prometheus server获取https metrics 指标,便于对认证机制的理解。

网络上很多prometheus 的指标抓取都是基于自建k8s环境,不适用于阿里云ACK专有集群。这里不做源码剖析,通过对prometheus中获取指标的认证机制做解析,目的在于:

1. 进一步理解k8s集群中的kubelet和etcd的tls认证机制,扩展使用curl直接访问apiserver API

2. 灵活处理客户端访问集群中https监听的组件或者pod,

3. 快速定位获取https的metrics指标报错401/403的问题。


前提条件:

本文环境基于阿里云ACK专有集群1.22以及ACK应用市场的ack-prometheus-operator  chart 12.0.0。



管理组件apiserver/scheduler/kcm pod的TLS认证


一句话总结, prometheus利用pod-serviceaccount-clusterrole-clusterrolebinding使得serviceaccount绑定的secret token可以具备RBAC权限获取到集群中的资源指标信息,sa 的token 会被挂载到pod中被prometheus server进程使用, 从而解决对targest发起pull https metrics接口TLS认证问题。 跨集群监控也可借鉴这种认证方式。


1. 先看prometheus server statefulset "prometheus-ack-prometheus-operator-prometheus"绑定的sa 以及其具备的rbac权限,从clusterrole的定义可以看出,prometheus pod具备足够的权限获取集群中资源的指标。

prometheus 实例pod :prometheus-ack-prometheus-operator-prometheus-0
serviceAccount: ack-prometheus-operator-prometheus
secret:ack-prometheus-operator-prometheus-token-79hj5
#省略无关行
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
  labels:
  name: ack-prometheus-operator-prometheus
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  - nodes/metrics
  - services
  - endpoints
  - pods
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- nonResourceURLs:
  - /metrics
  - /metrics/cadvisor
  verbs:
  - get


其中,获取pod 的/metrics接口起作用的RBAC是:

- nonResourceURLs:
  - /metrics
  - /metrics/cadvisor
  verbs:
  - get

#以上若缺失,会报错 server returned HTTP status 403 Forbidden

"message": "forbidden: User \"system:serviceaccount:monitoring:ack-prometheus-operator-prometheus\" cannot get path \"/metrics\"",


apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ack-prometheus-operator-prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ack-prometheus-operator-prometheus
subjects:
- kind: ServiceAccount
  name: ack-prometheus-operator-prometheus
  namespace: monitoring

2. 获取prometheus sa对应的token:


借地儿练习一下shell,基于sa name获取token:

sa="ack-prometheus-operator-prometheus"
token=$(kubectl describe secret -n monitoring $(kubectl describe sa -n monitoring $sa |grep Token |awk '{print $2}') |grep token:|awk '{print $2}')


基于跟sa绑定的secret name获取token:

secret="ack-prometheus-operator-prometheus-token-79hj5"
token=$(kubectl describe secret -n monitoring $secret |grep token:|awk '{print $2}')


3. 使用token手动curl https监听端口


先看下阿里云ACK集群每个组件的监听端口:


以下几个进程的https端口获取指标均成功,代表prometheus pod可以基于上述sa配置servicemonitor抓取数据:

//使用curl -k,或者--insecure 可不对服务器的https证书进行检查。

//apiserver
curl https://10.0.0.9:6443/metrics -H "Authorization: Bearer $token"  -k
//kcm
curl https://localhost:10257/metrics -H "Authorization: Bearer $token"  -k
//scheduler
curl https://localhost:10259/metrics -H "Authorization: Bearer $token"  -k



总结:

以上解析可以理解sa token可以通过pod 的tls认证,那么将serviceaccount 的token mount到prometheus pod中,然后在抓取任务中指定这个token即可完成prometheus server 对 tls 指标的获取。K8s中pod指定的 Serviceaccount对应的token是默认mount 的,此处不举例。

scrape_configs:
- job_name: monitoring/xxxx
  metrics_path: /metrics
  scheme: https
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    insecure_skip_verify: true
  #略


ACK etcd TLS 认证


ACK etcd 支持自动 TLS 以及通过客户端证书的身份验证, 包括客户端到服务器以及对等(服务器到服务器/集群)的通信。Prometheus访问时,需要使用etcd指定ca认证的client证书,而不可以使用serviceaccount token做认证(etcd不支持)。

先看一下etcd运行参数 证书相关的部分:

/usr/bin/etcd  --client-cert-auth --trusted-ca-file=/var/lib/etcd/cert/ca.pem --cert-file=/var/lib/etcd/cert/etcd-server.pem --key-file=/var/lib/etcd/cert/etcd-server-key.pem --peer-client-cert-auth --peer-trusted-ca-file=/var/lib/etcd/cert/peer-ca.pem --peer-cert-file=/var/lib/etcd/cert/10.0.0.9-name-3.pem --peer-key-file=/var/lib/etcd/cert/10.0.0.9-name-3-key.pem

不看代码,如何知道etcd客户端证书在哪儿?我们参考apiserver中配置的etcd client 证书,看看apiserver如何访问etcd的,借鉴即可:

kube-apiserver --etcd-cafile=/etc/kubernetes/pki/etcd/ca.pem --etcd-certfile=/etc/kubernetes/pki/etcd/etcd-client.pem --etcd-keyfile=/etc/kubernetes/pki/etcd/etcd-client-key.pem

其中/etc/kubernetes/pki/etcd中的三个客户端证书文件(CA证书ca.pem和签名密钥对c)等效果于/var/lib/etcd/cert/中的client 证书。



[root@ack ~]# cd  /var/lib/etcd/cert/
[root@ack cert]# ls
10.0.0.7-name-1.csr      10.0.0.8-name-2.csr      10.0.0.9-name-3.csr      ca-config.json  ca.pem               etcd-client.pem      etcd-server.pem      peer-ca-key.pem
10.0.0.7-name-1-key.pem  10.0.0.8-name-2-key.pem  10.0.0.9-name-3-key.pem  ca.csr          etcd-client.csr      etcd-server.csr      peer-ca-config.json  peer-ca.pem
10.0.0.7-name-1.pem      10.0.0.8-name-2.pem      10.0.0.9-name-3.pem      ca-key.pem      etcd-client-key.pem  etcd-server-key.pem  peer-ca.csr
[root@ack cert]# cd /etc/kubernetes/pki/etcd
[root@ack etcd]# ls
ca.pem  etcd-client-key.pem  etcd-client.pem


借鉴apiserver访问etcd方式,客户端到服务器端通讯,prometheus获取etcd metrics可用curl模拟如下:

curl --cacert  /etc/kubernetes/pki/etcd/ca.pem --cert /etc/kubernetes/pki/etcd/etcd-client.pem  --key  /etc/kubernetes/pki/etcd/etcd-client-key.pem -X GET https://10.0.0.9:2379/metrics


总结:

以上解析中可以看到客户端证书可以获取指标了,则etcd客户端证书可以被打包到k8s secret中, mount 到 prometheus server pod里。

volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/k8s-certs/etcd/
      name: etcd-certs
    volumes:
    - name: etcd-certs
      secret:
        secretName: etcd-certs

配置抓取任务的时候,指定prometheus server  pod 里证书目录即可。

- job_name: 'k8s-etcd-yibei'
    scheme: https
    tls_config: 
      ca_file: /var/run/secrets/kubernetes.io/k8s-certs/etcd/ca.pem
      cert_file: /var/run/secrets/kubernetes.io/k8s-certs/etcd/etcd-client.pem
      key_file: /var/run/secrets/kubernetes.io/k8s-certs/etcd/etcd-client-key.pem
    #略


ACK kubelet 的TLS 认证


ACK集群中kubelet默认开启https端口10250和只读端口10255,ack-prometheus采集kubelet指标走的http端口10255,无须tls认证。部分客户对安全性要求高禁止了10255,本文扩展讲解一下10250端口的tls认证。

小知识:--read-only-port=0 会关闭http监听,可以通过这个参数关闭或者修改只读端口,默认10255.

vi /etc/kubernetes/kubelet-customized-args.conf
# KUBELET_CUSTOMIZED_ARGS="--read-only-port=0 ..."
systemctl daemon-reload
systemctl restart kubelet


基于 kubelet认证的官方介绍,kubelet的tls认证分三种:

  • 匿名anonymous认证:默认禁止,比较简单,允许后不加证书即可访问https端口,所以非常不安全,不在本文赘述。
  • 基于客户端证书认证:类似etcd tls认证,比如api-server访问kubelet使用的就是客户端证书方式。但是kubelet默认开启了证书轮转更新,而且客户端证书拥有全部权限,可以访问kubelet所有的接口。出于安全考虑,prometheus不采用这种方式,客户端认证本文不赘述。
  • 基于SA bearer token认证:kubelet 也支持bearer token认证,通过service account的rbac绑定,可以限制权限仅开放/metrics接口,比较安全,prometheus访问kubelet就是采用这种方式,下文详细解析。


基于SA bearer token 访问kubelet tls端口的解析

看下kubelet https认证参数的官方解释:

--authentication-token-webhook=true This flag enables, that a ServiceAccount token can be used to authenticate against the kubelet(s). This can also be enabled by setting the kubelet configuration value authentication.webhook.enabled to true.
--authorization-mode=Webhook This flag enables, that the kubelet will perform an RBAC request with the API to determine, whether the requesting entity (Prometheus in this case) is allowed to access a resource, in specific for this project the /metrics endpoint. This can also be enabled by setting the kubelet configuration value authorization.mode to Webhook.


ACK集群kubelet默认启动参数如下,以下两个参数的配置即开启了token 认证方式(webhook)。

--authorization-mode=Webhook --authentication-token-webhook=true

kubelet 允许token 访问后,接下来看下token绑定的clusterrole中是否具备的nodes/metrics资源的相关权限 。

#省略无关行
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ack-prometheus-operator-prometheus
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics 
  verbs:
  - get
  - list
  - watch

curl模拟命令成功获取指标:

sa="ack-prometheus-operator-prometheus"
token=$(kubectl describe secret -n monitoring $(kubectl describe sa -n monitoring $sa |grep Token |awk '{print $2}') |grep token:|awk '{print $2}')
curl https://10.0.0.9:10250/metrics -H "Authorization: Bearer $token"  -k


实验1: 测试RBAC授权

若clusterrole中缺少nodes/metrics资源的get权限,会看到报错

Forbidden (user=system:serviceaccount:monitoring:ack-prometheus-operator-prometheus, verb=get, resource=nodes, subresource=metrics)


同理,换一个没RBAC授权的接口/configz 访问也会报错 :

curl https://10.0.0.9:10250/configz -H "Authorization: Bearer $token"  -k


Forbidden (user=system:serviceaccount:monitoring:ack-prometheus-operator-prometheus, verb=get, resource=nodes, subresource=proxy)


实验2:关闭kubelet webhook认证


关闭这俩 webhook参数:

vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --authentication-token-webhook=true --anonymous-auth=false --client-ca-file=/etc/kubernetes/pki/ca.crt"
修改为
Environment="KUBELET_AUTHZ_ARGS= --authentication-token-webhook=false --anonymous-auth=false --client-ca-file=/etc/kubernetes/pki/ca.crt"
重启
systemctl daemon-reload
systemctl restart kubelet



此时就可以模拟出kubelet https端口401/403了:


总结:

以上解析可以理解sa token可以通过kubelet 的tls认证,那么将serviceaccount 的token mount到prometheus server pod中,然后在抓取任务中指定这个token即可完成prometheus server 对 tls 指标的获取。K8s中pod指定的 Serviceaccount对应的token是默认mount 的,此处不举例。

scrape_configs:
- job_name: monitoring/kubelet-xxxx
  metrics_path: /metrics
  scheme: https
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    insecure_skip_verify: true
  #略



扩展:如何curl连接apiserver

既然可以使用serviceaccount的RBAC认证获取apiserver metrics数据,那么,直接向apiserver请求数据呢?

一样的道理,给SA足够BAC即可。我们借用默认的admin权限的SA: kube-system/admin.

SERVICE_ACCOUNT=admin
SECRET=$(kubectl get serviceaccount ${SERVICE_ACCOUNT} -n kube-system -o json | jq -Mr '.secrets[].name | select(contains("token"))')
TOKEN=$(kubectl get secret ${SECRET} -n kube-system -o json | jq -Mr '.data.token' | base64 -d)
kubectl get secret ${SECRET} -n kube-system  -o json | jq -Mr '.data["ca.crt"]' | base64 -d > /tmp/ca.crt
APISERVER=https://10.0.0.9:6443
APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
# 带证书访问--cacert /tmp/ca.crt
curl -s $APISERVER/apis   --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt 
#insecure访问 -k也可以
 curl -s -X GET $APISERVER/apis/metrics.k8s.io/v1beta1/nodes --header "Authorization: Bearer $TOKEN"  -k


相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
相关文章
|
3月前
|
存储 JSON Prometheus
如何精简 Prometheus 的指标和存储占用
如何精简 Prometheus 的指标和存储占用
|
3月前
|
存储 Prometheus Kubernetes
「译文」通过 Relabel 减少 Prometheus 指标的使用量
「译文」通过 Relabel 减少 Prometheus 指标的使用量
|
22天前
|
Prometheus 监控 Cloud Native
Prometheus结合Consul采集多个MySQL实例的监控指标
将 Prometheus 与 Consul 结合使用,实现对多个 MySQL 实例的自动发现与监控,不仅提高了监控的效率和准确性,也为管理动态扩缩容的数据库环境提供了强大的支持。通过细致配置每一部分,业务可以获得关键的性能指标和运行健康状况的即时反馈,进而优化资源配置,提高系统的稳定性和可用性。
38 3
|
26天前
|
测试技术 UED 存储
SLS Prometheus存储问题之在使用内置降采样时,SLS自动选择适配的指标库该如何解决
SLS Prometheus存储问题之在使用内置降采样时,SLS自动选择适配的指标库该如何解决
|
16天前
|
Prometheus 监控 Cloud Native
Gin 集成 prometheus 客户端实现注册和暴露指标
Gin 集成 prometheus 客户端实现注册和暴露指标
28 0
|
3月前
|
Prometheus Cloud Native
「译文」如何使用 PromQL join 来更有效地查询大规模的 Prometheus 指标
「译文」如何使用 PromQL join 来更有效地查询大规模的 Prometheus 指标
|
3月前
|
Prometheus 资源调度 监控
在Flink on Yarn中,确实可以使用Prometheus的Pushgateway来获取监控指标
在Flink on Yarn中,确实可以使用Prometheus的Pushgateway来获取监控指标
162 2
|
9月前
|
Prometheus 监控 Cloud Native
Prometheus监控Spring Boot应用,自定义应用监控指标
Prometheus监控Spring Boot应用,自定义应用监控指标
172 0
Prometheus监控Spring Boot应用,自定义应用监控指标
|
9月前
|
存储 Prometheus 监控
Prometheus 四种指标类型
Prometheus 四种指标类型
135 0
|
Prometheus 监控 Cloud Native
可以自定义指标的监控工具 - Prometheus的安装部署
可以自定义指标的监控工具 - Prometheus的安装部署
590 0