Open Policy Agent (OPA) 是云原生计算基金会 (CNCF) 的一个沙盒项目,可帮助您针对几乎所有内容实施自动化策略,其工作原理与 AWS Identity and Access Management (IAM) 类似。借助 OPA,您可以使用一种基于 datalog 的名为 rego 的语言编写非常精简的策略。然后,您可以将这些策略部署到 rego 文件中的 Open Policy Agent Admission Controller,并让其验证或修改向 Kubernetes API 服务器发送的请求。这就是说,您可以编写一个有两行代码的策略,并让此策略对请求中的属性实施验证,例如可以检查 imagePullPolicy 是否设置为 Always,或者 Deployment 是否总是拥有至少 2 个 replica,或者映像是否来源于白名单存储库中的注册表。下文将介绍如何将 OPA 部署到 Amazon Elastic Container Service for Kubernetes (EKS) 集群中并实施检查,仅允许存在来自您自己的 Amazon Elastic Container Registry (ECR) 或 EKS ECR 存储库的映像。
开始使用
在开始之前,我们需要设置一个 Amazon EKS 集群。我们将在集群配置文件机制中使用 eksctl。首先,必须下载以下工具:
部署集群
export AWS_REGION=us-east-2export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
复制代码
在导出区域后,我们可以按如下所示创建 ClusterConfig:
cat >cluster.yaml <<EOFapiVersion: eksctl.io/v1alpha4kind: ClusterConfigmetadata: name: opa region: ${AWS_REGION}
nodeGroups: - name: ng-1 desiredCapacity: 2 allowSSH: trueEOF
复制代码
在创建该文件后,我们将使用 eksctl create cluster 命令创建集群:
eksctl create cluster -f cluster.yaml
复制代码
完成此操作大约需要 15 分钟时间,之后,我们便可获得可供使用的 Amazon EKS 集群。与此同时,我们可以开始为满足 Open Policy Agent 需求做准备。首先,我们将为 Admission Controller 生成自签名证书颁发机构,以便所有通信均可通过 TLS 完成。
创建资源
openssl genrsa -out ca.key 2048openssl req -x509 -new -nodes -key ca.key -days 100000 -out ca.crt -subj "/CN=admission_ca"
复制代码
创建 CA 后,我们需要为 OPA 创建 TLS 密钥和证书:
cat >server.conf <<EOF[req]req_extensions = v3_reqdistinguished_name = req_distinguished_name[req_distinguished_name][ v3_req ]basicConstraints = CA:FALSEkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentextendedKeyUsage = clientAuth, serverAuthEOF
复制代码
创建 server.conf 后,我们可以再次使用 openssl 生成密钥和证书:
openssl genrsa -out server.key 2048openssl req -new -key server.key -out server.csr -subj "/CN=opa.opa.svc" -config server.confopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 100000 -extensions v3_req -extfile server.conf
复制代码
接下来,我们将创建 Open Policy Agent Admission Controller 清单:
cat >admission-controller.yaml <<EOF---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: name: opa-viewerroleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.iosubjects:- kind: Group name: system:serviceaccounts:opa apiGroup: rbac.authorization.k8s.io---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata: namespace: opa name: configmap-modifierrules:- apiGroups: [""] resources: ["configmaps"] verbs: ["update", "patch"]---kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: namespace: opa name: opa-configmap-modifierroleRef: kind: Role name: configmap-modifier apiGroup: rbac.authorization.k8s.iosubjects:- kind: Group name: system:serviceaccounts:opa apiGroup: rbac.authorization.k8s.io---kind: ServiceapiVersion: v1metadata: name: opa namespace: opaspec: selector: app: opa ports: - name: https protocol: TCP port: 443 targetPort: 443---apiVersion: extensions/v1beta1kind: Deploymentmetadata: labels: app: opa namespace: opa name: opaspec: replicas: 1 selector: matchLabels: app: opa template: metadata: labels: app: opa name: opa spec: containers: - name: opa image: openpolicyagent/opa:0.10.5 args: - "run" - "--server" - "--tls-cert-file=/certs/tls.crt" - "--tls-private-key-file=/certs/tls.key" - "--addr=0.0.0.0:443" - "--addr=http://127.0.0.1:8181" volumeMounts: - readOnly: true mountPath: /certs name: opa-server - name: kube-mgmt image: openpolicyagent/kube-mgmt:0.6 args: - "--replicate-cluster=v1/namespaces" - "--replicate=extensions/v1beta1/ingresses" volumes: - name: opa-server secret: secretName: opa-server---kind: ConfigMapapiVersion: v1metadata: name: opa-default-system-main namespace: opadata: main: | package system
import data.kubernetes.admission
main = { "apiVersion": "admission.k8s.io/v1beta1", "kind": "AdmissionReview", "response": response, }
default response = {"allowed": true}
response = { "allowed": false, "status": { "reason": reason, }, } { reason = concat(", ", admission.deny) reason != "" }EOF
复制代码
然后,我们将创建 ValidatingWebhookConfiguration,它将指示 Kubernetes 发送 CREATE、UPDATE Pod 事件,以让我们的策略对这些事件进行验证:
cat > webhook-configuration.yaml <<EOFkind: ValidatingWebhookConfigurationapiVersion: admissionregistration.k8s.io/v1beta1metadata: name: opa-validating-webhookwebhooks: - name: validating-webhook.openpolicyagent.org rules: - operations: ["CREATE", "UPDATE"] apiGroups: ["*"] apiVersions: ["v1"] resources: ["Pod"] clientConfig: caBundle: $(cat ca.crt | base64 | tr -d '\n') service: namespace: opa name: opaEOF
复制代码
然后,我们将创建第一个策略。我们要创建的策略将验证每个 Pod 的映像是否来自白名单中的注册表。我们策略中的前两个条目分别为我们自己账户的 Amazon ECR 和 Amazon EKS 特定的 ECR。
cat > image_source.rego <<EOFpackage kubernetes.admission
deny[msg] { input.request.kind.kind = "Pod" input.request.operation = "CREATE" image = input.request.object.spec.containers[_].image name = input.request.object.metadata.name not registry_whitelisted(image,whitelisted_registries) msg = sprintf("pod %q has invalid registry %q", [name, image])}
whitelisted_registries = {registry | registries = [ "602401143452.dkr.ecr.${AWS_REGION}.amazonaws.com", "${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com" ] registry = registries[_]}
registry_whitelisted(str, patterns) { registry_matches(str, patterns[_])}
registry_matches(str, pattern) { contains(str, pattern)}EOF
复制代码
最后,我们将创建用来测试策略的 nginx test Pod 清单:
cat > nginx.yaml <<EOFkind: PodapiVersion: v1metadata: name: nginx labels: app: nginx namespace: defaultspec: containers: - image: nginx name: nginxEOF
复制代码
在创建集群之后,我们便可部署所有资源并对其进行测试。
部署资源
首先,我们将创建 opa 命名空间,并在当前环境中对其进行设置。这样,可以更轻松地跟踪我们正在执行的所有操作:
kubectl create namespace opakubectl config set-context --namespace opa --current
复制代码
接下来,我们将部署之前创建的所有清单,先从使用我们的服务器密钥和证书的 TLS 密钥开始:
kubectl create secret tls opa-server --cert=server.crt --key=server.key
复制代码
然后,我们将部署 Admission Controller:
kubectl apply -f admission-controller.yaml
复制代码
如果您要在多租户或不受信任的环境中运行集群,建议您通读此处的 TLS 和身份验证方案。
在部署 AdmissionController 之后,我们可以部署已创建的 ValidatingWebhookConfiguration。这会指示 Kubernetes API 服务器将所有 Pod CREATE 和 UPDATE 事件发送至 OPA 服务进行验证。
kubectl apply -f webhook-configuration.yaml
最后需要进行的配置是部署我们的自定义策略,限制 Pod 通过不受信任的注册表进行部署:
kubectl create configmap image-source --from-file=image_source.rego
注意:与我们正在使用的其他 kubectl 命令不同,此命令属于命令性配置。这有时会使您的 ConfigMap 很难保持同步,尤其是在使用 Gitops 之类的部署策略时,难度更大。如果您想使用 apply,则需创建 ConfigMap 清单,并将您的策略复制到 data 属性中。
在创建策略之后,我们便可进行测试,看看它是否已正确编译,以及 Open Policy Agent 是否已成功对 rego 脚本进行了初始化。要执行此操作,请使用 kubectl get configmap image-source -o yaml:
$ kubectl get configmap image-source -o jsonpath="{.metadata.annotations}"map[openpolicyagent.org/policy-status (http://openpolicyagent.org/policy-status):{"status":"ok"}]
复制代码
在资源部署完毕并已在 Open Policy Agent 中进行初始化之后,我们便可运行 nginx Pod 测试。
测试策略
$ kubectl apply -f nginx.yamlError from server (pod "nginx" has invalid registry "nginx"): error when creating "nginx.yaml": admission webhook "validating-webhook.openpolicyagent.org" denied the request: pod "nginx" has invalid registry "nginx"
复制代码
现在,让我们使用自己的注册表标记 nginx 映像,推送该映像,并尝试通过我们自己的注册表进行部署。首先,我们需要创建一个存储库:
aws ecr create-repository —repository-name nginx
复制代码
然后,我们将从 API 中获得存储库名称,以便标记我们的 nginx 实例:
export REPOSITORY=$(aws ecr describe-repositories --repository-name nginx --query "repositories[0].repositoryUri" --output text)
复制代码
现在,我们会将 Docker Hub 公有 nginx 提取到本地,以便重新对其进行标记:
然后,我们可以使用存储库名称重新标记 latest,并将映像推送至您自己的 Amazon ECR。首先,我们登录 Amazon ECR:
aws ecr get-login —no-include-email | bash -
复制代码
然后,将 latest 标签推送至 Amazon ECR:
docker push ${REPOSITORY}:latest
复制代码
接下来,我们可以重新创建 nginx 清单文件,并将其推送至 Amazon EKS 集群:
cat > private-nginx.yaml <<EOFkind: PodapiVersion: v1metadata: name: nginx labels: app: nginx namespace: defaultspec: containers: - image: ${REPOSITORY}:latest name: nginxEOF
复制代码
最后,我们将 nginx Pod 部署到集群:
$ kubectl apply -f private-nginx.yamlpod/nginx created
复制代码
清理
如果您想删除已创建的集群,可以先删除集群中创建的所有资源,然后使用 eksctl 再次删除 Amazon EKS 集群:
kubectl delete -f private-nginx.yamlkubectl delete namespace opaeksctl delete cluster -f cluster.yaml
复制代码
更多示例
以下是一些很好的示例,其中展示了人们目前是如何将 Open Policy Agent 与 Kubernetes 集群结合使用,来帮助管理其自定义策略的:
现在,有谁在结合使用 @OpenPolicyAgent 与 @kubernetesio? 有没有有趣的策略?
我刚刚为 Amazon EKS 编写了一个策略,用来检查映像是来自 EKS 注册表还是您自己的账户的 ECR。
你们都用它来做什么?
– Chris Hein (@christopherhein) 2019 年 3 月 1 日
网关守卫实际效果视频 – https://t.co/brjywlDmen
– Lachlan Evenson (@LachlanEvenson) 2019 年 3 月 1 日
我编写了一些有关联合身份的有趣策略,其中它只允许基于标签部署到欧洲或全球的集群,另一个策略则用于检查第三方“jira”(模拟),它只允许在 P1 票证打开时访问生产名称空间
– Andy Repton (@SethKarlo) 2019 年 3 月 2 日
我们将它用于多种用途,但主要的是确保人们不向错误的 ingress 类添加 ingress,不向 Internet 披露他们不应披露的内容
– briggsl (@briggsl) 2019 年 3 月 2 日
@OpenPolicyAgent 是我们 @kubernetesio 服务堆栈中的一个新的核心组件。
我的同事 @sbueringer 为此撰写了两篇博文:https://t.co/LFkfJ8ElEs 和 https://t.co/ZxsQtZ2Z1Y
– Mario Constanti (@bavarian_bidi) 2019 年 3 月 2 日
小结
借助 Open Policy Agent,您不必再通过编写自定义代码来处理组织或团队的自定义策略。现在,您可以像我们在本文中所做的那样部署自定义 ValidatingAdmissionControllers 或 MutatingAdmissionControllers(为您的 Kubernetes 资源提供正常的默认值),或设置适当的标签。您会拥有几乎无穷无尽的控件。要了解有关 Open Policy Agent 的更多信息,请查看 Open Policy Agent 文档,并加入 Open Policy Agent 社区。
阅读 Chris 撰写的更多博文。
作者介绍:
Chris Hein
Chris Hein 是一位资深的开发者,倡导 Amazon Web Services 的 Kubernetes/EKS。加入 Amazon 之前,Chris 曾就职于众多规模不等的公司,如 GoPro、Sproutling 和 Mattel。有关 Chris 的更多信息,请访问 https://aws.amazon.com/blogs/opensource/author/heichris/,并通过 @christopherhein 关注他
本文转载自 AWS 技术博客。
原文链接:
https://amazonaws-china.com/cn/blogs/china/using-open-policy-agent-on-amazon-eks/
评论