用户访问API Server(以下简称Server),K8S的安全检查步骤:认证和授权。

认证解决用户是谁的问题,就是验证用户名密码;授权解决用户能做什么的问题,就是检查该用户是否拥有权限访问请求的资源。通过合理的权限管理,能够保证系统的安全可靠。

网络

Server通过本地端口(Localhost Port)和安全端口(Secure Port)对外提供API服务,其中本地端口是基于HTTP协议的,用于本地无限制访问,安全端口是基于HTTPS协议的,用于远程有限制访问。

本地端口

默认配置中,Server的本地端口默认绑定到地址127.0.0.1上,只能在本机访问。由于本地端口将绕过了Server的认证和授权,只要能够访问本地端口,可以无限制访问Server。基于安全考虑,尽量不要将本地端口绑定到127.0.0.1以外的地址上。

本地端口默认绑定到端口8080上,可以通过Server启动参数--insecure-port进行指定,如果为0关闭本地端口。参数--insecure-bind-address指定绑定地址。

安全端口

安全端口是Server对外提供的,用于外部访问的安全的可控的API调用接口,Server只允许通过认证的用户(认证信息来源于User Account或者Service Account)才能够通过安全端口访问,对于匿名用户401拒绝访问。

默认绑定到端口6443上,通过Server的启动参数--secure-port进行指定,如果为0关闭安全端口。默认绑定到地址0.0.0.0上,通过参数--bind-address进行指定。

通过参数--tls-cert-file和--tls-private-key-file指定证书和私钥。

代理和防火墙

在实际应用中,可能现有的认证体系无法与K8S集成或者需要执行特殊认证和授权逻辑的情况,可以考虑引入代理(Proxy)来解决认证和授权的问题,在认证通过后,代理将请求转发到Server。

当代理能够与Server部署在同一台主机时,建议按照下面的方式进行集成:

关闭安全端口,确保所有的API请求只能通过代理接入
将本地端口绑定到地址127.0.0.1上,确保只能在本机访问
设置防火墙规则,仅开放本机的443端口
配置nginx监听443端口,并且在此端口上配置认证和HTTPS
配置nginx将请求转发到本地端口,默认情况下为127.0.0.1:8080

当代理无法与Server部署在同一台主机时,从安全角度看,再试图通过本地端口与Server集成不是好的选择,使用安全端口与Server集成更好更安全。

认证

只能用于HTTPS(安全端口),对http(非安全端口)来说无效,原因请看上节的“本地端口”。

认证方式有很多种,这里主要介绍以下几种:

静态密码/用户账号

用户账号(User Accounts,以下简称UA),也称静态密码,是用于管理者通过web访问Server的认证用户名和密码。

静态密码是提前在某个文件中保存了用户名和密码的信息,然后通过Server启动参数 --basic-auth-file=SOMEFILE指定文件路径。

文件是CSV格式,每行对应一个用户信息,前面三列密码、用户名、UID 是必须的,第四列是可选的组名(多个组,必须用双引号):password,user,uid,"group1,group2,group3" 例如 cat /etc/kubernetes/useraccount.csv 1qaz2wsx,lykops,1 1qaz2wsx,lykchat,2

如果是通过客户端发送请求时(非用户通过web页面请求的),需要指定ca证书、用户名和密码。例如:

curl -u lykops:1qaz2wsx https://192.168.20.128:6443/ --cacert /etc/ssl/kube/ca.pem

注意:不能动态更新,需要重启api server。

服务账号

服务账号(Service Accounts,以下简称SA)并不是给K8S集群的用户使用的,而是用于Pod中的程序访问API的account,它为Pod中的程序提供了一种身份标识。UA的作用域为K8S集群全局,是全局性权限,SA的作用域为命名空间(简称ns)。SA作为一种资源对象存在于K8S中。具体请看资源对象—service acecount章节。

原理

查看一下kube-system ns下名为默认sa的详细信息: kubectl describe serviceaccount/default -n kube-system Name: default Namespace: kube-system Labels: Image pull secrets: Mountable secrets: default-token-hpni0 Tokens: default-token-hpni0

看到sa并不复杂,只是关联了一个secret资源对象作为token,该token也叫service-account-token,该token才是真正在Server验证(authentication)环节起作用的: kubectl get secret -n kube-system NAME TYPE DATA AGE default-token-hpni0 kubernetes.io/service-account-token 3 140d

kubectl get secret default-token-hpni0 -o yaml -n kube-system
apiVersion: v1
data:
ca.crt: {base64 encoding of ca.crt data}
namespace: a3ViZS1zeXN0ZW0=
token: {base64 encoding of bearer token}
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: default
name: default-token-hpni0
namespace: kube-system
type: kubernetes.io/service-account-token

看到这个类型为service-account-token的secret资源包含的数据有三部分:ca.crt、namespace和token。

ca.crt是Server的CA公钥证书;
namespace是Secret所在ns值的base64编码
token是一段用Server私钥(在创建sa时用Server参数--service-account-key-file指定的,如果未指定,那么将默认使用--tls-private-key-file值,即Server的私钥server.key)文件内容签发(sign)的bearer tokens的base64编码。

认证过程

在K8S的认证环节中,以某个sa提供身份的Pod的用户名为:system:serviceaccount:(ns):(sa)。以kube-system ns下的默认sa为例,使用它的Pod的username全称为:system:serviceaccount:kube-system:default。有了用户名,那么credentials(凭证)呢?就是上面提到的service-account-token中的token。

如果客户端使用sa token方式(携带service account token)访问api,Server采用signed bearer token方式进行身份校验。 通过身份校验后,Server将根据Pod用户名所在的group:system:serviceaccounts和system:serviceaccounts:(NAMESPACE)的权限分配权限(authority和admission control两个环节)。在这两个环节中,管理员可以对service account的权限进行细化设置。

引用

如果Pod中没有显式指定spec.serviceAccount字段值,那么K8S会将该ns下的默认sa自动mount到在该ns中创建的Pod里。

kubectl describe pod/index-api-2822468404-4oofr
Name: index-api-2822468404-4oofr
Namespace: default
... ...
Containers:
index-api:
... ...
Volume Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-40z0x (ro)
Environment Variables: <none>
... ...
Volumes:
... ...
default-token-40z0x:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-40z0x QoS Class: BestEffort
Tolerations: <none>
No events.

可以看到,K8S将default ns中的默认sa的service account token挂载(mount)到了Pod中容器的/var/run/secrets/kubernetes.io/serviceaccount路径下。

深入容器内部,查看mount的sa路径下的结构:

docker exec 3d11ee06e0f8 ls  /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

这三个文件与上面提到的sa中的数据是一一对应的。

双向认证

客户端证书认证叫作TLS双向认证,就是服务器客户端互相验证证书的正确性,在都正确的情况下协调通信加密方案。

双向认证方式是最为严格和安全的集群安全配置方式,主要配置流程如下:

生成根证书、Server服务端证书、服务端私钥、各个组件所用的客户端证书和客户端私钥。
修改K8S各个服务进程的启动参数,启用双向认证模式。

静态Token文件

类似于静态密码,只是通过token来代替密码。

当在命令行指定--token-auth-file=SOMEFILE选项时,Server从文件中读取bearer tokens。令牌文件是一个至少包含3列的csv文件: token, user name, user uid,后跟可选的组名。注意,如果有多个组,则列必须是双引号,例如:token,user,uid,"group1,group2,group3" 当客户端使用bearer token认证时,需要发送一个“Authorization: Bearer ”+token(token必须是一个可以放在HTTP请求头中且值不需要转码和引用)的字符串。例如:token是31ada4fd-adec-460c-809a-9e56ceb75269,客户端的HTTP头必须添加:Authorization:
Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

注意:不能动态更新,需要重启api server,很不灵活,也不安全,不推荐使用。

OpenID Connect Tokens

OpenID Connect是由OAuth2提供商支持的OAuth2,特别是Azure Active Directory,Salesforce和Google。OAuth2的协议的主要扩展是增加一个额外字段,返回了一个叫ID token的access token。这个token是被服务器签名的JSON Web Token (JWT) ,具有众所周知的字段,比如用户的email。

为了识别用户,验证使用来自OAuth2 token响应的idtoken
(而不是access
token)作为bearer token。

使用OpenID认证,API Server需要配置

- --oidc-issuer-url,如https://accounts.google.com
- --oidc-client-id,如kubernetes
- --oidc-username-claim,如sub
- --oidc-groups-claim,如groups
- --oidc-ca-file,如/etc/kubernetes/ssl/kc-ca.pem

Webhook Token

Webhook Token认证方式可以让用户使用自己的认证方式(类似于单点登录),用户按照约定的请求格式和应答格式提供HTTPS服务,当用户把Bearer Token放到请求的头部,K8S会把token发送给事先配置的地址进行认证,如果认证结果成功,则认为请求用户合法。这种方式下有两个参数 可以配置:

–authentication-token-webhook-config-file :认证URL地址的配置文件

–authentication-token-webhook-cache-ttl :认证结果要缓存多久,默认是两分钟

这种方式下,自定义认证的请求和应答都有一定的格式,具体的规范请参考官方文档。

认证代理

Server配置文件需要制定以下配置

--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-
# 为了防止头部欺骗,证书是必选项
--requestheader-client-ca-file
# 设置允许的CN列表。可选。
--requestheader-allowed-names

Keystone Password

Keystone是OpenStack提供的认证和授权组件,这个方法对于已经使用openstack来搭建Iaas平台的公司比较适用,直接使用keystone可以保证Iaas和Caas平台保持一致的用户体系。

需要Server在启动时指定--experimental-keystone-url=,而https时还需要设置--experimental-keystone-ca-file=SOMEFILE。

引导Token

在v1.6版本中,这个特性还是alpha特性。为了能够在新的集群中使用bootstrapping认证。Kubernetes包括一种动态管理的Bearer(持票人) token,这种token以Secrets的方式存储在kube-system命名空间中,在这个命名空间token可以被动态的管理和创建。Controller Manager有一个管理中心,如果token过期了就会删除。

创建的token证书满足[a-z0-9]{6}.[a-z0-9]{16}格式,Token的第一部分是一个Token ID,第二部分是token的秘钥。你需要在http协议头中加上类似的信息:

Authorization: Bearer 781292.db7bc3a58fc5f07e

如果要使用Bootstrap,需要在API Sever中开启--experimental-bootstrap-token-auth。同时必须在Controller Manager中开启管理中心的设置--controllers=*,tokencleaner。

在使用kubeadm部署Kubernetes时,kubeadm会自动创建默认token,可通过kubeadm token list命令查询。

匿名请求

如果请求没有通过以上任何方式的认证,正常情况下应该是直接返回 401 错误。但K8S还提供另外一种选择,给没有通过认证的请求一个特殊的用户名system:anonymous和组名 system:unauthenticated 。 这样可以跟下面要讲的授权结合起来,为匿名请求设置一些特殊的权限,比如只能读取当前ns的pod信息,方便用户访问。 如果使用AlwaysAllow、AlwaysDeny以外的认证模式,则匿名请求默认开启,但可用--anonymous-auth=false禁止匿名请求。

授权插件

K8S的授权是通过插件方式来实现的,目前K8S内置提供了AlwaysDeny、AlwaysAllow、ABAC、RBAC以及WebHook等几种授权插件(在1.5.2版本中,只有这五种),通过配置Server启动参数--authorization-mode来指定授权模式。

授权处理以下的请求属性: user, group, extra API、请求方法(如get、post、update、patch和delete)和请求路径(如/api) 请求资源和子资源 Namespace API Group

AlwaysDeny

该模式将会拒绝任何对安全端口的请求。任何访问,服务端总是返回Forbidden: "URL",表示访问被拒绝。

AlwaysDeny模式主要用于测试,当然也可以用来暂时停止集群的对外服务。

AlwaysAllow

默认模式,该模式下只要通过认证,服务端将会接受任何对安全端口的请求,换句话说就是除了认证没有任何权限限制。

当集群不需要做授权限制时,直接使用该模式,以降低配置的复杂性。

ABAC

ABAC(Attribute-based access control,基于属性的访问控制),ABAC的核心是根据请求的相关属性,例如用户属性、资源属性以及环境属性等属性,作为授权的基础来进行访问控制,以解决分布式系统的可信任关系的访问控制问题。

ABAC的策略文件是一个one JSON object per line格式的文本文件。ABAC的授权过程可以简单的理解为将请求属性转换为一个spec对象,然后拿到这个spec对象与策略文件中定义的spec对象进行匹配,如果这个spec对象能够与策略文件中定义的任何一条规则允许的spec对象匹配,那么授权通过;如果这个spec对象无法与任何一条规则匹配,那么授权失败。

RBAC

WebHook

WebHook模式是一种扩展授权模式,在这种模式下,API Server将授权过程委派到外部的一个REST服务,由外部的服务决定是否授予指定请求继续访问的权限。

WebHook模式的开启非常的简单,只需要通过API Server的启动参数--authorization-mode设置为WebHook并且通过启动参数--authorization-webhook-config-file将外部授权服务的配置信息告诉API Server即可。

Admission Control 准入控制

当请求通过了前面的认证和授权后,还需要经过准入控制处理通过之后,server才会处理这个请求。Admission Control 有一个准入控制列表,可以通过命令行设置选择执行哪几个准入控制器。只有所有的准入控制器都检查通过之后,apiserver 才执行该请求,否则返回拒绝。

kubernetes API Server安全的更多相关文章

  1. Kubernetes API server工作原理

    作为Kubernetes的使用者,每天用得最多的命令就是kubectl XXX了. kubectl其实就是一个控制台,主要提供的功能: 1. 提供Kubernetes集群管理的REST API接口,包 ...

  2. 资深专家深度剖析Kubernetes API Server第2章(共3章)

    欢迎来到深入学习Kubernetes API Server的系列文章的第二部分.在上一部分中我们对APIserver总体,相关术语及request请求流进行探讨说明.在本部分文章中,我们主要聚焦于探究 ...

  3. 资深专家深度剖析Kubernetes API Server第1章(共3章)

    欢迎来到深入学习Kubernetes API Server的系列文章,在本系列文章中我们将深入的探究Kubernetes API Server的相关实现.如果你对Kubernetes的内部实现机制比较 ...

  4. 深度剖析Kubernetes API Server三部曲 - part 2

    欢迎来到深入学习Kubernetes API Server的系列文章的第二部分.在上一部分中我们对APIserver总体,相关术语及request请求流进行探讨说明.在本部分文章中,我们主要聚焦于探究 ...

  5. 深度剖析Kubernetes API Server三部曲 - part 1

    欢迎来到深入学习Kubernetes API Server的系列文章,在本系列文章中我们将深入的探究Kubernetes API Server的相关实现.如果你对Kubernetes 的内部实现机制比 ...

  6. kubernetes API Server 权限管理实践

    API Server权限控制方式介绍 API Server权限控制分为三种:Authentication(身份认证).Authorization(授权).AdmissionControl(准入控制). ...

  7. 资深专家深度剖析Kubernetes API Server第3章(共3章)

    在本系列的前两部分中我们介绍了API Server的总体流程,以及API对象如何存储到etcd中.在本文中我们将探讨如何扩展API资源. 在一开始的时候,扩展API资源的唯一方法是扩展相关API源代码 ...

  8. 深度剖析Kubernetes API Server三部曲 - part 3

    在本系列的前两部分中我们介绍了API Server的总体流程,以及API对象如何存储到etcd中.在本文中我们将探讨如何扩展API资源. 在一开始的时候,扩展API资源的唯一方法是扩展相关API源代码 ...

  9. 利用curl命令访问Kubernetes API server

    kubectl 通过访问 Kubernetes API 来执行命令.我们也可以通过对应的TLS key, 使用curl 或是 golang client做同样的事. API 请求必须使用 JSON 格 ...

随机推荐

  1. Scala 基础(7)—— 函数字面量和一等函数

    1. 函数字面量 在 Scala 基础(3)—— 基础类型和基础操作 中提到了函数字面量,这里具体解释函数字面量的语法. 下面展示一个具体的函数字面量,它由三部分组成: (x: Int, y: Int ...

  2. <转自原博客> 可爱的字符串算法们

    在非常强又非常关心学弟学妹学习的企鹅学长变态的考纲下,我们无奈中选择一起学习新姿势 first:KMP算法 这是一个小迪更过博客的算法,我就不好意思在这里献丑了,所以献上友链一份:http://rab ...

  3. DP———7.导弹拦截(emmm冷静分析一波也不叫DP吧,不过有一种DP的方法写)

    最少拦截系统 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  4. NFS排错案例

    1.检验rpcinfo从客户端 # rpcinfo -p nfsserverip ,可以看到服务器端开的tcp/udp端口.默认都是打开的,客户端可以自己选择使用TCP/UDP program ver ...

  5. 物理和虚拟兼容性RDM的区别

    Difference between Physical compatibility RDMs and Virtual compatibility RDMs (2009226) Purpose This ...

  6. Java并发笔记(二)

    1. 活跃性危险 死锁(最常见) 饥饿 当线程由于无法访问它所需的资源而不能继续执行时,就发生了饥饿.引发饥饿最常见资源就是CPU时钟周期. 活锁 活锁指的是任务或者执行者没有被阻塞,由于某些条件没有 ...

  7. (计数器)NOIP模拟赛(神奇的数位DP题。。)

    没有原题传送门.. 手打原题QAQ [问题描述]     一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9.其中—个页码不含多余的0,如N=1234时第5页不是00 ...

  8. android与PC直连的socket问题

    关键字:abdroid 模拟器 socket 突然有人说使用android的模拟器做socket服务器,PC做客户端,使用UDP通信的时候,android端无法收到数据包.反过来没问题,我觉得这怎么可 ...

  9. Kubernetes控制节点安装配置

    #环境安装Centos 7 Linux release 7.3.1611网络: 互通配置主机名设置各个服务器的主机名hosts#查找kubernetes支持的docker版本Kubernetes v1 ...

  10. 多线程之:ThreadLocal

    Java中ThreadLocal类可以使创建的变量只被同一个线程进行读和写操作,即使有多个线程同时执行同一段代码,并且这段代码中又有一个指向同一个ThreadLocal变量的引用,这些线程依然不能看到 ...