Kubernetes 安全运维:API Server 审计与 Admission Controller 实践

各位 Kubernetes 探险家们,早上好!☕

今天我们要聊的是 Kubernetes 王国的安全命脉——API Server 审计与 Admission Controller。这两位可是 Kubernetes 安全界的“双子星”,一个负责事后追查,一个负责事前把关,珠联璧合,守护着我们的集群安全。

别害怕,这听起来好像很厉害的样子,其实就像给你的城堡🏰设置了双重保险,确保任何试图进入的家伙都得经过严格的审查,任何可疑的行为都会被记录在案。

准备好了吗?让我们一起踏上这段安全之旅,揭开这两位“安全卫士”的神秘面纱!

第一站:API Server 审计,Kubernetes 的“黑匣子” 🕵️‍♂️

想象一下,你的 Kubernetes 集群就像一个繁忙的都市,每天发生着各种各样的事件:Pod 被创建、Deployment 被更新、Service 被暴露…… 如果没有一个靠谱的“监控摄像头”,我们怎么知道谁做了什么,何时做的?

这就是 API Server 审计的作用!它就像一个“黑匣子”,记录着所有对 Kubernetes API Server 的请求,包括谁发起的请求、请求的内容、以及请求的结果。有了这些信息,我们就可以:

  • 事后追责: 发生了安全事件?不用慌!翻看审计日志,找到肇事者,让他“吃不了兜着走”。
  • 安全分析: 通过分析审计日志,我们可以发现潜在的安全风险,比如异常的用户行为、未授权的访问等等。
  • 合规性审计: 满足各种合规性要求,证明你的 Kubernetes 集群是安全可靠的。

那么,如何开启这个“黑匣子”呢?

其实很简单,只需要配置 API Server 的审计策略即可。审计策略定义了哪些事件需要被记录,以及如何记录。

我们可以通过一个 YAML 文件来配置审计策略,就像这样:

apiVersion: audit.k8s.io/v1
kind: Policy
metadata:
  name: default
rules:
  - level: Metadata
    users: ["system:serviceaccount:kube-system:default"]
    verbs: ["get", "watch", "list"]
    resources:
      - groups: [""]
        resources: ["pods"]
  - level: RequestResponse
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - groups: [""]
        resources: ["pods", "services", "deployments"]
  - level: RequestResponse
    verbs: ["*"]
    resources:
      - groups: [""]
        resources: ["secrets", "configmaps"]

这个策略定义了三个规则:

  1. 对于 kube-system 命名空间下的 default ServiceAccount,只记录对 Pod 的 getwatchlist 请求的元数据。
  2. 对于 Pod、Service、Deployment 的 createupdatepatchdelete 请求,记录完整的请求和响应。
  3. 对于 Secret、ConfigMap 的所有请求,记录完整的请求和响应。

审计级别 (Audit Level):

审计级别决定了记录事件的详细程度。常用的审计级别有:

  • None: 不记录任何事件。
  • Metadata: 只记录事件的元数据,比如请求者、请求时间、资源类型等等。
  • Request: 记录事件的元数据和请求内容。
  • RequestResponse: 记录事件的元数据、请求内容和响应内容。
  • RequestResponseBody: 记录事件的元数据、请求内容,响应内容,以及请求和响应的内容体。

📝小贴士:

  • 审计策略越详细,记录的信息就越多,但也意味着更高的性能开销。所以要根据实际需求选择合适的审计级别。
  • 审计日志可以输出到文件、syslog、webhook 等多种目标。选择合适的输出目标,方便后续的分析和处理。

审计日志长什么样?

审计日志通常是 JSON 格式的,包含了事件的各种信息,比如:

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "metadata": {
    "creationTimestamp": "2023-10-27T08:00:00Z"
  },
  "stage": "ResponseComplete",
  "requestReceivedTimestamp": "2023-10-27T07:59:59Z",
  "stageTimestamp": "2023-10-27T08:00:00Z",
  "verb": "create",
  "user": {
    "username": "kube-admin",
    "groups": [
      "system:masters",
      "system:authenticated"
    ]
  },
  "sourceIPs": [
    "10.0.0.1"
  ],
  "objectRef": {
    "resource": "pods",
    "namespace": "default",
    "name": "my-pod"
  },
  "requestURI": "/api/v1/namespaces/default/pods",
  "responseStatus": {
    "code": 201,
    "status": "Created"
  }
}

通过分析这些日志,我们可以了解集群中发生的各种事件,并及时发现潜在的安全风险。

第二站:Admission Controller,Kubernetes 的“安全门卫” 👮‍♀️

API Server 审计是事后追查,那有没有什么办法可以在事前阻止恶意请求呢?

答案就是:Admission Controller!

Admission Controller 就像 Kubernetes 的“安全门卫”,它会在请求到达 API Server 之前进行拦截,根据预定义的规则对请求进行验证和修改。只有通过了 Admission Controller 的检查,请求才能被 API Server 接受。

Admission Controller 的工作流程:

  1. 用户发起一个请求,比如创建一个 Pod。
  2. 请求首先到达 API Server。
  3. API Server 将请求发送给 Admission Controller。
  4. Admission Controller 根据预定义的规则对请求进行验证和修改。
  5. 如果请求通过了检查,Admission Controller 将修改后的请求返回给 API Server。
  6. API Server 将请求持久化到 etcd 中。
  7. API Server 将响应返回给用户。

Admission Controller 的类型:

Admission Controller 可以分为两种类型:

  • Mutating Admission Controller: 可以修改请求。
  • Validating Admission Controller: 只能验证请求,不能修改请求。

Kubernetes 内置了一些 Admission Controller,比如:

  • NamespaceLifecycle: 防止删除活跃的命名空间。
  • PodSecurityPolicy: 限制 Pod 的安全配置。
  • ResourceQuota: 限制命名空间的资源使用。

自定义 Admission Controller:

除了使用 Kubernetes 内置的 Admission Controller,我们还可以自定义 Admission Controller,以满足特定的安全需求。

自定义 Admission Controller 通常使用 Webhook 的方式实现。Webhook Admission Controller 实际上是一个 HTTP 服务,它接收 API Server 发送的 AdmissionReview 请求,并根据自定义的逻辑进行验证和修改,然后将结果返回给 API Server。

举个栗子:限制 Pod 的镜像来源

假设我们只想允许 Pod 使用来自 my-registry.com 的镜像。我们可以创建一个 Validating Admission Webhook 来实现这个功能。

首先,我们需要创建一个 Webhook 服务:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: image-validator
spec:
  selector:
    matchLabels:
      app: image-validator
  template:
    metadata:
      labels:
        app: image-validator
    spec:
      containers:
        - name: image-validator
          image: your-image-validator-image
          ports:
            - containerPort: 8080

这个 Deployment 创建了一个 Pod,Pod 中运行着我们的 Webhook 服务。

然后,我们需要创建一个 Service 来暴露这个 Webhook 服务:

apiVersion: v1
kind: Service
metadata:
  name: image-validator
spec:
  selector:
    app: image-validator
  ports:
    - port: 443
      targetPort: 8080

这个 Service 将 Pod 的 8080 端口映射到 Service 的 443 端口。注意,这里使用了 443 端口,因为 Admission Webhook 必须使用 HTTPS。

接下来,我们需要创建一个 ValidatingWebhookConfiguration 来告诉 API Server 如何调用我们的 Webhook 服务:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: image-validator
webhooks:
  - name: image-validator.example.com
    clientConfig:
      service:
        name: image-validator
        namespace: default
        path: "/validate"
      caBundle: your-ca-bundle
    rules:
      - apiGroups:   [""]
        apiVersions: ["v1"]
        operations:  ["CREATE", "UPDATE"]
        resources:   ["pods"]
    admissionReviewVersions: ["v1", "v1beta1"]
    sideEffects: None

这个 ValidatingWebhookConfiguration 定义了一个 Webhook,它会拦截对 Pod 的 CREATEUPDATE 请求,并将请求发送到 image-validator Service 的 /validate 路径。

⚠️ 注意:

  • caBundle 是用于验证 Webhook 服务证书的 CA 证书。你需要将 Webhook 服务的 CA 证书编码成 Base64 字符串,并替换 your-ca-bundle
  • sideEffects: None 表示 Webhook 服务没有副作用,也就是说,它不会修改任何资源的状态。

最后,我们需要编写 Webhook 服务的代码,来验证 Pod 的镜像来源:

from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/validate', methods=['POST'])
def validate():
    request_info = request.get_json()
    pod = request_info['request']['object']
    for container in pod['spec']['containers']:
        image = container['image']
        if not image.startswith('my-registry.com'):
            return jsonify({
                'apiVersion': 'admission.k8s.io/v1',
                'kind': 'AdmissionReview',
                'response': {
                    'uid': request_info['request']['uid'],
                    'allowed': False,
                    'status': {
                        'reason': f'Image {image} is not from my-registry.com'
                    }
                }
            })

    return jsonify({
        'apiVersion': 'admission.k8s.io/v1',
        'kind': 'AdmissionReview',
        'response': {
            'uid': request_info['request']['uid'],
            'allowed': True
        }
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

这个 Python 代码定义了一个 Flask 应用,它监听 /validate 路径,并接收 AdmissionReview 请求。它会检查 Pod 的所有容器的镜像是否来自 my-registry.com,如果不是,则返回一个错误,阻止 Pod 的创建或更新。

🎉 大功告成!

现在,任何试图创建或更新使用非 my-registry.com 镜像的 Pod 的请求都会被 Admission Controller 拦截,从而保证了集群的安全。

总结:

API Server 审计和 Admission Controller 是 Kubernetes 安全的两大支柱。API Server 审计负责事后追查,Admission Controller 负责事前把关。通过合理配置和使用它们,我们可以构建一个安全可靠的 Kubernetes 集群。

特性 API Server 审计 Admission Controller
作用 事后追查,记录所有 API 请求 事前把关,验证和修改 API 请求
工作方式 被动记录 主动拦截
类型 Mutating (修改请求), Validating (验证请求)
使用场景 安全事件调查、安全分析、合规性审计 权限控制、资源限制、安全策略强制执行
优缺点 记录详细,但性能开销大;无法阻止恶意请求 可以阻止恶意请求,但配置复杂;可能影响集群性能

最后的温馨提示:

安全是一个持续的过程,而不是一蹴而就的事情。我们需要不断学习和实践,才能构建一个真正安全的 Kubernetes 集群。

希望今天的分享对你有所帮助!下次再见!👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注