用户访问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. poj 1035 纯正的字符串水

    Spell checker Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 22673   Accepted: 8258 De ...

  2. npm理解

    NPM就是一个下载器,通过它可以下载到几乎所有你需要的代码资源.它的成功,包括如下几个方面: 海量资源:NPM背后有数以万计的开源免费模块. 高效利用:作为开发者,只需要敲几个简单的命令就可以将这些开 ...

  3. 使用 redux 监听插件的使用

    首先需要在chrome浏览器当中下载redux插件 接着在你的项目当中加上**window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX ...

  4. webpack最佳入门实践系列(5)

    9.路径相关 原来我们打包的东西都存放到了dist目录下,并没有进行分类存储,乱成一团,这一节我们就要处理一下打包的路径,让打包后的目录看起来更加优雅 9.1.代码准备 我们先建立起这样一个目录结构 ...

  5. bzoj4897 [Thu Summer Camp2016]成绩单

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4897 [题解] 第一次看这题想的是f[l,r]的区间dp发现仅记录这两个好像不能转移啊 会出 ...

  6. 【原创】Linux环境下的图形系统和AMD R600显卡编程(4)——AMD显卡显存管理机制

    显卡使用的内存分为两部分,一部分是显卡自带的显存称为VRAM内存,另外一部分是系统主存称为GTT内存(graphics translation table和后面的GART含义相同,都是指显卡的页表,G ...

  7. UVA 10940 Throwing cards away II

    题意略: 先暴力打表发现规律 N=1 ans=1N=2 ans=2N=3 ans=2N=4 ans=4N=5 ans=2N=6 ans=4N=7 ans=6N=8 ans=8N=9 ans=2N=10 ...

  8. trickle charging current is 0A ?

    Recently, I test trickle charging current of the smart phone. It's 0A. ?????????????????????? yes, i ...

  9. APscheduler总结

    APscheduler使用总结 APscheduler是执行定时任务的python库,其作用可以代替Linux系统下的crontab,github上有该库的例子. APsheduler基本使用 该模块 ...

  10. BestCoder 2nd Anniversary的前两题

    Oracle Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Su ...