K8S 的用户系统
K8S 有两种类型的用户
- service account
- 一般用户(人)
一般用户
一般用户被认为是由外部独立的服务(比如公司的员工)管理的。例如:一个分发私钥的管理员,一个像Keystone或谷歌帐户这样的用户存储,甚至一个包含用户名和密码列表的文件。在这方面,Kubernetes没有表示普通用户帐户的对象。不能通过API调用将普通用户添加到集群中。
service account
相反,服务帐户是由Kubernetes API管理的用户。它们被绑定到特定的名称空间,并由API服务器自动创建或通过API调用手动创建。服务帐户被关联到一组用作凭证的secret中,这些secret凭证被挂载到pod中,允许集群内进程与Kubernetes API通信。
API请求要么绑定到普通用户,要么绑定到服务帐户,要么作为匿名请求处理。这意味着集群内外的每个进程,不论是PC客户端上使用kubectl的人工用户或者节点上的kubelets,再到控制平面的成员,向API服务器发出请求时都必须进行身份验证,或者被视为匿名用户。
认证
API SERVER 认证方式(K8S 的所有访问都是通过 api server)
- https 证书认证: 基于CA根证书签名的双向数字证书认证方式
- http token 认证: 通过一个token来识别合法用户
- http basic 认证: 通过用户名密码的方式认证
- authenticating proxy: 第三方授权协议
认证策略
api server 拥有一条链式的认证插件, 没个请求被认证插件验证时,插件会试图将请求与以下属性进行关联
用户名(username):标识最终用户的字符串。常见的值可能是kube-admin或[email protected]。
UID:标识最终用户并试图比username更一致和惟一的字符串。
组(group):一组字符串,它将用户与一组通常分组的用户相关联。
额外字段(extra fileds):字符串映射到包含附加信息授权方可能会发现有用的字符串列表。
所有值对身份验证系统都是不透明的,只有在由授权方( authorizer)使用时才具有意义。
您可以同时启用多个身份验证方法。通常应该使用至少两种方法:
服务帐户(service account) 的服务帐户令牌(service account token)
一种用于用户身份验证的方法。
当启用多个验证器模块时,第一个模块将成功地验证 "请求短路评估" (request short-circuits evaluation)。,如果验证失败,则进行断路操作,API服务器不保证运行验证器的执行顺序。
所有通过验证的用户都会被添加进system:authenticated组。
可以使用authenticating proxy 或authentication webhook与其他身份验证协议(LDAP、SAML、Kerberos、备用x509方案等)集成。
额外知识补充:https证书认证原理
CA: PKI 系统中通信双方都信任的实体, 被称为可信第三方(trusted third party TTP)
CA通过证书证实他人的公钥信息,证书上有CA的签名. 证书中绑定了公钥数据和相应私钥用后者的身份信息,并带有CA的数字签名;在证书中也包含的CA的名称,以方便依赖方找到CA的公钥,验证数字证书上的签名
CA 涉及的概念
**根证书, 自签名证书, 密钥, 私钥, 加密算法 **
CA 认证步骤
- https 通信双方的服务器端, 想CA 机构申请证书. CA 机构下发根证书,服务端证书,私钥给申请者
- https 通信双方的客户端向CA机构申请证书, CA 机构下发根证书,服务端证书,私钥给申请者
- 客户端向服务端发起请求,服务端下发服务端证书给客户端,客户端接收到证书后, 通过私钥揭秘证书, 利用服务端证书中的公钥认证证书信息比较证书里的消息. 例如,比较域名和公钥, 与服务器刚发送的相关信息是否一致, 如果一致, 则认为服务端是可信的
- 客户端发送客户端证书给服务端,服务端通过私钥解密证书,获得客户端公钥,并用该公钥认证证书信息
- 客户端通过随机密钥加密信息发送给服务端. 服务端和客户端协商好加密方案后,客户端会产生一个随机的密钥,客户端通过协商好的加密方案加密该密钥,并发送该随机密钥给服务端. 服务器接收密钥后, 双方所有内容通过该随机密钥加密
http 其他认证方式
token 认证原理
token 是一个难以被模仿的字符串, 每个token对应一个用户名, 存放在API server能访问的一个文件中. 当客户端发起API调用时, token放在header中, API 就能识别是否非法.
http basic 认证
这种认证方式是把 用户名+冒号+密码 用base64 算法进行编码后放到header中进行身份识别
K8S 的 X509 Client Certs 认证
要启用 X509证书认证,需要在apiserver
的启动参数中添加--client-ca-file=SOMEFILE
, api server X509 认证的完整启动参数如下
kube-apiserver
--advertise-address=192.168.10.50
--allow-privileged=true
--authorization-mode=Node,RBAC
--client-ca-file=/etc/kubernetes/pki/ca.crt
--enable-admission-plugins=NodeRestriction
--enable-bootstrap-token-auth=true
--etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
--etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
--etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
--etcd-servers=https://127.0.0.1:2379
--insecure-port=0
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
--kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
--requestheader-allowed-names=front-proxy-client
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--secure-port=6443
--service-account-key-file=/etc/kubernetes/pki/sa.pub
--service-cluster-ip-range=10.96.0.0/12
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key
K8S 组件的X509证书认证配置
证书管理工具有一下三种
- easyrsa
- openssl
- cfssl
使用openssl 的方式
主要步骤如下
- 生成自签名 CA 证书
- 为kube-apiserver 生成数字证书, 并用CA证书签名
- 为kube-apiserver 配置相关启动参数
- 为每个kube-apiserver的客户端(kube-controller-manager, kube-scheduler, kubelet, kube-proxy, kubectl, etcd ) 都生成自己的证书,也用CA 进行签名,并配置起启动参数
生成 CA 证书
# 生成CA的私钥
openssl genrsa -out ca.key 2048
# 通过ca私钥生成ca证书,注意CN= 的部分必须是master的主机名或IP地址
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
准备master_ssl.cnf文件,用户生成X509 V3 版本的证书.该文件中主要设置master服务器的ip地址(192.168.10.3),以及k8s master service的虚拟服务域名(kubernetes.default),以及虚拟服务的cluster ip(10.96.0.1)
master_ssl.cnf
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C =
ST =
L =
O =
OU =
CN =
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
# apiserver 所在主机的IP
IP.1 =
# 一般为 api server --service-cluster-ip-range=10.96.0.0/12 参数的第一位ip,也就是10.96.
IP.2 =
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names
基于master_ssl.cnf 创建server.csr(证书请求) 和server.crt(证书) 文件. 在生成server.csr 时, -subj 参数中 "/CN" 的值需为master的主机名
#### 生成 api server的私钥
openssl genrsa -out server.key 2048
生成证书请求
openssl req -new -key server.key -subj "CN=k8s-master" -config master_ssl.cnf -out server.csr
# 生成ca 签名的证书
openssl x509 -req server.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out server.crt
执行完之后 生成ca.srl server.crt server.csr server.key 将生成的文件和之前生成的ca.key ca.crt 复制到/etc/kubernetes/ssl 文件夹下
设置kuber-apiserver 的三个启动参数
--client-ca-file=/etc/kubernetes/ssl/ca.crt
--tls-private-key=/etc/kubernetes/ssl/server.key
--tls-cert-file=/etc/kubernetes/ssl/server.crt
同事关闭非安全端口 --insecure-port = 0 并设安全端口 --secure-port=6443 重启kube-apiserver 服务
生成kube-controller-manager 的证书
openssl genrsa -out cs_client.key 2048
openssl req - new -key cs_client.key -subj "CN=k8s-master" -config master_ssl.cnf -out cs_client.csr
openssl x509 -req cs_client.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out cs_client.crt
编写kuber-controller-manager 配置文件
vim /etc/kubernetes/ssl/kubeconfig
# kubeconfig for kube-controller-manager
apiVersion: v1
kind: config
users:
- name: controllermanager
user:
client-certificate: /etc/kubernetes/ssl/cs_client.crt
client-key: /etc/kubernetes/ssl/cs_client.key
clusters:
- name: local
cluster:
certificate-authority: /etc/kubernetes/ssl/ca.crt
server: http://192.168.18.3:6443
contexts:
- context:
cluster: local
user: controllermanager
name: mycontext
current-context: mycontext
修改 kube-controller-manager 的启动参数
--service-account-key-file=/etc/kubernetes/ssl/server.key
--root-ca-file=/etc/kubernetes/ssl/ca.crt
--kubeconfig=/etc/kubernetes/ssl/kubeconfig
生成kubelet的证书
openssl genrsa -out kubelet_client.key 2048
openssl req - new -key kubelet_client.key -subj "CN=k8s-master" -config master_ssl.cnf -out kubelet_client.csr
openssl x509 -req kubelet_client.csr -CA ca.crt -CAkey ca.key -CAcreaterserial -days 5000 -extensions v3_req -extfile master_ssl.cnf -out kubelet_client.crt
在非master节点编写kuber-controller-manager 配置文件
vim /etc/kubernetes/ssl/kubeconfig
# kubeconfig for kube-controller-manager
apiVersion: v1
kind: config
users:
- name: controllermanager
user:
client-certificate: /etc/kubernetes/ssl/kubelet_client.crt
client-key: /etc/kubernetes/ssl/kubelet_client.key
clusters:
- name: local
cluster:
certificate-authority: /etc/kubernetes/ssl/ca.crt
server: http://192.168.18.3:6443
contexts:
- context:
cluster: local
user: controllermanager
name: mycontext
current-context: mycontext
修改 kubelet的启动参数, 添加--kubeconfig=/etc/kubernetes/kubeconfig
生成 admin的证书
openssl genrsa -out admin.key 2048
openssl req -new -key admin.key -out admin.csr -subj "/O=system:masters/CN=dmin"
openssl x509 -req -set_serial $(date +%s%N) -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt -days 365 -extensions v3_req -extfile req.conf
这样,通过 证书认证的形式配置了K8S的认证
使用easyrsa 生成证书
1 下载 easy rsa
curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki
2 生成 ca 证书
# --batch 自动模式,--req-cn 设置默认的CN
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
3 生成api server相关证书
./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:${MASTER_CLUSTER_IP},"\
"DNS:kubernetes,"\
"DNS:kubernetes.default,"\
"DNS:kubernetes.default.svc,"\
"DNS:kubernetes.default.svc.cluster,"\
"DNS:kubernetes.default.svc.cluster.local" \
--days=10000 \
build-server-full server nopass
4 修改 api server 启动参数
--client-ca-file=/yourdirectory/ca.crt
--tls-cert-file=/yourdirectory/server.crt
--tls-private-key-file=/yourdirectory/server.key
5 生成 admin 证书
./easyrsa --dn-mode=org --req-cn=admin --req-org=system:masters --req-c= --req-st= --req-city= --req-email= --req-ou= build-client-full admin nopass
cfssl 方式
1编写cfssl ca 配置文件
ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
2 变现 ca 证书请求配置文件
ca-csr.json
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names":[{
"C": "",
"ST": "",
"L": "",
"O": "",
"OU": ""
}]
}
3 生成CA证书文件
/opt/local/cfssl/cfssl gencert -initca csr.json | /opt/local/cfssl/cfssljson -bare ca
4 编写api server 证书配置文件 server-crs.json
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"",
"",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "",
"ST": "",
"L": "",
"O": "",
"OU": ""
}]
}
5 生成 api server 证书文件
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
--config=ca-config.json -profile=kubernetes \
server-csr.json | ../cfssljson -bare server
6 编辑 admin 配置文件 admin-csr.json
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "ShenZhen",
"L": "ShenZhen",
"O": "system:masters",
"OU": "System"
}
]
}
7 生成 admin 证书
/opt/local/cfssl/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
-ca-key=/etc/kubernetes/ssl/ca-key.pem \
-config=/opt/ssl/config.json \
-profile=kubernetes admin-csr.json | /opt/local/cfssl/cfssljson -bare admin
token 认证
传统token
api server 支持token认证, 通过在启动参数中添加 ----token-auth-file=SOMEFILE
进行支持,如果修改token file的内容,必须重启api server才能生效
在API 请求中通过在请求的header 中添加token 进行验证
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
Bootstrap Tokens
为了允许对新的集群进行方便的初始化安装引导,Kubernetes包含一个动态管理的承载令牌类型,称为引导令牌(bootstrap token)。这些令牌作为secret存储在kube-system名称空间中,可以在其中动态管理和创建它们。Controller Manager包含一个TokenCleaner控制器,它在引导令牌过期时删除它们。
令牌的形式是[a-z0-9]{6}.[a-z0-9]{16}。第一个组件是令牌ID(用户ID),第二个组件是secret。在HTTP头中指定令牌,如下所示:
Authorization: Bearer 781292.db7bc3a58fc5f07e
781292就是用户ID
启用bootstrap token
您必须在API服务器上使用--enable-bootstrap-token-auth 标志启用引导令牌身份验证器。并且必须同时通过--controllers=, tokencleaner*参数启用TokenCleaner控制器。如果使用kubeadm引导集群,它将自动完成这一任务。
身份验证器将身份验证为system:bootstrap:<令牌ID>。它包含在system:bootstrappers组中。有意限制命名和组,以阻止用户在引导之后使用这些令牌。可以使用用户名和组(kubeadm也使用这些用户名和组)来制定适当的授权策略,以支持集群的引导。
有关引导令牌身份验证器和控制器的详细文档,以及如何使用kubeadm管理这些令牌,请参见引导令牌
Static Password File
启用命令
通过在api server 启动参数中添加--basic-auth-file=SOMEFILE 启用静态密码验证。如果修改静态密码文件,需要重启api server 才能生效。
静态密码文件说明
基本的静态密码是一个csv文件,至少有3列:密码、用户名、用户id。在Kubernetes 1.6或更高版本中,您可以指定一个可选的第4列,其中包含逗号分隔的组名。如果您有多个组,则必须将第四个列值括在双引号(")中。请看下面的例子:
password,user,uid,"group1,group2,group3"
静态密码使用
当使用http客户机的基本身份验证时,API服务器期望header basic 的值为 base64编码的用户名密码 (用户:PASSWORD)。
service account token
服务帐户(service account)是一个自动启用的身份验证器,它使用带签名的token来验证请求。这个插件有两个可选的标志:
--service-account-key-file包含PEM编码密钥的文件,用于对token进行签名。如果未指定,将使用API服务器的TLS私钥。
--service-account-lookup如果启用,从API中删除的令牌将被撤销。
服务帐户通常由API服务器自动创建,并通过ServiceAccount controller manager与集群中运行的pod相关联。token被挂载到已知位置的pods中,并允许集群内进程与API服务器通信。帐户可以使用PodSpec的serviceAccountName字段显式地与pod关联。
注意:serviceAccountName通常被省略,因为这是自动完成的。
kubectl create serviceaccount jenkins
serviceaccount "jenkins" created
kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
# ...
secrets:
- name: jenkins-token-1yvwg
# 创建的secret包含API服务器的公共CA和一个签名的JSON Web令牌(JWT)。
kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion: v1
data:
ca.crt: (APISERVER'S CA BASE64 ENCODED)
namespace: ZGVmYXVsdA==
token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
# ...
type: kubernetes.io/service-account-token
值是用base64编码的,因为secret总是用base64编码的。
服务帐户(service account)使用用户名system:serviceaccount:(namespace):(serviceaccount)进行身份验证,并分配给system:serviceaccounts和system:serviceaccounts:(namespace)两个用户组。
警告:由于服务帐户令牌存储在secret中,任何具有读访问这些机密的用户都可以验证为服务帐户。在授予服务帐户的权限和secret的读取功能时要谨慎。
下一篇
最好的K8S 安全机制介绍 2——授权概述
如果文章对您有帮助,请点一下下面的 "喜欢"