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-2
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
复制代码
在导出区域后,我们可以按如下所示创建 ClusterConfig:
cat >cluster.yaml <<EOF
apiVersion: eksctl.io/v1alpha4
kind: ClusterConfig
metadata:
name: opa
region: ${AWS_REGION}
nodeGroups:
- name: ng-1
desiredCapacity: 2
allowSSH: true
EOF
复制代码
在创建该文件后,我们将使用 eksctl create cluster 命令创建集群:
eksctl create cluster -f cluster.yaml
复制代码
完成此操作大约需要 15 分钟时间,之后,我们便可获得可供使用的 Amazon EKS 集群。与此同时,我们可以开始为满足 Open Policy Agent 需求做准备。首先,我们将为 Admission Controller 生成自签名证书颁发机构,以便所有通信均可通过 TLS 完成。
创建资源
openssl genrsa -out ca.key 2048
openssl 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_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOF
复制代码
创建 server.conf 后,我们可以再次使用 openssl 生成密钥和证书:
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=opa.opa.svc" -config server.conf
openssl 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: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: opa-viewer
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
name: system:serviceaccounts:opa
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: opa
name: configmap-modifier
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: opa
name: opa-configmap-modifier
roleRef:
kind: Role
name: configmap-modifier
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
name: system:serviceaccounts:opa
apiGroup: rbac.authorization.k8s.io
---
kind: Service
apiVersion: v1
metadata:
name: opa
namespace: opa
spec:
selector:
app: opa
ports:
- name: https
protocol: TCP
port: 443
targetPort: 443
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: opa
namespace: opa
name: opa
spec:
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: ConfigMap
apiVersion: v1
metadata:
name: opa-default-system-main
namespace: opa
data:
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 <<EOF
kind: ValidatingWebhookConfiguration
apiVersion: admissionregistration.k8s.io/v1beta1
metadata:
name: opa-validating-webhook
webhooks:
- 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: opa
EOF
复制代码
然后,我们将创建第一个策略。我们要创建的策略将验证每个 Pod 的映像是否来自白名单中的注册表。我们策略中的前两个条目分别为我们自己账户的 Amazon ECR 和 Amazon EKS 特定的 ECR。
cat > image_source.rego <<EOF
package 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 <<EOF
kind: Pod
apiVersion: v1
metadata:
name: nginx
labels:
app: nginx
namespace: default
spec:
containers:
- image: nginx
name: nginx
EOF
复制代码
在创建集群之后,我们便可部署所有资源并对其进行测试。
部署资源
首先,我们将创建 opa 命名空间,并在当前环境中对其进行设置。这样,可以更轻松地跟踪我们正在执行的所有操作:
kubectl create namespace opa
kubectl 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.yaml
Error 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 <<EOF
kind: Pod
apiVersion: v1
metadata:
name: nginx
labels:
app: nginx
namespace: default
spec:
containers:
- image: ${REPOSITORY}:latest
name: nginx
EOF
复制代码
最后,我们将 nginx Pod 部署到集群:
$ kubectl apply -f private-nginx.yaml
pod/nginx created
复制代码
清理
如果您想删除已创建的集群,可以先删除集群中创建的所有资源,然后使用 eksctl 再次删除 Amazon EKS 集群:
kubectl delete -f private-nginx.yaml
kubectl delete namespace opa
eksctl 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/
评论