• kubernetes安全机制


    kubernetes安全机制

    大概分为三个部分,其一Kubernetes安全框架,其二传输安全,认证。授权准入控制,其三使用RBAC授权,这算是一系列流程,了解一下每个环节都做了哪些操作。

    kubernetes安全框架

    当你使用kubectl||API||UI实际上就是操作apiserver上的资源,之前创建过Deployment,使用api版本为apps/v1,也就是这个,

    apiVersion: apps/v1
    kind: Deployment
    

    在你创建的时候apiserver会识别你请求的资源,也就是上面的那两个,如果无法识别直接报错,识别成功后会经历三个阶段,第一认证,第二授权,第三准入控制,当你发起一个请求需要过了这三步验证K8S才会为你创建资源,如果这三步有任意一步出现问题,那你看到的就是一个失败的结果。

    通常用户如果要安全访问集群Apiserver往往需要证书、token、或用户名加密码,token之前配置过,手动生成的一个token,而且指定了一个token文件,也就是这里。

    [root@k8s01 ~]# cat /opt/kubernetes/cfg/kube-apiserver.conf | grep token.csv
    --token-auth-file=/opt/kubernetes/cfg/token.csv \
    [root@k8s01 ~]# 
    

    这个token文件有一个值是随机生成的,这里就是使用token来认证的,指定了用户,把token对应的用户绑定相对应的权限,那么拿着个token值就有相对应的权限来访问apiserver了。

    [root@k8s01 ~]# kubectl get serviceaccounts 
    NAME                     SECRETS   AGE
    default                  1         7h2m
    nfs-client-provisioner   1         6h46m
    [root@k8s01 ~]# 
    

    可以通过serveraccountpod中去访问apiserver,说白了就是不同类型的来访问apiserver都会有不同的方式,apiserver在各组件之间起到了协调的作用,和集群访问入口的功能,你想访问集群资源就必须得经过Apiserver

    K8S安全控制框架主要是由以下三个阶段进行控制,

    • Authentication
    • Authorrization
    • AdmissionControl

    如图所示

    每一个阶段都支持插件方式,需要通过API Server配置来启用插件,之前都已经配置过了,现在看一下,例如准入控制

    [root@k8s01 ~]#  cat /opt/kubernetes/cfg/kube-apiserver.conf | grep -i Admission
    --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
    

    授权启用了RBAC

    [root@k8s01 ~]#  cat /opt/kubernetes/cfg/kube-apiserver.conf | grep -i Author
    --authorization-mode=RBAC,Node \
    

    Authentication

    也就是认证,在认证之前还有个传输,现在已经告别了8080,使用了6443,现在8080已经不对外提供服务了,对外提供服务的是64438080主要是本地master组件来连接使用。

    认证方面提供了三种客户端认证方式。

    • HTTPS证书认证:基于CA证书签名的数字证书认证
      • 之前部署K8S时我们生成了N多证书,通过证书内的CN字段就可以识别出您是谁。
    • HTTP TOKEN认证: 通过TOKEN来识别用户
      • 这个也用到了,就是在apiserver中配置的那个token文件,那个是做kubelet-bootstrap认证时候用到的,这个用的比较广泛
    • HTTP Base认证: 用户名加密码的方式认证
      • 这种用的就很少了,安全系数比较低。

    这是传输和认证层面,第一阶段验证你的身份,你可以理解为这是门禁,你通过工卡进行身份验证,验证通过之后你就能进入到某片区域了。

    Authorrization

    第二阶段,授权,第一阶段你身份验证通过了,然后进入到了某片区域,但是这片区域有很多房间,具体你能进入到哪个房间就得看你工卡的授权了,你有权限就可以刷开某个门,没权限你就是刷不开,所以这就涉及到授权了,一般用的就是RBAC,基于角色的访问控制,角色就是具体的访问权限的集合,他是负责完成授权工作的。

    他去判断你是否有权限去访问某些资源,他会检查以下属性,如图。

    在你请求的时候我绝对会携带我要访问哪个资源,下面他就开始检查你有没有权限去访问那个资源,如果没授权的话在这个阶段直接给你拒绝了,你看到的是没有权限访问,所以这就是授权这个阶段。

    AdmissionControl

    准入控制,前两步认证都过了就该这个了,他实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器检查,检查不通过,则拒绝请求,啥意思呢,大概是这样,我现在想通过apiserver限制pod资源,但是想限制pod资源需要用到apiserverLimitRanger插件,如果这个插件没启用直接拒绝请求,提示我不支持这个撒,现在这个插件启着呢,所以不会有这个问题,他的工作逻辑就是这样,下面主要看一下RBAC授权。

    RBAC授权

    也就是上文第二阶段的授权,它允许我们通过API Server来动态修改配置,实时生效,在开始之前先来了解一下RBAC的组成。

    RBAC核心概念

    • 角色(Role,ClusterRole)
      • Role:授权特定命名空间的访问权限,K8S逻辑隔离是使用namespaces实现的,它的授权是在命名空间层面的,你能不能访问某个命名空间
      • ClusterRole:此为集群层面的,针对所有的命名空间,
    • 主体(User,Group,ServiceAccount)
      • User: 用户
      • Group: 用户组
      • ServicAccount:服务账号
    • 角色绑定(RoleBinding,ClusterRoleBinding)
      • RoleBinding:将角色绑定到主体,既subject ,它对应Role,创建Role使用这个去绑定,绑定后才会有相对应的权限
      • ClusterRoleBinding: 将集群角色绑定到主体,它对应ClusterRole,创建ClusterRole使用这个去绑定,绑定后才会有相对应的权限

    RBAC授权普通用户访问命名空间

    现在授权一个用户对某个命名空间有读取的权限,说白了就是只读,让你看看就行了,现在随便创建一个命名空间,然后在这个命名空间里启动几个pod

    [root@k8s01 ~]# kubectl create namespace opesn
    namespace/opesn created
    [root@k8s01 ~]# kubectl get namespaces opesn 
    NAME    STATUS   AGE
    opesn   Active   8s
    [root@k8s01 ~]# kubectl run nginx --image=nginx --replicas=3 --namespace=opesn
    [root@k8s01 ~]# kubectl get pods -n opesn
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-6db489d4b7-9xg6b   1/1     Running   0          26s
    nginx-6db489d4b7-bfgwf   1/1     Running   0          26s
    nginx-6db489d4b7-s6hrn   1/1     Running   0          26s
    [root@k8s01 ~]# 
    

    现在新建一个用户opesn,他的权限为只读opesn命名空间,其他的全部拒绝,首先要创建一个Role角色,需要定义规则了,基于官方文档

    [root@k8s01 ~]# cat rbac-role.yaml
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      namespace: opesn
      name: opesn
    rules:
    - apiGroups: [""] # "" indicates the core API group
      resources: ["pods"]
      verbs: ["get", "watch", "list"]
    

    权限为get,watch,list,只读的,创建看一下

    [root@k8s01 ~]# kubectl apply -f rbac-role.yaml 
    role.rbac.authorization.k8s.io/opesn created
    [root@k8s01 ~]# kubectl get role -n opesn
    NAME    AGE
    opesn   12s
    [root@k8s01 ~]# 
    
    

    现在有一个角色了,现在把他绑定到这个角色里。

    [root@k8s01 ~]# cat rbac-rolebinding.yaml
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: read-pods
      namespace: opesn
    subjects:
    - kind: User
      name: opesn # Name is case sensitive
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role #this must be Role or ClusterRole
      name: opesn # this must match the name of the Role or ClusterRole you wish to bind to
      apiGroup: rbac.authorization.k8s.io
    [root@k8s01 ~]# 
    

    主要两块,命名空间,subjectskind指定为User,不是程序,用户名是opesn,在下面就是角色绑定了,指定了类型和名称,也就是上面创建的那个,这就可以了,创建吧。

    [root@k8s01 ~]# kubectl create -f rbac-rolebinding.yaml 
    rolebinding.rbac.authorization.k8s.io/read-pods created
    [root@k8s01 ~]# kubectl get role,rolebinding -n opesn
    NAME                                   AGE
    role.rbac.authorization.k8s.io/opesn   4m40s
    
    NAME                                              AGE
    rolebinding.rbac.authorization.k8s.io/read-pods   10s
    [root@k8s01 ~]# 
    

    现在是创建完了,现在还差识别身份,现在使用基于证书的来识别身份,直接上脚本吧。

    [root@k8s01 kubernetes]# cat rabc-user.sh
    cat > opesn-csr.json <<EOF
    {
      "CN": "opesn",
      "hosts": [],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [
        {
          "C": "CN",
          "L": "BeiJing",
          "ST": "BeiJing"
        }
      ]
    }
    EOF
    
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes opesn-csr.json | cfssljson -bare opesn
    
    kubectl config set-cluster kubernetes \
      --certificate-authority=ca.pem \
      --embed-certs=true \
      --server=https://192.168.10.4:6443 \
      --kubeconfig=opesn-kubeconfig
      
    kubectl config set-credentials opesn \
      --client-key=opesn-key.pem \
      --client-certificate=opesn.pem \
      --embed-certs=true \
      --kubeconfig=opesn-kubeconfig
    
    kubectl config set-context default \
      --cluster=kubernetes \
      --user=opesn \
      --kubeconfig=opesn-kubeconfig
    
    kubectl config use-context default --kubeconfig=opesn-kubeconfig
    

    opesn就是我之前定义的用户名,apiserver我写的是负载均衡地址,会用到apiserver的根证书,所以要复制过来,下面执行一下吧。

    [root@k8s01 kubernetes]# bash rabc-user.sh
    2020/06/07 23:14:29 [INFO] generate received request
    2020/06/07 23:14:29 [INFO] received CSR
    2020/06/07 23:14:29 [INFO] generating key: rsa-2048
    2020/06/07 23:14:29 [INFO] encoded CSR
    2020/06/07 23:14:29 [INFO] signed certificate with serial number 147728077879656546154832435011075986225633644035
    2020/06/07 23:14:29 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
    websites. For more information see the Baseline Requirements for the Issuance and Management
    of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
    specifically, section 10.2.3 ("Information Requirements").
    Cluster "kubernetes" set.
    User "opesn" set.
    Context "default" created.
    Switched to context "default".
    [root@k8s01 kubernetes]# 
    
    [root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get pod -n default
    Error from server (Forbidden): pods is forbidden: User "opesn" cannot list resource "pods" in API group "" in the namespace "default"
    [root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get pod -n opesn
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-6db489d4b7-9xg6b   1/1     Running   0          16m
    nginx-6db489d4b7-bfgwf   1/1     Running   0          16m
    nginx-6db489d4b7-s6hrn   1/1     Running   0          16m
    [root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get service
    Error from server (Forbidden): services is forbidden: User "opesn" cannot list resource "services" in API group "" in the namespace "default"
    [root@k8s01 kubernetes]# 
    
    

    只能看到opesn命名空间下的pod,什么service之类的都不行,因为没有授权,

    RBAC授权ServiceAccount访问命名空间

    创建一个WEBUI

    wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
    vi recommended.yaml
    …
    kind: Service
    apiVersion: v1
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
      name: kubernetes-dashboard
      namespace: kubernetes-dashboard
    spec:
      type: NodePort
      ports:
        - port: 443
          targetPort: 8443
          nodePort: 30001
      selector:
        k8s-app: kubernetes-dashboard
    …
    # kubectl apply -f recommended.yaml
    
    #创建service account并绑定默认cluster-admin管理员集群角色:
    cat dashboard-adminuser.yaml 
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: admin-user
      namespace: kubernetes-dashboard
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: admin-user
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - kind: ServiceAccount
      name: admin-user
      namespace: kubernetes-dashboard
    
    #启动
    apply -f dashboard-adminuser.yaml 
    
    #获取token
    kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
    
    访问地址:http://NodeIP:30001
    使用输出的token登录Dashboard。
    

    现在创建一个ServiceAccount,只允许访问opesn命名空间,权限和上面的一样,首先要创建一个ServiceAccount,然后把这个ServiceAccount绑定到上面创建的角色里。

    [root@k8s01 ~]# cat sa.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: pod-reader
      namespace: opesn
    
    ---
    
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: sa-read-pods
      namespace: opesn 
    subjects:
    - kind: ServiceAccount
      name: pod-reader
    roleRef:
      kind: Role
      name: opesn
      apiGroup: rbac.authorization.k8s.io
    [root@k8s01 ~]# 
    

    就是这样,然后创建

    [root@k8s01 ~]# kubectl create -f sa.yaml 
    serviceaccount/pod-reader created
    rolebinding.rbac.authorization.k8s.io/sa-read-pods created
    [root@k8s01 ~]# kubectl get secrets -n opesn pod-reader-token-fv9qg 
    NAME                     TYPE                                  DATA   AGE
    pod-reader-token-fv9qg   kubernetes.io/service-account-token   3      38s
    [root@k8s01 ~]# kubectl describe secrets -n opesn pod-reader-token-fv9qg 
    Name:         pod-reader-token-fv9qg
    Namespace:    opesn
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: pod-reader
                  kubernetes.io/service-account.uid: 009f347c-be63-40cf-97c2-b4631f5e5b4c
    
    Type:  kubernetes.io/service-account-token
    
    Data
    ====
    ca.crt:     1359 bytes
    namespace:  5 bytes
    token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IlNqcHV5S0V5dnZEWDJtck9TSGdZYkppb0V5SFdyOXpVUnd5b3NHX1Zmd00ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVzbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwb2QtcmVhZGVyLXRva2VuLWZ2OXFnIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InBvZC1yZWFkZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIwMDlmMzQ3Yy1iZTYzLTQwY2YtOTdjMi1iNDYzMWY1ZTViNGMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6b3Blc246cG9kLXJlYWRlciJ9.j8ZryrAGx4c2VAiW2ZR_McJCDSUDYKXpDf5hwkLxOzYAt5_gIzvJCWE3htCd3IGiALanK88iDCid3nwRzyNPXSEcMtTGeLtAdIJ9ZwtFfxZVTNuHhW0p4C1Gw-9PWTNvbZiLQv4IUKzJRlSvfn121lo7OSG5WdovmCkmGug_c8es4FJvOHPVtQBXvOTWihlvwZMO6NRLQ9mTtBaqbpXseBUUjfENk7tuRs-LsS31bqlmCH2DkcPGlLArpMBp0bnjtAH0OAfYJbfErTfeXyNjHDVSx1tOJV7yly4nvKwe5_PFYlKBKZ-FDMT6T0qTmitDvYjB6cml9AdzgukJjHJ9AQ
    

    下面去用这个token登陆一下UI

    命名空间需要你手动输入了,然后会发现各种权限不足,就是这种效果,只读opesn命名空间,其他的全部权限不足,这就是RBAC授权

  • 相关阅读:
    五种常见的 PHP 设计模式
    转载:php header下载乱码 空格 问题
    PHP程序员最常犯的11个MySQL错误
    启迪人心:10个的有关编程的至理名言
    如何使用搜索技巧来成为一名高效的程序员
    随机验证码
    产生sql表中表示字段, 实现自增列
    在当前页面弹出对话框
    读取页面传入的URL值
    Sql临时表
  • 原文地址:https://www.cnblogs.com/helloord/p/13211976.html
Copyright © 2020-2023  润新知