美文网首页工作生活kubernetes
最好的K8S 安全机制介绍 1 ——认证部分

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

作者: 陈sir的知识图谱 | 来源:发表于2019-07-03 11:37 被阅读0次

    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或jane@example.com

    • UID:标识最终用户并试图比username更一致和惟一的字符串。

    • 组(group):一组字符串,它将用户与一组通常分组的用户相关联。

    • 额外字段(extra fileds):字符串映射到包含附加信息授权方可能会发现有用的字符串列表。

    所有值对身份验证系统都是不透明的,只有在由授权方( authorizer)使用时才具有意义。

    您可以同时启用多个身份验证方法。通常应该使用至少两种方法:

    • 服务帐户(service account) 的服务帐户令牌(service account token)

    • 一种用于用户身份验证的方法。

    当启用多个验证器模块时,第一个模块将成功地验证 "请求短路评估" (request short-circuits evaluation)。,如果验证失败,则进行断路操作,API服务器不保证运行验证器的执行顺序。

    所有通过验证的用户都会被添加进system:authenticated组。

    可以使用authenticating proxyauthentication 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. 客户端通过随机密钥加密信息发送给服务端. 服务端和客户端协商好加密方案后,客户端会产生一个随机的密钥,客户端通过协商好的加密方案加密该密钥,并发送该随机密钥给服务端. 服务器接收密钥后, 双方所有内容通过该随机密钥加密
    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 = <country>
    ST = <state>
    L = <city>
    O = <organization>
    OU = <organization unit>
    CN = <MASTER_IP>
    
    [ 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 = <MASTER_IP>
    # 一般为 api server --service-cluster-ip-range=10.96.0.0/12 参数的第一位ip,也就是10.96.
    IP.2 = <MASTER_CLUSTER_IP>
    
    [ 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": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    

    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",
        "<MASTER_IP>",
        "<MASTER_CLUSTER_IP>",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
      ],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [{
        "C": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    

    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 ——认证部分

        本文链接:https://www.haomeiwen.com/subject/pnhqhctx.html