×

关于准入插件

准入插件拦截对主 API 的请求以验证资源请求。在请求经过身份验证和授权后,准入插件确保遵循任何关联的策略。例如,它们通常用于实施安全策略、资源限制或配置要求。

准入插件作为准入链按顺序运行。如果序列中的任何准入插件拒绝请求,则整个链将中止并返回错误。

OpenShift Container Platform 为每种资源类型启用了一组默认的准入插件。这些对于集群的正常运行是必需的。准入插件会忽略它们不负责的资源。

除了默认设置外,还可以通过调用自定义 Webhook 服务器的 Webhook 准入插件动态扩展准入链。Webhook 准入插件有两种类型:修改型准入插件和验证型准入插件。修改型准入插件首先运行,可以修改资源和验证请求。验证型准入插件验证请求,并在修改型准入插件之后运行,以便也可以验证修改型准入插件触发的修改。

通过修改型准入插件调用 Webhook 服务器可能会对与目标对象相关的资源产生副作用。在这种情况下,必须采取步骤验证最终结果是否符合预期。

应谨慎使用动态准入,因为它会影响集群控制平面操作。在 OpenShift Container Platform 4.17 中通过 Webhook 准入插件调用 Webhook 服务器时,请确保已完整阅读文档并测试了突变的副作用。包括在请求未通过整个准入链的情况下将资源恢复到其原始状态的步骤。

默认准入插件

OpenShift Container Platform 4.17 中启用了默认的验证和准入插件。这些默认插件有助于基本控制平面功能,例如入口策略、集群资源限制覆盖和配额策略。

不要在默认项目中运行工作负载或共享对默认项目的访问权限。默认项目保留用于运行核心集群组件。

以下默认项目被认为是高度特权的:`default`、`kube-public`、`kube-system`、`openshift`、`openshift-infra`、`openshift-node`以及其他将`openshift.io/run-level`标签设置为`0`或`1`的系统创建的项目。依赖于准入插件的功能(例如 Pod 安全准入、安全上下文约束、集群资源配额和镜像引用解析)在高度特权的项目中不起作用。

以下列表包含默认准入插件

验证型准入插件
  • LimitRanger

  • ServiceAccount

  • PodNodeSelector

  • Priority

  • PodTolerationRestriction

  • OwnerReferencesPermissionEnforcement

  • PersistentVolumeClaimResize

  • RuntimeClass

  • CertificateApproval

  • CertificateSigning

  • CertificateSubjectRestriction

  • autoscaling.openshift.io/ManagementCPUsOverride

  • authorization.openshift.io/RestrictSubjectBindings

  • scheduling.openshift.io/OriginPodNodeEnvironment

  • network.openshift.io/ExternalIPRanger

  • network.openshift.io/RestrictedEndpointsAdmission

  • image.openshift.io/ImagePolicy

  • security.openshift.io/SecurityContextConstraint

  • security.openshift.io/SCCExecRestrictions

  • route.openshift.io/IngressAdmission

  • config.openshift.io/ValidateAPIServer

  • config.openshift.io/ValidateAuthentication

  • config.openshift.io/ValidateFeatureGate

  • config.openshift.io/ValidateConsole

  • operator.openshift.io/ValidateDNS

  • config.openshift.io/ValidateImage

  • config.openshift.io/ValidateOAuth

  • config.openshift.io/ValidateProject

  • config.openshift.io/DenyDeleteClusterConfiguration

  • config.openshift.io/ValidateScheduler

  • quota.openshift.io/ValidateClusterResourceQuota

  • security.openshift.io/ValidateSecurityContextConstraints

  • authorization.openshift.io/ValidateRoleBindingRestriction

  • config.openshift.io/ValidateNetwork

  • operator.openshift.io/ValidateKubeControllerManager

  • ValidatingAdmissionWebhook

  • ResourceQuota

  • quota.openshift.io/ClusterResourceQuota

修改型准入插件
  • NamespaceLifecycle

  • LimitRanger

  • ServiceAccount

  • NodeRestriction

  • TaintNodesByCondition

  • PodNodeSelector

  • Priority

  • DefaultTolerationSeconds

  • PodTolerationRestriction

  • DefaultStorageClass

  • StorageObjectInUseProtection

  • RuntimeClass

  • DefaultIngressClass

  • autoscaling.openshift.io/ManagementCPUsOverride

  • scheduling.openshift.io/OriginPodNodeEnvironment

  • image.openshift.io/ImagePolicy

  • security.openshift.io/SecurityContextConstraint

  • security.openshift.io/DefaultSecurityContextConstraints

  • MutatingAdmissionWebhook

Webhook 准入插件

除了 OpenShift Container Platform 默认准入插件之外,还可以通过调用 Webhook 服务器的 Webhook 准入插件来实现动态准入,以扩展准入链的功能。Webhook 服务器在定义的端点上通过 HTTP 调用。

OpenShift Container Platform 中有两种类型的 Webhook 准入插件

  • 在准入过程中,*修改型准入插件*可以执行任务,例如注入亲和性标签。

  • 在准入过程结束时,*验证型准入插件*可用于确保对象已正确配置,例如确保亲和性标签符合预期。如果验证通过,OpenShift Container Platform 将按配置调度对象。

当 API 请求进入时,修改型或验证型准入插件使用配置中的外部 Webhook 列表并并行调用它们。

  • 如果所有 Webhook 都批准请求,则准入链将继续。

  • 如果任何 Webhook 拒绝请求,则准入请求将被拒绝,拒绝的原因基于第一次拒绝。

  • 如果多个 Webhook 拒绝准入请求,则仅将第一次拒绝的原因返回给用户。

  • 如果调用 Webhook 时遇到错误,请求将根据设置的错误策略被拒绝或忽略。如果错误策略设置为忽略,则在发生故障时会无条件接受请求。如果策略设置为失败,则拒绝失败的请求。使用忽略可能会导致所有客户端出现不可预测的行为。

Webhook 准入插件和 Webhook 服务器之间的通信必须使用 TLS。生成 CA 证书,并使用该证书签署 Webhook 准入服务器使用的服务器证书。PEM 编码的 CA 证书通过某种机制提供给 Webhook 准入插件,例如服务提供证书密钥。

下图说明了调用多个 Webhook 服务器的顺序准入链流程。

API admission stage
图 1. 具有变更和验证准入插件的 API 准入链

Webhook 准入插件的一个示例用例是所有 Pod 都必须具有公共标签集。在此示例中,变更准入插件可以注入标签,而验证准入插件可以检查标签是否符合预期。OpenShift Container Platform 随后将调度包含所需标签的 Pod 并拒绝不包含所需标签的 Pod。

一些常见的 Webhook 准入插件用例包括:

  • 命名空间预留。

  • 限制由 SR-IOV 网络设备插件管理的自定义网络资源。

  • 定义容忍度,使污点能够限定哪些 Pod 应该调度到节点上。

  • Pod 优先级类验证。

OpenShift Container Platform 中最大的默认 Webhook 超时值为 13 秒,并且无法更改。

Webhook 准入插件类型

集群管理员可以通过 API 服务器准入链中的变更准入插件或验证准入插件调用 Webhook 服务器。

变更准入插件

变更准入插件在准入过程的变异阶段被调用,允许在资源持久化之前修改资源内容。可以通过变更准入插件调用的一个示例 Webhook 是 Pod 节点选择器功能,该功能使用命名空间上的注释来查找标签选择器并将其添加到 Pod 规范中。

变更准入插件配置示例
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration (1)
metadata:
  name: <webhook_name> (2)
webhooks:
- name: <webhook_name> (3)
  clientConfig: (4)
    service:
      namespace: default (5)
      name: kubernetes (6)
      path: <webhook_url> (7)
    caBundle: <ca_signing_certificate> (8)
  rules: (9)
  - operations: (10)
    - <operation>
    apiGroups:
    - ""
    apiVersions:
    - "*"
    resources:
    - <resource>
  failurePolicy: <policy> (11)
  sideEffects: None
1 指定变更准入插件配置。
2 MutatingWebhookConfiguration 对象的名称。将<webhook_name>替换为适当的值。
3 要调用的 Webhook 的名称。将<webhook_name>替换为适当的值。
4 关于如何连接、信任和向 Webhook 服务器发送数据的相关信息。
5 创建前端服务的命名空间。
6 前端服务的名称。
7 用于准入请求的 Webhook URL。将<webhook_url>替换为适当的值。
8 签署 Webhook 服务器使用的服务器证书的 PEM 编码的 CA 证书。将<ca_signing_certificate>替换为 base64 格式的相应证书。
9 定义 API 服务器何时应使用此 Webhook 准入插件的规则。
10 一个或多个触发 API 服务器调用此 Webhook 准入插件的操作。可能的值为createupdatedeleteconnect。将<operation><resource>替换为适当的值。
11 指定如果 Webhook 服务器不可用,策略应如何继续执行。将<policy>替换为忽略(在发生故障时无条件接受请求)或失败(拒绝失败的请求)。使用忽略可能会导致所有客户端出现不可预测的行为。

在 OpenShift Container Platform 4.17 中,用户或控制循环通过变更准入插件创建的对象可能会返回意外的结果,尤其是在初始请求中设置的值被覆盖的情况下,这并不推荐。

验证准入插件

验证准入插件在准入过程的验证阶段被调用。此阶段允许对特定 API 资源强制执行不变性,以确保资源不会再次更改。Pod 节点选择器也是通过验证准入插件调用的 Webhook 的一个示例,以确保所有nodeSelector字段都受命名空间上的节点选择器限制约束。

验证准入插件配置示例
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration (1)
metadata:
  name: <webhook_name> (2)
webhooks:
- name: <webhook_name> (3)
  clientConfig: (4)
    service:
      namespace: default  (5)
      name: kubernetes (6)
      path: <webhook_url> (7)
    caBundle: <ca_signing_certificate> (8)
  rules: (9)
  - operations: (10)
    - <operation>
    apiGroups:
    - ""
    apiVersions:
    - "*"
    resources:
    - <resource>
  failurePolicy: <policy> (11)
  sideEffects: Unknown
1 指定验证准入插件配置。
2 ValidatingWebhookConfiguration 对象的名称。将<webhook_name>替换为适当的值。
3 要调用的 Webhook 的名称。将<webhook_name>替换为适当的值。
4 关于如何连接、信任和向 Webhook 服务器发送数据的相关信息。
5 创建前端服务的命名空间。
6 前端服务的名称。
7 用于准入请求的 Webhook URL。将<webhook_url>替换为适当的值。
8 签署 Webhook 服务器使用的服务器证书的 PEM 编码的 CA 证书。将<ca_signing_certificate>替换为 base64 格式的相应证书。
9 定义 API 服务器何时应使用此 Webhook 准入插件的规则。
10 一个或多个触发 API 服务器调用此 Webhook 准入插件的操作。可能的值为createupdatedeleteconnect。将<operation><resource>替换为适当的值。
11 指定如果 Webhook 服务器不可用,策略应如何继续执行。将<policy>替换为忽略(在发生故障时无条件接受请求)或失败(拒绝失败的请求)。使用忽略可能会导致所有客户端出现不可预测的行为。

配置动态准入

此过程概述了配置动态准入的高级步骤。通过配置 Webhook 准入插件来调用 Webhook 服务器,可以扩展准入链的功能。

Webhook 服务器也配置为聚合的 API 服务器。这允许其他 OpenShift Container Platform 组件使用内部凭据与 Webhook 通信,并方便使用oc命令进行测试。此外,这还能够对 Webhook 进行基于角色的访问控制 (RBAC),并防止将来自其他 API 服务器的令牌信息泄露给 Webhook。

先决条件
  • 具有集群管理员访问权限的 OpenShift Container Platform 帐户。

  • 已安装的 OpenShift Container Platform CLI (oc)。

  • 已发布的 Webhook 服务器容器镜像。

步骤
  1. 构建 Webhook 服务器容器镜像,并使用镜像注册表使其对集群可用。

  2. 创建本地 CA 密钥和证书,并使用它们签署 Webhook 服务器的证书签名请求 (CSR)。

  3. 为 Webhook 资源创建一个新项目

    $ oc new-project my-webhook-namespace  (1)
    1 请注意,Webhook 服务器可能需要特定的名称。
  4. 在一个名为rbac.yaml的文件中定义聚合 API 服务的 RBAC 规则

    apiVersion: v1
    kind: List
    items:
    
    - apiVersion: rbac.authorization.k8s.io/v1  (1)
      kind: ClusterRoleBinding
      metadata:
        name: auth-delegator-my-webhook-namespace
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: system:auth-delegator
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1  (2)
      kind: ClusterRole
      metadata:
        annotations:
        name: system:openshift:online:my-webhook-server
      rules:
      - apiGroups:
        - online.openshift.io
        resources:
        - namespacereservations  (3)
        verbs:
        - get
        - list
        - watch
    
    - apiVersion: rbac.authorization.k8s.io/v1  (4)
      kind: ClusterRole
      metadata:
        name: system:openshift:online:my-webhook-requester
      rules:
      - apiGroups:
        - admission.online.openshift.io
        resources:
        - namespacereservations (5)
        verbs:
        - create
    
    - apiVersion: rbac.authorization.k8s.io/v1  (6)
      kind: ClusterRoleBinding
      metadata:
        name: my-webhook-server-my-webhook-namespace
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: system:openshift:online:my-webhook-server
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1  (7)
      kind: RoleBinding
      metadata:
        namespace: kube-system
        name: extension-server-authentication-reader-my-webhook-namespace
      roleRef:
        kind: Role
        apiGroup: rbac.authorization.k8s.io
        name: extension-apiserver-authentication-reader
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: rbac.authorization.k8s.io/v1  (8)
      kind: ClusterRole
      metadata:
        name: my-cluster-role
      rules:
      - apiGroups:
        - admissionregistration.k8s.io
        resources:
        - validatingwebhookconfigurations
        - mutatingwebhookconfigurations
        verbs:
        - get
        - list
        - watch
      - apiGroups:
        - ""
        resources:
        - namespaces
        verbs:
        - get
        - list
        - watch
    
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: my-cluster-role
      roleRef:
        kind: ClusterRole
        apiGroup: rbac.authorization.k8s.io
        name: my-cluster-role
      subjects:
      - kind: ServiceAccount
        namespace: my-webhook-namespace
        name: server
    1 将身份验证和授权委托给 Webhook 服务器 API。
    2 允许 Webhook 服务器访问集群资源。
    3 指向资源。此示例指向namespacereservations资源。
    4 启用聚合 API 服务器创建准入审查。
    5 指向资源。此示例指向namespacereservations资源。
    6 允许 Webhook 服务器访问集群资源。
    7 角色绑定以读取终止身份验证的配置。
    8 聚合 API 服务器的默认集群角色和集群角色绑定。
  5. 将这些 RBAC 规则应用于集群

    $ oc auth reconcile -f rbac.yaml
  6. 创建一个名为webhook-daemonset.yaml的 YAML 文件,用于在命名空间中将 Webhook 部署为守护程序集服务器

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      namespace: my-webhook-namespace
      name: server
      labels:
        server: "true"
    spec:
      selector:
        matchLabels:
          server: "true"
      template:
        metadata:
          name: server
          labels:
            server: "true"
        spec:
          serviceAccountName: server
          containers:
          - name: my-webhook-container  (1)
            image: <image_registry_username>/<image_path>:<tag>  (2)
            imagePullPolicy: IfNotPresent
            command:
            - <container_commands>  (3)
            ports:
            - containerPort: 8443 (4)
            volumeMounts:
            - mountPath: /var/serving-cert
              name: serving-cert
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8443 (5)
                scheme: HTTPS
          volumes:
          - name: serving-cert
            secret:
              defaultMode: 420
              secretName: server-serving-cert
    1 请注意,Webhook 服务器可能需要特定的容器名称。
    2 指向 Webhook 服务器容器镜像。将<image_registry_username>/<image_path>:<tag>替换为适当的值。
    3 指定Webhook容器运行命令。请将<container_commands>替换为适当的值。
    4 定义Pod内的目标端口。此示例使用端口8443。
    5 指定就绪探测使用的端口。此示例使用端口8443。
  7. 部署DaemonSet

    $ oc apply -f webhook-daemonset.yaml
  8. 在一个名为webhook-secret.yaml的YAML文件中定义为服务证书签名者服务的Secret。

    apiVersion: v1
    kind: Secret
    metadata:
      namespace: my-webhook-namespace
      name: server-serving-cert
    type: kubernetes.io/tls
    data:
      tls.crt: <server_certificate>  (1)
      tls.key: <server_key>  (2)
    1 引用已签名的Webhook服务器证书。请将<server_certificate>替换为适当的base64格式证书。
    2 引用已签名的Webhook服务器密钥。请将<server_key>替换为适当的base64格式密钥。
  9. 创建Secret

    $ oc apply -f webhook-secret.yaml
  10. 在一个名为webhook-service.yaml的YAML文件中定义服务账户和服务。

    apiVersion: v1
    kind: List
    items:
    
    - apiVersion: v1
      kind: ServiceAccount
      metadata:
        namespace: my-webhook-namespace
        name: server
    
    - apiVersion: v1
      kind: Service
      metadata:
        namespace: my-webhook-namespace
        name: server
        annotations:
          service.beta.openshift.io/serving-cert-secret-name: server-serving-cert
      spec:
        selector:
          server: "true"
        ports:
        - port: 443  (1)
          targetPort: 8443  (2)
    1 定义服务监听的端口。此示例使用端口443。
    2 定义服务将连接转发到的Pod内的目标端口。此示例使用端口8443。
  11. 在集群中暴露Webhook服务器

    $ oc apply -f webhook-service.yaml
  12. 在一个名为webhook-crd.yaml的文件中定义Webhook服务器的自定义资源定义 (CRD)。

    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: namespacereservations.online.openshift.io  (1)
    spec:
      group: online.openshift.io  (2)
      version: v1alpha1  (3)
      scope: Cluster  (4)
      names:
        plural: namespacereservations  (5)
        singular: namespacereservation  (6)
        kind: NamespaceReservation  (7)
    1 反映CustomResourceDefinitionspec值,格式为<plural>.<group>。此示例使用namespacereservations资源。
    2 REST API组名称。
    3 REST API版本名称。
    4 可接受的值为NamespacedCluster
    5 要包含在URL中的复数名称。
    6 oc输出中看到的别名。
    7 资源清单的引用。
  13. 应用自定义资源定义

    $ oc apply -f webhook-crd.yaml
  14. 在一个名为webhook-api-service.yaml的文件中将Webhook服务器配置为聚合API服务器。

    apiVersion: apiregistration.k8s.io/v1beta1
    kind: APIService
    metadata:
      name: v1beta1.admission.online.openshift.io
    spec:
      caBundle: <ca_signing_certificate>  (1)
      group: admission.online.openshift.io
      groupPriorityMinimum: 1000
      versionPriority: 15
      service:
        name: server
        namespace: my-webhook-namespace
      version: v1beta1
    1 签署 Webhook 服务器使用的服务器证书的 PEM 编码的 CA 证书。将<ca_signing_certificate>替换为 base64 格式的相应证书。
  15. 部署聚合API服务

    $ oc apply -f webhook-api-service.yaml
  16. 在一个名为webhook-config.yaml的文件中定义Webhook准入插件配置。此示例使用验证准入插件。

    apiVersion: admissionregistration.k8s.io/v1beta1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: namespacereservations.admission.online.openshift.io  (1)
    webhooks:
    - name: namespacereservations.admission.online.openshift.io  (2)
      clientConfig:
        service:  (3)
          namespace: default
          name: kubernetes
          path: /apis/admission.online.openshift.io/v1beta1/namespacereservations  (4)
        caBundle: <ca_signing_certificate>  (5)
      rules:
      - operations:
        - CREATE
        apiGroups:
        - project.openshift.io
        apiVersions:
        - "*"
        resources:
        - projectrequests
      - operations:
        - CREATE
        apiGroups:
        - ""
        apiVersions:
        - "*"
        resources:
        - namespaces
      failurePolicy: Fail
    1 ValidatingWebhookConfiguration对象的名称。此示例使用namespacereservations资源。
    2 要调用的Webhook名称。此示例使用namespacereservations资源。
    3 启用通过聚合API访问Webhook服务器。
    4 用于准入请求的Webhook URL。此示例使用namespacereservation资源。
    5 签署 Webhook 服务器使用的服务器证书的 PEM 编码的 CA 证书。将<ca_signing_certificate>替换为 base64 格式的相应证书。
  17. 部署Webhook

    $ oc apply -f webhook-config.yaml
  18. 验证Webhook是否按预期工作。例如,如果您已配置动态准入以预留特定命名空间,请确认创建这些命名空间的请求被拒绝,而创建未预留命名空间的请求成功。