前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用 Open Policy Agent 实现 K8s 授权

利用 Open Policy Agent 实现 K8s 授权

作者头像
CNCF
发布2019-12-05 14:10:50
2.2K0
发布2019-12-05 14:10:50
举报
文章被收录于专栏:CNCF

翻译:小君君 技术校对:星空下的文仔、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 的权限:

代码语言:javascript
复制
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 限制这些权限,请部署以下策略:

代码语言:javascript
复制
package authorization
import data.k8s.matches
deny[{   
       "id": "pods-kube-system",    
       "resource": {        
       "kind": kind,        
       "namespace": namespace,        
       "name": name,
   },    "resolution": 
{
"message": "Your're 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 授予用户访问权限:

代码语言:javascript
复制
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,部署以下策略:

代码语言:javascript
复制
package authorization
import data.k8s.matches
deny[{    
      "id": "storageclasses",    
      "resource": {       
             "kind": kind,      
             "namespace": namespace,
             "name": name,
   },   
    "resolution": {"message": "Your're not allowed to create/update/delete the StorageClass'ceph'"},
}] {
    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)
}

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

代码语言:javascript
复制
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.https://kubernetes.io/docs/reference/access-authn-authz/rbac/

2.https://medium.com/capital-one-tech/policy-enabled-kubernetes-with-open-policy-agent-3b612b3f0203

3.https://itnext.io/kubernetes-compliance-with-open-policy-agent-3d282179b1e9

4.https://github.com/open-policy-agent/gatekeeper

5.https://www.openpolicyagent.org/docs/how-do-i-test-policies.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CNCF 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参考文献
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档