翻译:小君君

技术校对:星空下的文仔、bot

在项目中, Kubernetes 集群会对 Kubernetes APIServer 的每个请求都进行身份验证和授权管理。在此过程中,授权管理通常由 RBAC 授权模块来实现,但开发者也可以选择其他组件,如 Open Policy Agent(OPA)。

本文从使用目的、设计方式以及示例演示阐述了如何利用 Webhook 授权模块使 OPA 实现高级授权策略。

使用动机

在一些项目中,我们希望为用户提供类似集群管理员的访问许可权。但为了确保基线的安全性和稳定性,我们不希望授予用户完整的集群管理员许可权。例如:

  • 我们允许用户完全访问除kube-system之外的所有 namespace,因为我们的基础设施(例如监视和日志记录)部署在kube-system中;
  • 我们希望强制执行 PodSecurityPolicy,不允许用户以root的身份运行容器,也不允许用户直接挂载hostPath卷。

面对这些要求,一种解决方案是通过 Kubernetes RBAC 和一个自定义操作符实现授权。其基本思想是让所有必要的许可权通过 RBAC RoleBindings 进行授予绑定。并且,除了kube-system(通过 operator)之外,我们为每个 namespace 的客户提供了 ClusterRole admin。每当我们发现某些东西不能像预期那样工作时,我们就会通过每个 namespace 角色或 ClusterRole 添加其他许可权。

但是,这种方式会出现很多针对特定用例的单独规则。从长远发展角度来看,这些规则无法得到很好的维护。特别是在用户群不断增长的情况下,只要有人检测到与配置不匹配的边缘情况,调整角色不太可行。

综上所述,我们不能选择基于白名单的配置授权,而是需要切换到基于黑名单的模型。因为,我们真正想要的是为客户提供集群管理员访问许可权,并限制某些特定许可权。

基于白名单与黑名单的授权

关于授权,绝大多数要求可以通过 Roles 和 RoleBindings 简单地使用 RBAC 授权模块来实现 [1]。但 RBAC 在设计上仅限于白名单。即对于每个请求,它会选择检查其中的一个 Roles 和 RoleBindings 是否适用,然后批准请求。

请求只有在没有匹配项时才会被拒绝,虽然听起来限制不大,但一些特定用例需要更大的灵活性。例如:

  • 当用户想在除kube-system之外的所有 namespace 中创建/更新/删除 Pod 时,通过 RBAC 实现此目的的唯一方法是在每个 namespace 的基础上分配许可权。例如,我们可以部署 ClusterRole 和每个 namespace 的 RoleBinding。如果 namespace 随时间而变化,则必须手动部署此 RoleBindings 或为它运行 operator;
  • 当 Kubernetes 集群提供预安装的 StorageClass 时,用户可能会想要拥有创建/更新/删除自定义 StorageClass 的许可权。但他不应该有修改预安装 StorageClass 的许可权。如果你想利用 RBAC 来实现,则用户必须有权创建 StorageClass,并且一旦创建 StorageClass,就必须分配其他许可权以更新和删除此 StorageClass。

如果你有很多这样的用例,你就要通过运营商来实现很多自定义的逻辑,但是你需要知道这些用例可能不会被扩展。因为这样做就会有很多的运营商和随附的 RBAC 角色,我们将很难控制用户实际拥有的权利。下面,我们将展示如何通过 OPA 轻松实现上述两种情况。

Webhook 授权模块与 ValidatingWebhook & MutatingWebhook

除了本文探讨的情况,一些高级用例也可以通过 Dynamic Admission Control 实现,如 ValidatingWebhook 或 MutatingWebhook。这里为大家推荐两篇关于如何使用 OPA 的博客:Policy Enabled Kubernetes with Open Policy Agent [2]以及 Kubernetes Compliance with Open Policy Agent [3]。

动态准入控制具有以下限制:仅在 Kubernetes 资源上调用 Webhook 来创建、更新和删除事件。因此,它们不可能拒绝获取的请求。但与 Webhook 授权模块相比,它们也具有优势,因为它们可以根据 Kubernetes 资源的内容拒绝请求。这些是 Webhook 授权模块无法访问的信息。

作为参考,Webhook 授权模块由 SubjectAccessReviews 决定,而 ValidatingWebhook 和 MutatingWebhook 则由 AdmissionReviews 决定。在实践中,我们通过授权模块和 MutatingWebhook 来集成 OPA。

设计

本节概述了 Kubernetes 如何与 OPA 集成。由于 OPA 本身不能实现 Kubernetes 所需的 REST 介面,所以 Kubernetes Policy Controller 将 Kubernetes SubjectAccessReviews 和 AdmissionReviews 转换为 OPA 查询。

对于 Kubernetes API 伺服器收到的每个请求,执行以下序列:

  • 请求已通过身份验证;
  • 基于通过认证提取的用户信息,授权请求:
  • 调用 Webhook。在我们的例子中,Webhook 可以拒绝请求或将其转为发给 RBAC。Kubernetes Webhook 也可以允许请求,但这在 Kubernetes Policy Controller 中无法实现;
  • 执行 RBAC 模块。如果 RBAC 不允许该请求,则拒绝该请求;
  • 如果请求导致持久性发生变化,例如创建/更新/删除资源,则执行 Admission Controllers(MutatingWebhook 只是其中之一)。

因此,根据我们想要拒绝的具体内容,我们可以实施授权或许可 OPA 策略。有关如何配置此方案的更多信息,请参见 open-policy-agent / kubernetes-policy-controller(授权方案[4])。

实现

本节将说明如何使用 OPA 实现上述用例。除 kube-system 之外,为每个 namespace 创建/更新/删除 Pod。

它的基本思想是通过 RBAC 在集群范围内授予 Pod 的创建/更新/删除许可权,然后使用 OPA 策略拒绝访问 kube-system 中的 Pod。首先,我们授予user组创建/更新/删除 Pod 的许可权:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "update", "delete"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: user-pods
subjects:
- kind: Group
name: user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: pods
apiGroup: rbac.authorization.k8s.io

现在,允许user组中每个用户在集群范围内创建/更新/删除 Pod。如有需要通过 OPA 限制这些许可权,请部署以下策略:

package authorization
import data.k8s.matches
deny[{
"id": "pods-kube-system",
"resource": {
"kind": kind,
"namespace": namespace,
"name": name,
}, "resolution":
{
"message": "Yourre not allowed to create/update/delete pods in kube-system"

},
}]
{
matches[[kind, namespace, name, resource]]
not re_match("^(system:kube-controller-manager|system:kube-scheduler)$",
resource.spec.user)
resource.spec.resourceAttributes.namespace = "kube-system"
resource.spec.resourceAttributes.resource = "pods"
re_match("^(create|update|delete|deletecollections)$",
resource.spec.resourceAttributes.verb)
}

注意

排除system:kube-controller-managersystem:kube-scheduler,因为 Kubernetes 控制管理器和调度程序都必须能够访问 Pod。

resource.spec.resourceAttributes.resource ="pods" 如果删除,我们就可以限制对kube-system中所有 namespace 资源的访问。

OPA 使我们为所有策略编写单元测试变得非常容易。有关更多信息,请参阅如何测试策略[5]。

在特定 StorageClass 上执行创建/更新/删除

在此示例中,我们要授予用户对除ceph之外的所有 StorageClass 创建/更新/删除许可权。与第一个示例一样,我们必须通过 RBAC 授予用户访问许可权:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: storageclasses
rules:
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["create", "update", "delete"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: user-storageclasses
subjects:
- kind: Group
name: user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: storageclasses
apiGroup: rbac.authorization.k8s.io

现在我们需要拒绝通过 OPA 访问 StorageClass 的ceph,部署以下策略:

package authorization
import data.k8s.matches
deny[{
"id": "storageclasses",
"resource": {
"kind": kind,
"namespace": namespace,
"name": name,
},
"resolution": {"message": "Yourre not allowed to create/update/delete the StorageClassceph"},
}] {
matches[[kind, namespace, name, resource]]
resource.spec.resourceAttributes.resource = "storageclasses"
resource.spec.resourceAttributes.name = "ceph"
re_match("^(create|update|delete|deletecollections)$",
resource.spec.resourceAttributes.verb)
}

你可以通过以下的方式进行策略的单元测试:

package authorization
test_deny_update_storageclass_ceph {
deny[{"id": id, "resource":
{
"kind": "storageclasses", "namespace": "", "name": "ceph"},
"resolution": resolution
}]
with data.kubernetes.storageclasses[""].ceph as
{ "kind": "SubjectAccessReview",
"apiVersion": "authorization.k8s.io/v1beta1",
"spec":
{ "resourceAttributes":
{ "verb": "update",
"version": "v1",
"resource": "storageclasses",
"name": "ceph",
},
"user": "alice",
"group": ["user"],
},
}
}

总结

总之,与内置 RBAC 授权相比,OPA 允许更灵活的策略,尤其是在不使用其他 operator 的情况下。在我看来,将 OPA 直接集成为授权模块和准入控制器会很好,但与此同时,Kubernetes Policy Controller 弥补了 Kubernetes 和 OPA 之间的差距。以下是我通过实践得到的一些启示:

  • 拒绝访问特定的 CustomResourceDefinitions,如calico
  • 拒绝访问特定的 ClusterRoles,如cluster-adminadmin
  • 只允许埠转发到kube-system中的某些特定 Pod;
  • 创建一个映射,哪些 PodSecurityPolicies 可用于哪些 namespace ;
  • 除了一些预安装的配置,允许用户访问 ValidatingWebhookConfigurations。

以上就是本文的全部内容,你是如何看待 OPA 作为 Kubernetes 的策略引擎?如果感兴趣,不妨在读完本文后,亲自动手进行尝试!

参考文献

1.kubernetes.io/docs/refe

2.medium.com/capital-one-

3.itnext.io/kubernetes-co

4.github.com/open-policy-

5.openpolicyagent.org/doc


推荐阅读:
相关文章