一文读懂什么是K8s Admission Controller

news/2025/2/26 19:31:06

#作者:曹付江

文章目录

  • 1、什么是 Admission Controllers?
  • 2、如何创建 Admission Controllers?
  • 3、Admission 控制器的最佳实践

K8s 中的操作与安全标准执行机制:
在这里插入图片描述

1、什么是 Admission Controllers?

Admission controllers 是一段拦截请求的代码,它会在请求被持久化之前验证或更改(变更)这些请求。Admission controllers 与外部 WebHook 连接,处理入驻请求。因此,它们也被称为 Admission WebHook。该 WebHook 在对象创建、修改或删除最终确定之前接收 K8s 的入驻请求。

我们可以定义两种类型的 Admission controllers:

  • MutatingAdmissionWebhook:该控制器既可以验证也可以更改请求。
  • ValidatingAdmissionWebhook:该控制器只能验证请求。
    Admission Controller 是在需要强制执行特定组织政策时最有效的选项之一,例如:
  • 确保所有容器都有资源限制,以避免资源占用过多。
  • 阻止某些常见的镜像标签。
  • 强制执行资源的命名规范。
  • 限制仅允许来自受信任注册表的批准容器镜像。
    检查内建的 Admission controllers:
    在这里插入图片描述
    在这里插入图片描述

2、如何创建 Admission Controllers?

要创建一个 Mutating Admission Webhook,我们需要以下内容:

  1. 用于 Webhook 的 Web 应用程序
  2. 运行 Web 应用程序的服务帐户
  3. 用于托管 Web 应用程序的 Deployment
  4. 用于将流量路由到 Web 应用程序的 Service
  5. 一个 ClusterRole,定义 API 级别的访问权限(此博客未详细介绍)
  6. 一个 ClusterRoleBinding,将服务帐户与 ClusterRole 关联
  7. 一个 Secret,包含 Web 应用程序用于提供 TLS 的证书。(K8s 会向我们的服务发起 HTTPS 调用,因此需要有效的 SSL/TLS 证书)

WebHook 服务器
在本文章中,我将使用基于 Python 的 Webhook,使用 Sanic 框架。

FROM sanicframework/sanic:LTS
RUN pip install jsonpatch
COPY apps.py apps.py
ENTRYPOINT ["sanic", "apps:app", "--host=0.

上面的 Dockerfile 将创建用于运行 Web 服务器的镜像。这里我们挂载了一个卷(来自 secret),该卷将用于 TLS 证书。

apps.py 的内容:

import base64
import json as nativejson
from copy import deepcopy
from pprint import pformat

import jsonpatch
from sanic import Request, Sanic
from sanic.log import logger
from sanic.response import json

app = Sanic(name=__name__)

@app.post("/validate")
async def validate(request: Request):
    allowed = True
    message = ""
    try:
        pass 
        # add logic to validate th
        # update allowed & message accordingly
    except KeyError:
        pass
    return json(
        {
            "response": {
                "allowed": allowed,
                "uid": request.json["request"]["uid"],
                "status": {"message": message},
            }
        }
    )


@app.post("/mutate")
async def mutate(request: Request):
    logger.info(f"Obtained Request \n {pformat(request.json)}")
    original_spec = request.json["request"]["object"]
    modified_spec = deepcopy(spec)
    try:
        pass
        # add logic to update
        # update the modified_spec
    except KeyError:
        pass
    patch = jsonpatch.JsonPatch.from_diff(spec, modified_spec)
    return json(
        {
            "response": {
                "allowed": True,
                "uid": request.json["request"]["uid"],
                "patch": base64.b64encode(nativejson.dumps(patch).encode()).decode(),
                "patchtype": "JSONPatch",
            }
        }
    )


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=443)

Kubernetes 对验证的期望是返回一个简单的响应,值为 False 或 True。因此,在上述代码中,我们返回 allowed 为 True 或 False。在变更 Webhook 的情况下,我们还返回补丁(新旧对象的差异)。

创建 Webhook 的清单:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admission-controller
  namespace: admission-webhook-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admission-demo-rbac
subjects:
  - kind: ServiceAccount
    name: admission-controller
    namespace: admission-webhook-ns
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: v1
kind: Service
metadata:
  name: admission-webhook-svc
  namespace: admission-webhook-ns
  labels:
    app: admission-webhook-demo
spec:
  ports:
  - port: 443
    targetPort: 3030
  selector:
    app: admission-webhook-demo
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: admission-controller-cert
  namespace: admission-webhook-ns
spec:
  dnsNames:
  - admission-webhook-svc
  - admission-webhook-svc.admission-webhook-ns
  - admission-webhook-svc.admission-webhook-ns.svc
  issuerRef:
    kind: ClusterIssuer
    name: ca-issuer
  secretName: admission-controller-secret
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: admission-webhook-deployment
  namespace: admission-webhook-ns
  labels:
    app: admission-webhook-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: admission-webhook-demo
  template:
    metadata:
      labels:
        app: admission-webhook-demo
    spec:
      serviceAccountName: admission-controller
      containers:
        - name: admission-webhook-demo
          image: asrathore08/admission-controller:latest
          imagePullPolicy: Always
          resources:
            limits:
              cpu: 1000m
              memory: 512Mi
          volumeMounts:
          - name: webhook-certs
            mountPath: /mnt/certs
            readOnly: true
          - name: admission-controller-conf
            mountPath: /mnt/conf
      volumes:
      - name: webhook-certs
        secret:
          secretName: admission-controller-secret
      - name: admission-controller-conf
        configMap:
          name: admission-controller-configmap

在 Kubernetes 中注册 Webhook:
创建一个 ValidatingWebhookConfiguration,指向我们的 webhook 服务器。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: admission-service-delete-pod-validate
  namespace: admission-webhook-ns
  labels:
    app: admission-webhook-demo
  annotations:
    cert-manager.io/inject-ca-from: admission-webhook-ns/admission-controller-cert
webhooks:
- name: validate.webhook.demo
  clientConfig:
    service:
      name: admission-webhook-svc
      namespace: admission-webhook-ns
      path: "/validate"
  admissionReviewVersions: ["v1"]
  sideEffects: None
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1", "v1beta1"]
    resources: ["configmaps"]
    scope: "Namespaced"
  namespaceSelector:
    matchLabels:
      demo-admission-validation: enabled
  failurePolicy: Ignore

注意:这里我使用了 cert-manager CRD 来生成 TLS/SSL 证书。注解 cert-manager.io/inject-ca-from 有助于获取证书。

创建一个 MutatingWebhookConfiguration,指向我们的 webhook 服务器:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: admission-service-configmap-mutate
  namespace: admission-webhook-ns
  labels:
    app: mutating-admission-webhook
  annotations:
    cert-manager.io/inject-ca-from: admission-webhook-ns/admission-controller-cert
webhooks:
- name: mutate.webhook.demo
  clientConfig:
    service:
      name: admission-webhook-svc
      namespace: admission-webhook-ns
      path: "/mutate"
  admissionReviewVersions: ["v1"]
  sideEffects: None
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1", "v1beta1"]
    resources: ["configmaps"]
    scope: "Namespaced"
  namespaceSelector:
    matchLabels:
      demo-admission-validation: enabled
  failurePolicy: Ignore

上面,我们定义了一个 mutating 和一个 validating webhook。我们只启用了这些 webhooks 处理在具有标签 demo-admission-validation 设置为 enabled 的命名空间中创建或更新的对象。此功能允许我们控制 webhook 的作用范围。

  • MutatingAdmissionWebhook — 转换器
  • ValidatingAdmissionWebhook — 审核员

注意:在上述 webhook 中,我将资源限制为 configmap。K8s 上的 Apache Spark 使用 configmap 来存储 Spark 配置。这种 webhook 可以控制用户为某些配置提供的值,并且可以为某些配置注入特定的默认值。

一旦部署,Webhook 将接收以下请求体的请求。

#
{
    "kind": "AdmissionReview",
    "request": {
        "kind": {
            "kind": "Pod",
            "version": "v1",
            "group": ""
        },
        "resource": {
            "resource": "pods",
            "version": "v1",
            "group": ""
        },
        "uid": "b06b6ec2-681d-11e9-a645-06b44ed6a042",
        "object": {
            "status": {},
            "spec": {
                "dnsPolicy": "ClusterFirst",
                "securityContext": {},
                "serviceAccountName": "",
                "schedulerName": "default-scheduler",
                "serviceAccount": "",
                "priority": 0,
                "terminationGracePeriodSeconds": 30,
                "restartPolicy": "Always",
                "containers": [
                    {
                        "name": "",
                        "image": "",
                        "imagePullPolicy": "Always",
                        "ports": [
                            {
                                "protocol": "TCP",
                                "containerPort": 80
                            }
                        ],
                        "resources": {}
                    }
                ]
            },
            "metadata": {
            }
        },
        "namespace": "",
        "userInfo": {
            "username": "",
            "groups": [
                "system:masters",
                "system:authenticated"
            ]
        },
        "oldObject": null,
        "dryRun": false,
        "operation": "CREATE"
    },
    "apiVersion": "admission.k8s.io/v1beta1"
}

控制器将以特定格式返回响应。响应格式如下所述。

# Response
{
    "body": {
    "kind": "AdmissionReview",
    "apiVersion": "admission.k8s.io/v1",
    "response": {
        "uid": "request.uid",
        "allowed": "True",
        "patch": "patch_base64",
        "patchType": "JSONPatch"
    },
    "headers": {
      "Content-Type": "application/json"
    },
    "statusCode": 200
}

# patch_base64

[
    {
        "op": "replace",
        "path": "/spec/containers/0/image",
        "value": "xxxx.dkr.ecr.us-west-2.amazonaws.com/nginx:latest"
    }
]

3、Admission 控制器的最佳实践

  1. 我们应该确保 webhook 尽可能轻量化。
  2. 我们应该在开发环境中彻底测试我们的 webhook,以确保它们不会无意中阻止合法的请求。
  3. 我们应该详细记录 admission 控制决策,并对被拒绝的请求进行故障排除。

http://www.niftyadmin.cn/n/5869102.html

相关文章

LabVIEW形状误差测量系统

在机械制造领域,形状与位置公差(GD&T)直接影响装配精度与产品寿命。国内中小型机加工企业因形状误差导致的返工率高达12%-18%。传统测量方式存在以下三大痛点: ​ 设备局限:机械式千分表需人工读数,精度…

u3d预制件笔记

本文意在整合预制件相关重要信息,将较多的信息量浓缩出精华,并记录个人理解心得 一.预制件的概念和用途 Unity 的预制件系统允许创建、配置和存储游戏对象及其所有组件、属性值和子游戏对象作为可重用资源。预制件资源充当模板,在此模板的基…

OkHttp、Retrofit、RxJava:一文讲清楚

一、okHttp的同步和异步请求 Call 是 OkHttp 的核心接口,代表一个已准备好执行的 HTTP 请求。它支持 同步 和 异步 两种模式: enqueue——>okHttp异步 OkHttpClient client new OkHttpClient();Request request new Request.Builder().url("…

UIAutomation开发常用方法的参考文档

简介 由于UIAutomation的官方文档只有一个github中的readme文件,只是简单的使用示例,具体使用还需要在代码中查找,非常不方便。经过我多年使用UIAutomation开发的经验和整理,把常用的功能梳理成本文档,作为我的开发参考使用,这样就不用每次都翻代码了,同时也可以使用AI…

【机器学习】强化学习(2)——捋清深度强化学习的思路

在之前学习的过程中我了解到深度学习中很重要的一个概念是反向传播,最近看论文发现深度强化学习(DRL)有各种各样的方法,但是却很难区分他们的损失函数的计算以及反向传播的过程有何不同。在有监督的学习中,损失可以理解…

什么是死锁?构成死锁的条件如何解决

什么是死锁?构成死锁的条件&如何解决 1. 什么是死锁 在计算机科学中,死锁是一种非常常见且棘手的问题。从线程和锁的角度来看,死锁主要存在三种典型情况:一线程一锁、两线程两锁以及 M 线程 N 锁。接下来,我们将…

微信小程序源码逆向 MacOS

前言 日常工作中经常会遇到对小程序的渗透测试,微信小程序的源码是保存在用户客户端本地,在渗透的过程中我们需要提取小程序的源码进行问题分析,本篇介绍如何在苹果电脑 MacOS 系统上提取微信小程序的源码。 0x01 微信小程序提取 在苹果电…

HTML解析 → DOM树 CSS解析 → CSSOM → 合并 → 渲染树 → 布局 → 绘制 → 合成 → 屏幕显示

一、关键渲染流程 解析 HTML → 生成 DOM 树 浏览器逐行解析 HTML&#xff0c;构建**DOM&#xff08;文档对象模型&#xff09;**树状结构 遇到 <link> 或 <style> 标签时会暂停 HTML 解析&#xff0c;开始加载 CSS 解析 CSS → 生成 CSSOM 将 CSS 规则解析为**…