为了账号安全,请及时绑定邮箱和手机立即绑定

OPA守门人:Kubernetes集群策略编写指南

学习如何使用OPA Gatekeeper在Kubernetes集群中编写并执行策略,以确保环境的安全和资源的有效管理。

有了像 Kubernetes 这样的工具,微服务环境的日常工作流程管理和自动化来说变得更加容易。

在 Kubernetes 中使用策略将帮助您获得最大的控制权和灵活性,例如:

  • 提高微服务的安全
  • 积极管理云基础设施中的有限资源,例如计算和存储
  • 符合监管法规要求

读了这篇文章,你会学到

  1. 使用策略来保障 Kubernetes 环境的安全性的好处。
  2. 如何设置策略管理系统;Kubernetes 和 OPA 在后台是如何运作的。
  3. 开始在您的集群中编写和运行策略所需的所有条件。

开放策略代理 (OPA) 是什么?

Open Policy Agent (OPA) 帮助我们来使用专为编写策略设计的声明性语言Rego编写策略。

通过OPA,我们可以定义并强制执行从Kubernetes到底层的微服务等各个层级的堆栈的策略。

这种方法有助于提升在管理 Kubernetes 集群中的策略时的一致性、可扩展性和敏捷性。

此外,通过使用表达力强的语法,您可以高效地表示组织做出的访问控制规则和复杂政策决策。

这样一来,这在很大程度上保证了你的 K8s 环境符合规范且安全。

本文的重点在于编写 Kubernetes 配置中的配置策略。

如果你不熟悉OPA,你可以快速了解它的工作方式和实现细节:这篇文章

OPA 和 Kubernetes 是如何一起工作的?

在这部分,我们来详细了解一下如何让 OPA 运行起来吧。

还不错,OPA 对 Kubernetes 的支持也很好,正如其文档中所述,所以我们可以看看如何将其集成到您的 Kubernetes 环境中。

但首先,让我们来谈谈一些重要的组件,并理解它背后的运作方式。

Kubernetes 自带一个叫做准入控制器的组件,它就像 Kubernetes API 和每个请求之间的中间人,用于处理这些请求。

准入控制器可以实施策略并确保安全措施得以执行,确保只有经过授权且配置正确的工作负载才能进入集群。

他们可能修改请求中的细节,以确保请求格式正确且可接受,然后再进行处理。

所以,准入控制器可以分为两种类型:mutating(突变型)或 validating(验证型)。理解这一点非常重要,因为这就是 Open Policy Agent (OPA) 发挥作用的地方。

为什么我们需要在集群中使用准入控制器,官方 Kubernetes 文档 如下解释:

“…一个没有正确配置准入控制器的Kubernetes API服务器来说,是不完整的,这样的服务器将无法支持你所期望的所有功能…”

实际上,你可以选择使用 Open Policy Agent (OPA) 或者编写你自己的准入控制器,这取决于你打算在 Kubernetes 环境中自定义的程度。

什么是OPA Gatekeeper?

Kubernetes 集群通常需要准入控制器才能完整运行。OPA Gatekeeper 就是一个这样的控制器,会检查所有发送到 Kubernetes API 的请求。

守门人拦截请求并根据预设的策略进行检查。根据这项检查,请求可以被拒绝或批准。

从上面的图示中,我们可以看到OPA Gatekeeper是如何处理进入Kubernetes API服务器的任何请求的流程。

它也一直在观察 API 服务器中的 pod 和服务这些资源是否有任何变化。

所以实际上,当你在 Kubernetes 环境中装了 Gatekeeper 时,你可以直接在这里制定并实施策略。下面我们会继续讨论更多相关内容。

在 Kubernetes 集群中通过 OPA 网关来编写策略

为进一步更好地理解OPA守门人在Kubernetes中的好处和集成范围,我们将通过以下案例来说明:

本两部分的教程将一步步指导你完成整个过程,教你如何使用 OPA 在你的 Kubernetes 集群中编写和测试策略。

在第一部分,我们将使用OPA守门人准入控制器来实施我们编写的策略,然后,在第二部分,我们将动手编写我们自己的自定义验证控制程序。

到本指南结束时,你就能做到如下:

  1. 了解了如何在Kubernetes环境中使用OPA策略
  2. 如何编写并应用自己的策略
  3. 更深入地了解了Kubernetes中的准入控制器webhook,包括其工作流程以及如何实现自己的验证控制器。
先决条件

要充分利用这份实用指南,你需要在本地电脑上准备好以下项目:

  1. 确保你已安装OPA
  2. Minikube:确保你已安装Minikube 并且有一个正在运行的Kubernetes集群
  3. kubectl:确保你已配置kubectl可以与你的集群进行交互。
  4. OPA Gatekeeper:确保在你的集群中已经安装了OPA Gatekeeper
  5. Docker和DockerHub账户

咱们直接切入正题。

1. 设定命名空间规则

在这个用例中,让我们编写一个OPA策略规则,规定每个命名空间创建请求都应添加一个注解。

第一步:创建一个约束模板文件。约束模板定义了策略的结构和逻辑规则,这。此模板强制要求每个命名空间都必须包含 team 注解。

apiVersion: templates.gatekeeper.sh/v1beta1  
kind: ConstraintTemplate  
metadata:  
  name: k8srequiredannotations  
spec:  
  crd:  
    spec:  
      names:  
        kind: K8sRequiredAnnotations  
  targets:  
    - target: admission.k8s.gatekeeper.sh  
      rego: |  
        package k8srequiredannotations
            违规[{"msg": msg}] {  
              input.review.kind.kind == "Namespace"  
              input.review.object.metadata.annotations 中没有 'team'  
              msg := "Namespace 必须有一个 'team' 注解"  
            }

将此 YAML 保存到文件 constrainttemplate.yaml 中,然后应用到您的集群中:

运行以下命令来应用约束模板:

kubectl apply -f constrainttemplate.yaml

第二步:创建约束文件

约束通过约束模板在特定资源上实施策略——在这种情况下,指的是在命名空间上。

版本号:constraints.gatekeeper.sh/v1beta1  
类型:K8sRequiredAnnotations  
元数据:  
  名称:require-team-annotation  
规范:  
  匹配:  
    类型:  
      - API组:[""]  
        类型:["Namespace"]

注解:需要团队注解
注解:Namespace:命名空间

将此 YAML 保存到名为 constraint.yaml 的文件里,并应用到您的集群上。

kubectl apply -f constraint.yaml # 这条命令用于应用constraint.yaml文件中的配置。

步骤三:核实一下政策内容

为了验证策略是否起作用,可以尝试创建一个未标注团队的命名空间。这应该会被拒绝。

apiVersion: v1
kind: Namespace
metadata:
  name: demo-namespace
  # 创建一个名为 demo-namespace 的命名空间

将这段 YAML 代码保存到名为 demo-namespace.yaml 的文件中,并执行这个配置。

运行以下命令来应用yaml文件:

kubectl apply -f demo-namespace.yaml

果然遇到了错误

现在,让我们通过创建一个带有 team 标签的命名空间来按照政策行事。

apiVersion: v1
kind: Namespace  # 这是一个命名空间
metadata:
  name: test-namespace
  annotations:  # 注释部分
    team: "devops"

保存上述 YAML 文件为 test-namespace-with-annotation.yaml,然后在集群中应用它。

这次它终于成功地创建了命名空间。

2 分配资源限额

接下来,我们想要编写一个稍微更复杂的策略,带有 env:production 标签的命名空间必须设置资源配额。

这样的政策在你想要管理和监控资源使用的情况时会很有帮助,使事情更高效。我们开始吧。

第一步,创建模板文件

这个模板会检查标有 env: production 的命名空间(namespace)是否有资源配额(resource quota)。

apiVersion: templates.gatekeeper.sh/v1beta1  
kind: ConstraintTemplate  
metadata:  
  name: k8srequiredresourcequotas  
spec:  
  crd:  
    spec:  
      names:  
        kind: K8sRequiredResourceQuotas  
  targets:  
    - target: admission.k8s.gatekeeper.sh  
      rego: |  
        package k8srequiredresourcequotas
            违规[{"msg": msg}] {  
              input.review.kind.kind == "Namespace"  
              namespace := input.review.object; 某些 label_key  
              namespace.metadata.labels[label_key] == "production"  
              没有 has_resource_quota(namespace.metadata.name)  
              msg := sprintf("带有 'env: production' 标签的命名空间必须有资源配额", [])  
            }        has_resource_quota(namespace_name) {  
              某个索引 i  
              input.review.context.related[i].kind == "ResourceQuota"  
              input.review.context.related[i].metadata.namespace == namespace_name  
            }

将此 YAML 保存到名为 constrainttemplate.yaml 的文件中,然后将其应用到您的集群中:

kubectl apply -f constrainttemplate.yaml 该命令用于将constrainttemplate.yaml文件应用到Kubernetes集群中。

第二步:创建一个限制条件文件。

apiVersion: constraints.gatekeeper.sh/v1beta1  # 定义使用的API版本
kind: K8sRequiredResourceQuotas  # 定义资源类型,这里表示K8s所需资源配额
metadata:  
  name: require-resource-quota-for-production  # 元数据名称,表示需要为生产环境设置资源配额
spec:  # 规范部分,定义了资源配额的具体规则
  match:  # 匹配部分,定义了哪些资源需要遵守这些规则
    kinds:  
      - apiGroups: [""]  # 指定API组为空,表示核心API组
        kinds: ["Namespace"]  # 指定资源类型为Namespace
每个Namespace是否需要满足资源配额的要求在此处定义

将此 YAML 保存到名为 constraint.yaml 的文件中,并将其应用到您的集群上。

kubectl apply -f constraint.yaml

第三步:验证策略是否生效,为了验证策略是否生效,让我们创建一个带有生产标签但没有设置资源配额的简单测试命名空间。它应当被拒绝。

# 类型:Namespace,标签:环境=生产环境
apiVersion: v1
# API版本为v1
kind: Namespace
# 类型:Namespace
metadata:
  # 元数据部分
  name: test-namespace-production-no-quota
  # 名称:test-namespace-production-no-quota
  labels:
    # 标签部分,env标签值为production
    env: production
    # 环境标签:env=production

将以下 YAML 保存到文件 test-namespace-production-no-quota.yaml,并应用该文件。

kubectl apply -f test-namespace-production-no-quota.yaml

此命令用于创建或更新名为 test-namespace-production-no-quota 的命名空间,该命名空间没有配额。

正如预期的那样,当我们尝试创建命名空间时,它会告诉我们,我们需要先分配配额,正如我们在策略文件里提到的。

太棒了。我们给命名空间设定一个额度吧。

apiVersion: v1
kind: 资源配额限制
元数据:
  名称: 资源配额限制
  命名空间: default
spec:
  硬限制:
    请求的CPU: "1"
    请求的内存: 1Gi
    限制的CPU: "2"
    限制的内存: 2Gi

将此 YAML 保存为名为 resource-quota.yaml 的文件并应用这个配置。

运行以下命令来应用资源配额文件:
kubectl apply -f resource-quota.yaml
这个命令会应用名为 resource-quota.yaml 的文件里的资源限制。

按照上述步骤申请后,命名空间的创建和配额申请都成功了。

你可以更进一步地使用命令查看命名空间的配额,如下所示:

kubectl get resourcequotas -n default,运行该命令来获取默认命名空间中的资源配额。

到现在为止,我们已经看到了OPA gatekeeper在这些情况下的作用,它在我们想要在Kubernetes中执行特定操作时充当中间人或拦截特定操作的角色。

我们现在来进入最后部分,即创建我们自己的自定义验证 webhook(网络钩子)。

3. 自己动手写个自定义控制器代码

首先,创建并切换到一个专门为此过程创建的单独的文件夹,你可以命名为 webhook_server

  1. 运行 Minikube 集群。minikube start

2. 编写 webhook 验证逻辑。我们将用 Python 编写这个逻辑,但也可以用任何其他语言。在文件 app.py 中添加以下代码。

    from flask import Flask, request, jsonify  
    import logging  

    app = Flask(__name__)  
    logger = logging.getLogger(__name__)  

    @app.route('/validate', methods=['POST'])  
    def validate_pod():  
        try:  
            admission_review = request.get_json()  
            pod_spec = admission_review['request']['object']['spec']  

            # 在这里加入你的验证逻辑  
            # 例如:检查Pod是否有特定标签  
            labels = pod_spec.get('labels', {})  
            if 'app' not in labels:  
                logger.error("Pod验证失败:缺少'app'标签")  
                return jsonify({"response": {"allowed": False, "status": {"reason": "MissingAppLabel"}}}), 200  

            # 如果所有验证检查都通过了  
            logger.info("Pod验证成功")  
            return jsonify({"response": {"allowed": True}}), 200  

        except Exception as e:  
            logger.exception("在验证Pod期间发生错误")  
            return jsonify({"response": {"allowed": False, "status": {"reason": "InternalServerError"}}}), 500  

    if __name__ == '__main__':  
        # 配置日志记录  
        logging.basicConfig(level=logging.INFO)  

        # 启动Flask应用程序  
        app.run(host='0.0.0.0', port=8080, debug=False)

3. 我们需要将该 webhook 服务器打包成容器,并将其构建并推送到 DockerHub 仓库。步骤 I. 在 Dockerhub 上创建一个仓库。步骤 II. 在文件夹中创建一个包含以下内容的 Dockerfile:

# 示例内容:FROM python:3.8-slim
# 示例内容:WORKDIR /app
# 示例内容:COPY . /app
# 示例内容:CMD ["python", "./server.py"]

请根据实际情况填写具体内容。

运行 Dockerfile

    # 从Python 3.9 slim镜像开始
    FROM python:3.9-slim  

    # 设置工作目录为 /app
    WORKDIR /app  

    # 复制 requirements.txt 文件到当前目录
    COPY requirements.txt .  

    # 运行 pip 安装 requirements.txt 文件中列出的包,不使用缓存
    RUN pip install --no-cache-dir -r requirements.txt  

    # 复制 app.py 文件到当前目录
    COPY app.py .  

    # 设置容器启动时运行的命令为 python app.py
    CMD [ "python", "app.py" ]

III. 构建 Docker 镜像 docker build -t your-username/repository-name:latest .
注:此命令用于从当前目录构建一个 Docker 镜像,并将其标记为 your-username/repository-name:latest

四. 推送到DockerHub

docker 登录

请将标签改为 `docker tag <repository-name>:latest your-username/repository-name:latest`
然后推送镜像 `docker push your-username/repository-name:latest`

注意:这里的 <repository-name>:latest 是占位符,请根据实际情况替换为具体的仓库名和标签。这些步骤将帮助你更新并推送最新的 Docker 镜像。

现在,该镜像应该已经在Dockerhub上可以实时获取了。这意味着我们现在可以在部署时使用它了。

💡小提示:如果您在将 Docker 镜像推送到 DockerHub 时遇到请求被拒绝,确保在终端登录 Docker,并仔细核对镜像名、仓库名和标签是否一致,是否有拼写错误或不匹配的地方。

4. 生成 TLS 证书这一操作。这有助于确保我们 webhook 服务器与 Kubernetes 之间的通信安全。这一步骤至关重要,需要特别注意。如果配置不当,可能会遇到 TLS 错误。

openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -subj "/CN=pod-validation-webhook.default.svc"
    kubectl create secret tls pod-validation-webhook-tls --cert=server.crt --key=server.key -n default
  1. 创建用于部署的 YAML 文件。

运行 webhook-deployment.yaml 文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-validation-webhook
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pod-validation-webhook
  template:
    metadata:
      labels:
        app: pod-validation-webhook
    spec:
      containers:
      - name: cweb
        image: cannarron/cweb:latest
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: tls-certs
          mountPath: /etc/webhook/certs
          readOnly: true
      volumes:
      - name: tls-certs
        secret:
          secretName: pod-validation-webhook-tls

6. 创建一个 kubectl 服务,用于指向我们的 Python webhook 服务器 touch webhook-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: pod-validation-webhook
spec:
  # 规范说明
  selector:
    # 选择器
    app: pod-validation-webhook
  ports:
    # 定义端口
    - protocol: TCP
      port: 8080
      targetPort: 8080
  1. 创建验证配置文件。验证配置文件正式将我们的webhook注册为kubernetes API的一部分。换句话说,kubernetes会知道有一个新的中介代理,每当有新的pod创建请求时,它就会被调用。

运行 validating-webhook-config.yaml:

apiVersion: admissionregistration.k8s.io/v1  
kind: ValidatingWebhookConfiguration  
metadata:  
  name: pod-validation-webhook  
webhooks:  
  - name: pod.validation.example.com  
    clientConfig:  
      service:  
        name: pod-validation-webhook  
        namespace: default  
        path: "/validate"  
      caBundle: <base64 encoded ca.crt>  
    admissionReviewVersions:  
      - v1  
    sideEffects: None  
    timeoutSeconds: 5  
    failurePolicy: Fail  
    matchPolicy: Equivalent  
    rules:  
      - apiGroups: [""]  
        apiVersions: ["v1"]  
        operations: ["CREATE", "UPDATE"]  
        resources: ["pods"]

8. 应用清单文件:我们来应用之前步骤中创建的部署文件、服务文件和验证文件,这些文件都是 YAML 格式的。

    kubectl apply -f webhook-deployment.yaml  // 部署 webhook 部署配置
    kubectl apply -f webhook-service.yaml  // 部署 webhook 服务配置
    kubectl apply -f validating-webhook-config.yaml  // 部署验证 webhook 配置

9. 验证步骤。如果部署顺利,你应该能看到 pod 运行正常。验证 webhook 也应该在工作。为了确认我们的验证钩子是否已经启动,根据我们在 webhook 中设置的验证规则,我们只需创建一个没有标签的测试 pod,这个请求会被拒绝。

总结和结尾

在这份全面的指南中,我们讨论了如何使用 Kubernetes 策略来扩展 Kubernetes 的功能,并根据需求添加自定义增强或团队偏好。我们还逐步讲解了如何在 Kubernetes 中实施策略,并通过实际案例进行说明。

在你的 Kubernetes 配置中使用策略是一种创新的方法,可以帮助你充分发掘容器化部署中的潜力,并使部署更加安全。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消