尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Kubernetes监控安全加固:为kube-prometheus配置统一OAuth2认证

Kubernetes监控安全加固:为kube-prometheus配置统一OAuth2认证 1. 从“裸奔”到“上锁”为什么你的监控面板需要身份认证如果你在生产环境用过 kube-prometheus大概率经历过这样一个场景在浏览器里输入http://你的节点IP:9090然后 Grafana 的仪表盘或者 Prometheus 的查询界面就直接打开了没有任何登录框没有任何密码验证。那一刻你是不是心里“咯噔”了一下这种感觉就像把自家大门的钥匙直接插在锁孔上然后出门逛街去了。kube-prometheus 是 Kubernetes 生态中部署监控栈的“事实标准”它打包了 Prometheus、Alertmanager、Grafana 以及一系列用于监控 Kubernetes 自身的 exporter。默认安装后这些组件的 Web UI 服务通常以ClusterIP或NodePort方式暴露并且没有启用任何身份认证。这意味着任何能够访问集群网络无论是内网还是通过某些方式暴露到了公网的人都可以查看所有监控指标、节点状态、Pod 资源使用情况这等同于业务架构和运行状态的完全暴露。在 Prometheus 里执行任意查询甚至通过某些特殊的查询对集群造成负载压力。在 Alertmanager 里静默或修改告警规则让故障发生时无人知晓。如果 Grafana 配置了数据源甚至可能通过它间接访问到数据库等其他敏感系统。这绝不是危言耸听。在安全左移和合规性要求日益严格的今天一个没有认证的监控入口在安全审计中就是一个必须立即修复的高危漏洞。所以为 kube-prometheus 添加身份认证不是一项“锦上添花”的优化而是保障系统安全性的“底线”操作。本文将带你绕过官方文档中相对零散的指引结合我多次在生产集群中实施的经验手把手完成从零到一的认证加固并分享几个关键环节中容易踩坑的细节。2. 认证方案选型Basic Auth、OAuth2 与反向代理的权衡在动手之前我们得先搞清楚有哪些“锁”可以选。为 Web 服务添加认证主流方案无外乎以下几类每种都有其适用的场景和复杂度。2.1 方案一应用层内置认证以 Grafana 为例这是最直接的方式。像 Grafana 本身就提供了完善的用户体系支持内置用户、LDAP、OAuth 等多种登录方式。你只需要在 Grafana 的配置中启用并配置它即可。对于 Prometheus 和 Alertmanager它们原生并不支持复杂的用户管理但可以通过启动参数配置非常基础的 HTTP Basic Authentication。优点实现简单与具体应用绑定不依赖外部组件。缺点不统一Prometheus、Alertmanager、Grafana 需要分别配置管理分散。功能弱Prometheus 的 Basic Auth 非常原始缺乏用户管理、角色权限等高级功能。配置繁琐密码需要以 Secret 形式挂载任何变更都需要更新配置并重启 Pod。对于小规模或测试环境直接配置 Grafana 的认证并将 Prometheus 和 Alertmanager 通过 Grafana 的数据源和 Alertmanager 数据源来访问即不直接暴露它们的 UI是一个快速可行的方案。但这并没有解决 Prometheus UI 本身暴露的问题。2.2 方案二Ingress 控制器集成认证这是目前生产环境最主流、最推荐的方式。通过 Kubernetes Ingress 资源配合 Nginx Ingress Controller 或 Traefik 等在流量入口处统一完成认证然后再将请求转发给后端的无认证服务。Basic Auth在 Ingress Annotations 中配置一个包含用户名密码的 Secret即可为整个路由添加基础的弹窗认证。OAuth2 / OIDC与公司的单点登录系统如 Keycloak, Okta, Google, GitHub OAuth集成。用户通过公司账号登录后Ingress Controller 会在请求头中注入认证信息如X-Auth-Email再转发给后端。优点统一入口一个配置点保护所有后端服务Prometheus, Alertmanager, Grafana。功能强大可以利用成熟的 OAuth2 提供商实现复杂的认证鉴权逻辑。对应用透明后端的 Prometheus 等应用完全无需修改它们接收到的已经是“已认证”的请求或附加了用户信息的请求。易于管理认证策略作为 Kubernetes 资源管理与代码部署流程一致。缺点需要部署和配置 Ingress Controller并对其认证模块有一定了解。2.3 方案三专用 API 网关或 Service Mesh对于超大规模或安全要求极高的集群可能会使用更重的方案如将监控流量全部经过 Ambassador、Gloo 等 API 网关或通过 Istio、Linkerd 等 Service Mesh 的入口网关Ingress Gateway来管理并在网关上配置认证策略。优点功能最全可观测性和策略控制粒度最细能与整个微服务的认证体系融合。缺点架构复杂运维成本高属于“杀鸡用牛刀”通常不是仅为了监控认证而引入。结论与选型建议 对于绝大多数使用 kube-prometheus 的场景方案二Ingress 控制器集成认证是最佳平衡点。它实现了安全、统一、易管理的目标且与 Kubernetes 原生集成度最高。下文也将以最流行的Nginx Ingress Controller配合OAuth2 代理为例进行详细演示。之所以选择 OAuth2 而非 Basic Auth是因为前者更适合团队协作无需分发和维护静态密码体验也更佳。3. 实战使用 OAuth2-Proxy 与 Nginx Ingress 搭建统一认证门户我们的目标是通过一个统一的域名如monitoring.your-company.com访问监控栈用户首先被重定向到公司的 OAuth2 提供商例如 GitHub、Google 或自建的 Keycloak进行登录登录成功后才能访问后端的 Prometheus、Alertmanager 和 Grafana。3.1 前置条件与环境准备假设你已经有一个正在运行的 Kubernetes 集群并且已经通过kube-prometheus-stackHelm Chart 或kube-prometheus的 manifests 文件部署了一套监控系统。同时假设你已有一个可用的 OAuth2 应用例如在 GitHub 上注册的 OAuth App。确保 Nginx Ingress Controller 已部署# 使用 Helm 部署是最简单的方式 helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace部署后获取 Ingress Controller 的服务外部 IP 或域名。准备域名和 TLS 证书准备一个域名如monitoring.your-company.com并将其 DNS A 记录指向上述 Ingress Controller 的外部 IP。生产环境务必使用 HTTPS你可以使用 Let‘s Encrypt 的 cert-manager 自动签发证书这超出了本文范围但强烈建议配置。创建 OAuth2 应用以 GitHub 为例在 Settings - Developer settings - OAuth Apps 中创建新应用。Homepage URL:https://monitoring.your-company.comAuthorization callback URL:https://monitoring.your-company.com/oauth2/callback创建成功后你会得到Client ID和Client Secret。请妥善保存Client Secret。3.2 部署与配置 OAuth2-ProxyOAuth2-Proxy 是一个独立的反向代理和身份认证提供者我们将把它作为 Sidecar 或独立 Deployment 运行与 Nginx Ingress 配合工作。创建存储 Client Secret 的 Kubernetes Secretkubectl create secret generic oauth2-proxy-secret -n monitoring \ --from-literalclient-secret你的 GitHub Client Secret注意这里假设你的 kube-prometheus 部署在monitoring命名空间。请根据实际情况调整。部署 OAuth2-Proxy以下是其 Deployment 和 Service 的示例 manifest。关键点在于–cookie-secret它用于加密会话 Cookie必须是一个随机的、足够长的字符串建议 32 字节base64 编码。# oauth2-proxy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: oauth2-proxy namespace: monitoring spec: replicas: 1 selector: matchLabels: app: oauth2-proxy template: metadata: labels: app: oauth2-proxy spec: containers: - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.0 ports: - containerPort: 4180 protocol: TCP args: - --providergithub - --email-domain* - --upstreamfile:///dev/null - --http-address0.0.0.0:4180 - --cookie-secret$(COOKIE_SECRET) - --client-id你的 GitHub Client ID - --client-secret$(CLIENT_SECRET) - --cookie-securetrue - --cookie-refresh1h - --cookie-expire4h - --skip-provider-buttontrue - --whitelist-domain.your-company.com env: - name: CLIENT_SECRET valueFrom: secretKeyRef: name: oauth2-proxy-secret key: client-secret - name: COOKIE_SECRET value: 随机生成的32字节base64字符串 # 可用命令生成openssl rand -base64 32 | head -c 32 | base64 --- apiVersion: v1 kind: Service metadata: name: oauth2-proxy namespace: monitoring spec: ports: - port: 4180 targetPort: 4180 protocol: TCP selector: app: oauth2-proxy重要提示--upstreamfile:///dev/null这个参数很关键。它告诉 OAuth2-Proxy 本身不反向代理任何实际应用它的工作仅仅是“认证”。认证通过后由 Nginx Ingress 根据auth_request模块的结果来决定是否转发请求到后端。3.3 配置 Nginx Ingress 的auth_request认证这是整个流程的核心。Nginx 的auth_request模块允许在将请求转发给上游Upstream服务之前先向另一个 URI 发起一个子请求进行认证。如果子请求返回 2xx则继续如果返回 401 或 403则拦截并重定向到登录页。创建 ConfigMap 配置 Nginx 模板片段我们需要告诉 Ingress Controller对于特定的域名启用auth_request模块并指向 OAuth2-Proxy 的验证端点/oauth2/auth。# ingress-nginx-cm.yaml apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx-controller namespace: ingress-nginx # 注意命名空间是 ingress-controller 所在的 data: proxy-set-headers: ingress-nginx/custom-headers这个 ConfigMap 告诉 Ingress Controller 去加载一个名为custom-headers的 ConfigMap 来设置请求头。创建自定义请求头 ConfigMap# custom-headers.yaml apiVersion: v1 kind: ConfigMap metadata: name: custom-headers namespace: ingress-nginx data: X-Auth-Request-Email: $auth_response_email # 将认证后的用户邮箱传递给后端创建关键的 Ingress 资源这个 Ingress 定义了路由规则和认证逻辑。# monitoring-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: monitoring-auth namespace: monitoring annotations: nginx.ingress.kubernetes.io/auth-response-headers: X-Auth-Request-Email nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd$request_uri nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.monitoring.svc.cluster.local:4180/oauth2/auth nginx.ingress.kubernetes.io/configuration-snippet: | auth_request_set $auth_response_email $upstream_http_x_auth_request_email; # 如果你的 OAuth2-Proxy 版本较新可能需要显式设置 upstream vhost nginx.ingress.kubernetes.io/auth-snippet: | proxy_set_header Host $host; # 以下为 TLS 和域名配置按需修改 cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: nginx tls: - hosts: - monitoring.your-company.com secretName: monitoring-tls-secret rules: - host: monitoring.your-company.com http: paths: - path: / pathType: Prefix backend: service: name: prometheus-operated # Prometheus 的 Service名称可能因部署方式而异 port: number: 9090 - path: /alertmanager pathType: Prefix backend: service: name: alertmanager-operated port: number: 9093 - path: /grafana pathType: Prefix backend: service: name: grafana port: number: 3000 # OAuth2-Proxy 的路由必须暴露以下两个路径 - path: /oauth2 pathType: Prefix backend: service: name: oauth2-proxy port: number: 4180关键注解解析auth-url: 认证检查的地址指向 OAuth2-Proxy 的/oauth2/auth端点。auth-signin: 当认证失败返回 401时重定向到的登录起始页指向 OAuth2-Proxy 的/oauth2/start。auth-response-headers: 从认证子请求的响应头中提取哪些头传递给上游后端服务。这里我们提取了邮箱。configuration-snippet: 一段自定义 Nginx 配置将子请求返回的X-Auth-Request-Email头值赋值给一个 Nginx 变量$auth_response_email。auth-snippet: 在认证子请求中设置 Host 头避免某些 OAuth2 提供商校验 Host 失败。4. 部署验证与深度排错指南应用上述所有配置后执行kubectl apply -f .。理论上现在访问https://monitoring.your-company.com你会被重定向到 GitHub 登录登录成功后才能看到 Prometheus 界面。但现实往往比理想骨感下面是我在多次部署中总结的排查链条。4.1 问题一无限重定向循环这是最常见的问题。表现是浏览器在 GitHub 登录成功回调后又立刻跳转到登录页陷入死循环。排查思路检查 Cookie 作用域这是最可能的原因。浏览器发送的 Cookie 作用域Domain必须与auth-url中配置的地址完全匹配。在我们的配置中auth-url使用的是 Kubernetes 内部 Service DNS 名http://oauth2-proxy.monitoring.svc.cluster.local:4180。而 OAuth2-Proxy 生成的 Cookie默认作用域是当前访问的浏览器地址即monitoring.your-company.com。当 Nginx 向内部地址发起auth子请求时浏览器不会携带这个 Cookie导致认证失败。解决方案在 OAuth2-Proxy 的启动参数中显式设置 Cookie 作用域。args: - ... - --cookie-domain.your-company.com # 注意前面的点表示所有子域名这确保了无论请求是发给外部域名还是内部 Service只要在your-company.com下Cookie 都会被发送。检查auth-url的可达性进入 Ingress Controller 的 Pod用curl手动测试auth-url。kubectl exec -it -n ingress-nginx ingress-controller-pod -- curl -v http://oauth2-proxy.monitoring.svc.cluster.local:4180/oauth2/auth如果返回401 Unauthorized说明 OAuth2-Proxy 服务正常但无有效 Cookie。如果连接失败检查 OAuth2-Proxy 的 Service 和 Endpoints 是否正确网络策略是否允许ingress-nginx命名空间的 Pod 访问monitoring命名空间的 Service。检查 OAuth2 回调地址确保在 GitHub OAuth App 中注册的Authorization callback URL完全正确必须是https://monitoring.your-company.com/oauth2/callback。多一个斜杠或少一个字母都会导致认证失败。4.2 问题二认证通过但访问后端服务出现 404 或错误检查 Ingress 路径与后端 Service 的映射确认prometheus-operated、alertmanager-operated、grafana这些 Service 名称和端口在你的集群中确实存在且正确。使用kubectl get svc -n monitoring查看。检查后端服务的root_url或web.external-url这是另一个巨坑。Prometheus 和 Grafana 等应用有时会根据请求的 Host 头来生成返回给前端的链接如静态资源路径、重定向地址。当经过多层代理后这个 Host 头可能被修改导致应用生成的链接错误。对于 Prometheus在 Prometheus Server 的启动命令或配置文件中需要设置--web.external-urlhttps://monitoring.your-company.com/prometheus。注意如果你的 Ingress 路径是/则这里就是https://monitoring.your-company.com/。这通常需要在kube-prometheus-stack的 values.yaml 中配置prometheus.prometheusSpec.externalUrl。对于 Grafana在 Grafana 的配置文件通常是 ConfigMap中设置[server]部分的root_url https://monitoring.your-company.com/grafana/。同样在 Helm Chart 中可以通过grafana.ini.server.root_url配置。 如果不设置应用可能会基于错误的 Base Path 生成资源链接导致前端页面 CSS/JS 加载失败或者 API 请求发往错误的路径。4.3 问题三如何实现基于邮箱域名的白名单或团队授权OAuth2-Proxy 提供了强大的会话管理和验证钩子。假设你只允许公司邮箱your-company.com访问。使用--email-domain参数在 OAuth2-Proxy 启动参数中设置--email-domainyour-company.com它会自动拒绝非该域名的邮箱登录。使用--whitelist-domain参数如上文配置确保 Cookie 在相关域名下共享。更精细的控制Google/GitHub 团队对于 GitHub你可以使用--github-team或--github-org参数只允许特定团队或组织的成员访问。这需要在 OAuth App 中申请相应的read:org权限。配置会更复杂一些需要传递--scope参数并可能自定义验证逻辑。5. 进阶考量认证后的细粒度权限控制RBAC通过上述步骤我们实现了“进门”的认证。但进门后是否所有人都能看所有数据通常我们需要更细粒度的控制例如运维团队可以查看所有数据并配置告警而开发团队只能查看其所属命名空间的指标。这超出了简单的入口认证范畴需要结合监控系统自身的权限模型。Prometheus 多租户与 RBAC原生 Prometheus 不支持用户级别的 RBAC。社区方案通常有两种Prometheus 联邦 按租户分实例为不同团队部署独立的 Prometheus 实例通过联邦Federation在顶层汇总部分数据。每个实例的访问权限独立控制。成本高管理复杂。使用代理层如 Thanos Query Frontend 或 Cortex这些分布式 Prometheus 方案在其查询前端Query Frontend集成了更完善的认证和授权中间件可以通过请求头中的用户信息如我们传递的X-Auth-Request-Email来动态过滤查询结果实现基于标签的权限控制。这是更现代和优雅的方案但架构复杂度显著提升。Grafana 数据源权限在 Grafana 中可以为不同团队创建不同的组织Organization并为每个组织分配不同的数据源Data Source权限。例如开发团队的 Grafana 组织只能访问标记了namespacedev-*的 Prometheus 数据源这需要 Prometheus 支持上述的查询过滤或者使用 Grafana 的企业版功能。结合我们传递的邮箱信息可以在 Grafana 中配置自动将用户分配到对应组织。告警管理权限Alertmanager 原生也不支持多租户。常见的做法是为不同业务线配置独立的 Alertmanager 实例或者使用类似alertmanager-bot这样的工具将告警路由到不同的通知渠道如不同的 Slack Channel实现逻辑上的隔离。实操建议对于大多数中小规模场景在入口处做好统一的强认证配合清晰的命名规范和标签体系如为所有指标打上teamdevops或teamproduct-a的标签然后通过 Grafana 仪表盘的文件夹权限进行分享管理是一个在安全性和复杂度之间取得平衡的实用方案。只有当团队规模很大、合规要求极严时才需要考虑引入 Thanos/Cortex 等重量级方案来实现查询层的 RBAC。整个配置过程最精髓的部分在于理解 Nginxauth_request模块与 OAuth2-Proxy 的协作流程以及 Cookie 作用域、上游应用外部 URL 这两个最容易出错的配置点。一旦打通这套方案不仅适用于 kube-prometheus几乎可以为集群内任何需要认证的 Web 服务提供统一的、基于 OAuth2 的单点登录入口极大地提升了集群内应用的安全水位。
返回列表