最好的K8S 安全机制介绍 1 ——认证部分

K8S 的用户系统

K8S 有两种类型的用户

  1. service account
  2. 一般用户(人)

一般用户

一般用户被认为是由外部独立的服务(比如公司的员工)管理的。例如:一个分发私钥的管理员,一个像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 认证步骤

  1. https 通信双方的服务器端, 想CA 机构申请证书. CA 机构下发根证书,服务端证书,私钥给申请者
  2. https 通信双方的客户端向CA机构申请证书, CA 机构下发根证书,服务端证书,私钥给申请者
  3. 客户端向服务端发起请求,服务端下发服务端证书给客户端,客户端接收到证书后, 通过私钥揭秘证书, 利用服务端证书中的公钥认证证书信息比较证书里的消息. 例如,比较域名和公钥, 与服务器刚发送的相关信息是否一致, 如果一致, 则认为服务端是可信的
  4. 客户端发送客户端证书给服务端,服务端通过私钥解密证书,获得客户端公钥,并用该公钥认证证书信息
  5. 客户端通过随机密钥加密信息发送给服务端. 服务端和客户端协商好加密方案后,客户端会产生一个随机的密钥,客户端通过协商好的加密方案加密该密钥,并发送该随机密钥给服务端. 服务器接收密钥后, 双方所有内容通过该随机密钥加密
最好的K8S 安全机制介绍 1 ——认证部分_第1张图片
image.png

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 的方式

主要步骤如下

  1. 生成自签名 CA 证书
  2. 为kube-apiserver 生成数字证书, 并用CA证书签名
  3. 为kube-apiserver 配置相关启动参数
  4. 为每个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——授权概述

如果文章对您有帮助,请点一下下面的 "喜欢"

你可能感兴趣的:(最好的K8S 安全机制介绍 1 ——认证部分)