内容:记录kubernetes的认证鉴权机制
k8s的安全问题:
1、保证容器与其所在宿主机的隔离; 2、限制容器给基础设施及其他容器带来消极影响的能力; 3、最小权限原则,合理限制所有组件权限,确保组件只执行它被授权的行为,通过限制单个组件 的能力来限制他所能达到的权限范围; 4、明确组件间边界的划分; 5、划分普通用户和管理员角色; 6、在必要的时候允许将管理员权限赋给普通用户; 7、允许拥有Secret数据(Keys、Certs、Passwords)的应用在集群中运行;k8s的认证过程:
## 对集群的操作方式: kubernetes 集群的所有操作基本上都是通过 apiserver 这个组件进行的,它提供 HTTP RESTful 形式的 API 供集群内外客户端调用。 ## 访问k8s的API需要经过的检查: kubernetes 对于访问 API 来说提供了三个步骤的安全措施:认证、授权、准入控制 当用户使用 kubectl,client-go 或者 REST API 请求 apiserver 时,都要经过 以上三个步骤的校验。 认证:是识别用户的身份 鉴权:是为了解决用户有哪些权限 准入控制:是作用于 kubernetes 中的对象,通过合理的权限管理,能够保证系统的安全可靠。 注意: 认证授权过程只存在 HTTPS 形式的 API 中,也就是说,如果客户端使用 HTTP 连接到 apiserver,是不会进行认证授权的访问示意图: 组件证书级配置参数
注意点:所有客户端的证书首先要经过集群CA的签署,否则不会被集群认可
1、kubectl
kubectl是个go编写的可执行程序,只要为kubectl配置合适的kubeconfig,就可以在集群中 的任意节点使用 。kubectl的权限为admin,具有访问kubernetes所有api的权限。 证书名称 作用 ca.pem CA根证书 admin.pem kubectl的TLS认证证书,具有admin权限 admin-key.pem kubectl的TLS认证私钥 设置了该集群的根证书路径,: --certificate-authority=/etc/kubernetes/ssl/ca.pem 证书写入到kubeconfig中: --embed-certs为true表示将--certificate-authority 指定kubectl证书: --client-certificate=/etc/kubernetes/ssl/admin.pem 指定kubectl私钥: --client-key=/etc/kubernetes/ssl/admin-key.pem2、kubelet
证书名称 作用 ca.pem CA根证书 kubelet-client.crt kubectl的TLS认证证书 kubelet-client.key kubectl的TLS认证私钥 kubelet.crt 独立于 apiserver CA 的自签 CA kubelet.key 独立于 apiserver CA 的私钥 当成功签发证书后,目标节点的 kubelet 会将证书写入到 --cert-dir= 选项指定的目录中; 此时如果不做其他设置应当生成上述除ca.pem以外的4个文件 注意: kubelet-client.crt 该文件在 kubelet 完成 TLS bootstrapping 后生成,此证书是由 controller manager 签署的,此后 kubelet 将会加载该证书,用于与 apiserver 建立 TLS 通讯,同时使用该证书的 CN 字段作为用户名,O 字段作为用户组向 apiserver 发起 其他请求 注意: kubelet.crt 该文件在 kubelet 完成 TLS bootstrapping 后并且没有配置 --feature-gates=RotateKubeletServerCertificate=true 时才会生成; 这种情况下该文件为一个独立于 apiserver CA 的自签 CA 证书,有效期为 1 年; 被用作 kubelet 10250 api 端口3、kube-apiserver
kube-apiserver是在部署kubernetes集群是最需要先启动的组件,是和集群交互核心组件。 以下是kube-apiserver所使用的证书 使用的证书 证书作用 ca.pem CA根证书 ca-key.pem CA端私钥 kubernetes.pem kube-apiserver的tls认证证书 kubernetes-key.pem kube-apiserver的tls认证私钥 --token-auth-file=/etc/kubernetes/token.csv 指定了token.csv的位置,用于kubelet 组件 第一次启动时没有证书如何连接 apiserver 。 Token 和 apiserver 的 CA 证书被写入了 kubelet 所使用的 bootstrap.kubeconfig 配置文件中;这样在首次请求时,kubelet 使用 bootstrap.kubeconfig 中的 apiserver CA 证书来与 apiserver 建立 TLS 通讯,使用 bootstrap.kubeconfig 中的用户Token 来向 apiserver 声明自己的 RBAC 授权身份 --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem 指定kube-apiserver证书地址 --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem 指定kube-apiserver私钥地址 --client-ca-file=/etc/kubernetes/ssl/ca.pem 指定根证书地址 --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem 包含PEM-encoded x509 RSA公钥和私钥的文件路径,用于验证Service Account的token, 如果不指定,则使用--tls-private-key-file指定的文件 --etcd-cafile=/etc/kubernetes/ssl/ca.pem 到etcd安全连接使用的SSL CA文件 --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem 到etcd安全连接使用的SSL 证书文件 --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem 到etcd安全连接使用的SSL 私钥文件4、kube-controller-manager
kubelet 发起的 CSR 请求都是由 kube-controller-manager 来做实际签署的, 所有使用的证书都是根证书的密钥对 。 由于kube-controller-manager是和kube-apiserver部署在同一节点上,且使用 非安全端口通信,故不需要证书 使用的证书 证书作用 ca.pem CA根证书 ca-key.pem kube-apiserver的tls认证私钥 --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem 指定签名的CA机构根证书,用来签名为 TLS BootStrap 创建的证书和私钥 --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem 指定签名的CA机构私钥,用来签名为 TLS BootStrap 创建的证书和私钥 --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem 同上 --root-ca-file=/etc/kubernetes/ssl/ca.pem 根CA证书文件路径 ,用来对 kube-apiserver 证书进行校验,指定该参数后,才会 在Pod 容器的 ServiceAccount 中放置该 CA 证书文件 --kubeconfig kubeconfig 配置文件路径,在配置文件中包括Master的地址信息及必要认证信息 kube-scheduler和kube-proxy: kube-scheduler是和kube-apiserver一般部署在同一节点上,且使用非安全端口通信, 故启动参参数中没有指定证书的参数可选 。 若分离部署,可在kubeconfig文件中指定证书, 使用kubeconfig认证,kube-proxy类似k8s的认证方式:
kubernetes 目前所有的认证策略如下所示: X509 client certs Static Token File Bootstrap Tokens Static Password File Service Account Tokens OpenId Connect Tokens Webhook Token Authentication Authticating Proxy Anonymous requests User impersonation Client-go credential plugins 常用举例: * X509 client certs X509是一种数字证书的格式标准,现在 HTTPS 依赖的SSL证书使用的就是使用的X509格式。 X509客户端证书认证方式是 kubernetes 所有认证中使用最多的一种,相对来说也是最安全 的一种,kubernetes 的一些部署工具 kubeadm、minkube 等都是基于证书的认证方式。 客户端证书认证叫作 TLS 双向认证,也就是服务器客户端互相验证证书的正确性,在都正确 的情况下协调通信加密方案。目前最常用的 X509 证书制作工具有 openssl、cfssl 等。 * Service Account Tokens 有些情况下,我们希望在 pod 内部访问 apiserver,获取集群的信息,甚至对集群进行改动。 针对这种情况,kubernetes 提供了一种特殊的认证方式:serviceaccounts。 serviceaccounts 是面向 namespace 的,每个 namespace 创建的时候,kubernetes 会自动在这个 namespace 下面创建一个默认的 serviceaccounts;并且这个 serviceaccounts 只能访问该 namespace 的资源。serviceaccounts 和 pod、 service、deployment 一样是 kubernetes 集群中的一种资源,用户也可以创建自己的 serviceaccounts。 serviceaccounts 主要包含了三个内容:namespace、token 和 ca,每个 serviceaccounts 中都对应一个secrets。namespace、token 和 ca 信息 都是保存在 secrets 中且都通过 base64 编码的。 namespace:指定了pod所在的namespace ca:用于验证apiserver的证书 token:用作身份验证 它们都通过 mount 的方式保存在 pod 的文件系统中,其三者都是保存在: /var/run/secrets/kubernetes.io/serviceaccount/ 认证解决的问题是识别用户的身份,那 kubernetes 中都有哪几种用户? 目前 kubernetes 中的用户分为内部用户和外部用户 内部用户:指在 kubernetes 集群中的 pod 要访问 apiserver 时所使用的,也就是 serviceaccounts,内部用户需要在 kubernetes 中创建。 外部用户:指kubectl 以及一些客户端工具访问 apiserver 时所需要认证的用户, 此类用户嵌入在客户端的证书中。k8s的鉴权方式:
kubernetes常见的鉴权机制: Node ABAC RBAC Webhook 举例:RBAC RBAC(Role-Based Access Control)是 kubernetes 中负责完成授权,是基于角色的 访问控制,通过自定义角色并将角色和特定的 user,group,serviceaccounts 关联起来 已达到权限控制的目的。 RBAC 中有三个比较重要的概念: Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限; Subject:被作用者,包括 user,group,serviceaccounts,通俗来讲就是认证 机制中所识别的用户; RoleBinding:定义了“被作用者”和“角色”的绑定关系,也就是将用户以及操作权限进行绑定; RBAC 其实就是通过创建角色(Role),通过 RoleBinding 将被作用者(subject)和角色 (Role)进行绑定。k8s的准入控制方式:
准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数,在对 kubernetes api服务器的请求过程中,先经过认证、授权后,执行准入操作,在对目标 对象进行操作。这个准入插件代码在apiserver中,而且必须被编译到二进制文件中才能被执行。 认证插件和授权插件完成身份认证和权限检查之后,准入控制器将拦截那些创建、更新和删除的 相关操作请求以强制实现控制器中实现的功能。 在对集群进行请求时,每个准入控制插件都按顺序运行,只有全部插件都通过的请求才会进入系统, 如果序列中的任何插件拒绝请求,则整个请求将被拒绝,并返回错误信息。 如何运行准入控制插件? 在kubernetes apiserver中有一个flag:admission_control,他的值为一串用逗号连接、 有序的准入模块列表,设置后,就可在对象操作前执行一定顺序的准入模块调用。 每个插件都做什么的? AlwaysPullImages: 此准入控制器修改每个 Pod 的时候都强制重新拉取镜像。 DefaultStorageClass: 此准入控制器观察创建PersistentVolumeClaim时不请求任何特定存储类的对象, 并自动向其添加默认存储类。这样,用户就不需要关注特殊存储类而获得默认存储类。 DefaultTolerationSeconds: 此准入控制器将Pod的容忍时间notready:NoExecute和unreachable:NoExecute 默认设置为5分钟。 DenyEscalatingExec: 此准入控制器将拒绝exec 和附加命令到以允许访问宿主机的升级了权限运行的pod。 EventRateLimit (alpha): 此准入控制器缓解了 API Server 被事件请求淹没的问题,限制时间速率。 ExtendedResourceToleration: 此插件有助于创建具有扩展资源的专用节点。 ImagePolicyWebhook: 此准入控制器允许后端判断镜像拉取策略,例如配置镜像仓库的密钥。 Initializers (alpha): Pod初始化的准入控制器,详情请参考动态准入控制。 LimitRanger: 此准入控制器将确保所有资源请求不会超过 namespace 的 LimitRange。 MutatingAdmissionWebhook (1.9版本中为beta): 该准入控制器调用与请求匹配的任何变更 webhook。匹配的 webhook是串行调用的; 如果需要,每个人都可以修改对象。 NamespaceAutoProvision: 此准入控制器检查命名空间资源上的所有传入请求,并检查引用的命名空间是否存在。 如果不存在就创建一个命名空间。 NamespaceExists: 此许可控制器检查除 Namespace 其自身之外的命名空间资源上的所有请求。 如果请求引用的命名空间不存在,则拒绝该请求。 NamespaceLifecycle: 此准入控制器强制执行正在终止的命令空间中不能创建新对象,并确保Namespace 拒绝不存在的请求。此准入控制器还防止缺失三个系统保留的命名空间default、 kube-system、kube-public。 NodeRestriction: 该准入控制器限制了 kubelet 可以修改的Node和Pod对象。 OwnerReferencesPermissionEnforcement: 此准入控制器保护对metadata.ownerReferences对象的访问,以便只有对该对象 具有“删除”权限的用户才能对其进行更改。 PodNodeSelector:此准入控制器通过读取命名空间注释和全局配置来限制可在命名 空间内使用的节点选择器。 PodPreset:此准入控制器注入一个pod,其中包含匹配的PodPreset中指定的字段, 详细信息见Pod Preset。 PodSecurityPolicy: 此准入控制器用于创建和修改pod,并根据请求的安全上下文和可用的Pod安全策略确 是否应该允许它。 PodTolerationRestriction: 此准入控制器首先验证容器的容忍度与其命名空间的容忍度之间是否存在冲突,并在 存在冲突时拒绝该容器请求。 Priority: 此控制器使用priorityClassName字段并填充优先级的整数值。如果未找到优先级,则拒绝Pod。 ResourceQuota: 此准入控制器将观察传入请求并确保它不违反命名空间的ResourceQuota对象中列举的任何约束。 SecurityContextDeny: 此准入控制器将拒绝任何试图设置某些升级的SecurityContext字段的pod 。 ServiceAccount: 此准入控制器实现serviceAccounts的自动化。准入控制实践举例:
(1)LimitRange资源与准入控制器 LimitRange资源在每个名称空中为每个容器指定最小及最大的计算资源用量 LimitRaneg资源支持限制容器、Pod和PersistentVolumeClaim三种资源对象的系统资源用量。 定义一个容器cpu资源限制如下: 比如定义个一限制对象:limitrange-cpu.yaml apiVersion: v1 kind: LimitRange metadata: name: cpu-limit-range spec: limits: - default: cpu: 1000m defaultRequest: cpu: 1000m min: cpu: 500m max: cpu: 2000m maxLimitRequestRatio: cpu: 4 type: Container (2)ResourceQuota资源与准入控制器 ResourceQuota资源用于定义名称空间的对象数量或系统资源配额,它支持限制每种资源类型 的对象总数以及所有对象所能消耗的计算资源及存储资源总量。 ResourceQuota对象可限制指定名称空间中非终止状态的所有pod对象的计算资源需求及计算 资源的限制总量: cpu或requests.cpu:cpu资源需求的总量限制 memory或requests.memory:内存资源需求的总量限制 limits.cpu:cpu资源限制的总量限制 limits.memory:内存资源限制的总量限制 ResourceQuota资源还支持限制特定名称空间中可以使用的PVC数量和这些PVC资源的空间 总大小,以及特定名称空间中可在指定的StorageClass上使用的PVC数量和这些PVC资源总数: requests.storage:所有PVC存储需求的总量限制 persistentvolumeclaims:可以创建的pvc总数 <storage-class-name>.storageclass.storage.k8s.io/requests.storage:指定 存储类上可使用的所有PVC存储需求的总量限额 <storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims: 指定存储类上可使用的PVC总数 requests.ephemeral-storage:所有pod可用的本地临时存储需求的总量 limits.ephemeral-storage:所有pod可用的本地临时存储限制的总量 比如创建一个限制对象:cat resourcequota-test.yaml apiVersion: v1 kind: ResourceQuota metadata: name: quota-example spec: hard: pods: "5" requests.cpu: 5 requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi count/deployments.apps: "1" count/deployments.extensions: "1" persistentvolumeclaims: "2" 查看效果: kubectl describe resourcequota quota-example Name: quota-example Namespace: default Resource Used Hard -------- ---- ---- count/deployments.apps 0 1 count/deployments.extensions 0 1 limits.cpu 0 2 limits.memory 0 2Gi persistentvolumeclaims 4 2 pods 4 5 requests.cpu 0 5 requests.memory 0 1Gi 注意: 在名称空间上启用了CPU和内存等系统资源的配额后,用户创建Pod对象时必须指定资源需求或 资源限制,否则会触发ResouceQuota准入控制器拒绝相应的操作。同时资源配额仅对那些在 ResourceQuota对象创建之后生成的对象有效,对已经存在的对象不会产生任何的影响。