Open Source Technology Improvement Fund(OSTIF)公布了 Cortex 安全审计的完成情况,审计工作由 Quarkslab 参与实施。Cortex 为 Prometheus 和 OpenTelemetry 提供长期、可扩展的多租户开源存储,因此它不仅承载监控数据,还承担租户隔离、身份传递、对象存储访问和内部服务通信等安全责任。
一次独立审计的价值,不只是列出若干漏洞。它还为维护者和使用者提供了一份风险基线:哪些边界值得重点检查,哪些默认部署方式需要收紧,以及修复措施应该如何进入日常升级流程。
为什么 Cortex 的安全边界比较复杂
Cortex 通常由 Distributor、Ingester、Querier、Query Frontend、Store Gateway、Compactor 等多个组件组成。数据从写入入口流向内部服务、缓存和对象存储,查询请求则沿另一条路径读取并聚合数据。
这种架构带来几个需要持续验证的边界:
- 多租户隔离:请求携带的租户身份必须可信,查询和写入不能越过租户边界。
- 外部入口:写入与查询 API 需要认证、限流、超时和请求体大小限制。
- 内部通信:组件之间的 HTTP 或 gRPC 端口不应直接暴露到不受信任的网络。
- 对象存储权限:访问 S3、GCS 或兼容存储的凭据应遵循最小权限原则。
- 资源消耗:高基数标签、超大查询范围和异常并发都可能演变为拒绝服务风险。
来源摘要没有披露具体漏洞、严重等级或修复版本,因此不能据此推断某个 Cortex 版本存在特定缺陷。实际采用时,应结合正式审计报告、Cortex 安全公告和对应版本的发布说明确认影响范围。
审计完成后,使用者应该做什么
安全审计不会自动加固已经运行的集群。运维团队至少需要把审计结论转化为三类工作。
第一类是版本治理。记录当前 Cortex 镜像的精确版本或摘要,对照维护者发布的修复版本升级,并在预发布环境执行写入、查询、压缩和历史数据读取测试。不要长期使用浮动的 latest 标签。
第二类是入口治理。Cortex 常通过租户请求头区分数据归属,但请求头本身不等于认证。生产环境应由可信网关验证调用方身份,再写入或覆盖租户标识;客户端不应能够任意指定其他租户。
第三类是运行时收敛。限制容器权限、网络可达范围和服务账号权限,同时为查询并发、样本摄入和标签基数设置合理上限。这样即使输入异常,影响也更容易限制在单个租户或单个组件内。
可以这样实践:为 Kubernetes 部署增加最小安全基线
下面是一个可改造的 Kubernetes 示例。它不是审计报告给出的官方配置,而是一份通用加固起点。运行前需要替换命名空间、镜像版本、端口和 Pod 标签,使其与实际 Cortex 部署一致。
apiVersion: apps/v1
kind: Deployment
metadata:
name: cortex-distributor
namespace: observability
spec:
replicas: 2
selector:
matchLabels:
app: cortex-distributor
template:
metadata:
labels:
app: cortex-distributor
spec:
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: cortex
image: quay.io/cortexproject/cortex:v1.18.1
args:
- -target=distributor
- -config.file=/etc/cortex/cortex.yaml
ports:
- name: http
containerPort: 8080
- name: grpc
containerPort: 9095
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: config
mountPath: /etc/cortex
readOnly: true
- name: tmp
mountPath: /tmp
volumes:
- name: config
configMap:
name: cortex-config
- name: tmp
emptyDir: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cortex-distributor-ingress
namespace: observability
spec:
podSelector:
matchLabels:
app: cortex-distributor
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring-gateway
ports:
- protocol: TCP
port: 8080
应用前先让 Kubernetes 服务端执行校验:
kubectl apply --dry-run=server -f cortex-hardened.yaml
kubectl apply -f cortex-hardened.yaml
kubectl -n observability rollout status deployment/cortex-distributor
示例中的镜像版本只用于展示固定版本的写法,并不代表它一定是当前推荐版本。上线前应选择包含相关安全修复的受支持版本,最好进一步固定镜像摘要:
image: quay.io/cortexproject/cortex@sha256:REPLACE_WITH_VERIFIED_DIGEST
如果集群启用了默认拒绝网络策略,还需要显式添加 Cortex 组件访问 DNS、成员发现、缓存、对象存储及其他内部组件所需的出站规则。策略过严会导致服务不可用,策略过宽则失去隔离效果,因此应根据真实流量逐项放行。
验证租户身份没有被客户端绕过
可以在测试环境对入口网关做一个简单的负向验证。下面的地址、令牌和租户名称需要替换为实际值:
export CORTEX_URL="https://cortex.example.com"
export ACCESS_TOKEN="replace-with-test-token"
curl --fail-with-body \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "X-Scope-OrgID: another-tenant" \
"${CORTEX_URL}/api/prom/api/v1/query?query=up"
预期结果取决于网关设计:请求应被拒绝,或者网关应忽略客户端提供的租户头并使用经过认证的租户身份。若普通客户端可以通过修改请求头读取其他租户数据,就必须在入口层修复身份映射逻辑。
这类测试应覆盖查询、远程写入和规则相关入口,并避免在生产环境使用真实跨租户数据做破坏性验证。
把一次审计变成持续控制
采用审计成果时,可以按下面的清单推进:
- 获取正式审计报告,确认发现项、影响版本、修复状态和剩余风险。
- 将 Cortex 组件升级到维护者建议的受支持版本,并固定镜像版本或摘要。
- 确保租户请求头只能由认证网关注入或覆盖。
- 限制外部入口和组件内部端口的网络可达性。
- 使用最小权限访问对象存储、Kubernetes API 和密钥系统。
- 配置摄入、查询、并发与资源限制,并针对单个租户设置保护措施。
- 在 CI 或预发布环境加入跨租户负向测试和升级回归测试。
- 订阅 Cortex、OSTIF 及相关依赖的后续安全公告。
独立安全审计提高了 Cortex 风险状况的可见性,但审计完成并不等于部署自动安全。真正决定结果的,是团队能否核对正式发现、及时升级,并把身份校验、网络隔离、最小权限和滥用防护固化到每次发布中。