k8s阶段06 k8s认证体系和插件, 添加用户账号认证, kubeconfig使用, serviceaccount, 鉴权体系及RBAC, CNI及pod网络基础, kuboard

1 Kubernetes的访问控制体系

认证:
    API Server:
        https://control_host:6443/ #集群外部访问控制平面节点ip+6443
        https://kubernetes.default.svc.cluster.local #集群内部访问

    集群网关:API Server #执行安全策略:认证,鉴权,准入控制(其他地方很少用到)
        内置了三重功能:认证、鉴权、准入控制
            认证:身份识别
            鉴权:
            准入控制:仅同“写”请求相关,负责实现“校验(validating)”和“修订或补全(mutating)”

        模块化:并允许同时启用多个
            认证插件:可同时存在多个
            鉴权插件:
            准入控制插件:

API Server内置的访问控制机制

API Server内置了一个有着三级别的访问控制机制
  ◼ 认证:核验请求者身份的合法性
  ◼ 授权:核验请求的操作是否获得许可
  ◼ 准入控制:检查操作内容是否合规

插件化机制,每种访问控制机制均有一组专用的插件栈
  ◼ 认证:身份核验过程遵循“或”逻辑,且任何一个插件核验成功后都将不再进行后续的插件验证
    ◆均不成功,则失败,或以“匿名者”身份访问
    ◆建议禁用“匿名者”
  ◼ 授权:鉴权过程遵循“或”逻辑,且任何一个插件对操作的许可授权后都将不再进行后续的插件验证
    ◆均未许可,则拒绝请求的操作
  ◼ 准入控制:内容合规性检查过程遵循“与”逻辑,且无论成败,每次的操作请求都要经由所有插件的检验
    ◆将数据写入etcd前,负责检查内容的有效性,因此仅对“写”操作有效
    ◆分两类:validating(校验)和 mutating(补全或订正)

2 API身份验证

Kubernetes上的用户

“用户”即服务请求者的身份指代,一般使用身份标识符进行识别
  ◼ 用户标识:用户名或者ID
  ◼ 用户组
 Kubernetes系统的用户大体可分为 2 类
  ◼ Service Account:服务账户,指Pod内的进程访问API Server时使用的身份信息
    ◆API Server使用ServiceAccount类型的资源对象来保存该类账号
    ◆认证到API Server的认证信息称为Service Account Token,它们保存于同名的专用类型的Secret对象中
    ◆名称空间级别
  ◼ User Account:用户账户,指非Pod类的客户端访问API Server时使用的身份标识,一般是现实中的“人”
    ◆ API Server没有为这类账户提供保存其信息的资源类型,相关的信息通常保存于外部的文件或认证系统中
    ◆身份核验操作可由API Server进行,也可能是由外部身份认证服务完成
    ◆本身非由Kubernetes管理,因而作用域为整个集群级别
不能被识别为Service Account,也不能被识别为User Account的用户,即“匿名用户”

#每一个名称空间下都有一个default用户(给创建pod但没指明pod身份,都用default身份,支持至少downward api作用能力)
[root@master01 ~]#kubectl get serviceaccount
NAME      SECRETS   AGE
default   0         17d
#dafault是最小权限,只有获取当前pod自身之上的名称空间,节点等信息的权限

[root@master01 ~]#kubectl create deployment demoapp --image=ikubernetes/demoapp:v1.0 --replicas=3
#查看,可以看到pod对应的serviceAccount
[root@master01 ~]#kubectl get pods demoapp-8699b9895b-bljbb -o yaml
...
serviceAccount: default #已经被废弃了
serviceAccountName: default

身份认证策略

X.509客户端证书认证
持有者令牌(bearer token)
  ◼ 静态令牌文件(Static Token File)
  ◼ Bootstrap令牌
  ◼ Service Account令牌
  ◼ OIDC(OpenID Connect)令牌 #很少用(如果用公有云,都已经配置好了)
  ◼ Webhook令牌
身份认证代理(Authenticating Proxy)#很少用
匿名请求

  API Server启用的身份认证机制

基于认证插件支持多种认证方式,而相应认证插件的启用需要经由kube-apiserver上的专用选项完成
kubeadm v1.22 部署的集群默认启用的认证机制如下图红框中的选项,它们依次是
◼ X509客户端证书认证
◼ Bootstrap令牌认证
◼ 身份认证代理
◼ Service Account认证
注意:API Server并不保证各认证插件的生效次序与定义的次序相同

  kubelet启用的身份认证机制

#api server和kubelet互为客户端,服务端
kubelet的REST API端点默认通过TCP协议的10250端口提供,支持管理操作
  Kubelet API 功能简介
  /pods 列出当前kubelet节点上的Pod
  /run 在一个容器内运行指定的命令
  /exec 在一个容器内运行指定的命令
  /configz 设置Kubelet的配置文件参数
  /debug 调试信息

需要对客户端身份进行认证
  ◼ 启用的身份认证
    ◆webhook
    ◆x509客户端证书认证
    ◆注意:建议显式禁用匿名用户
  ◼ API Server是该API端点的客户端,因此,kubelet需要在验证客户端身份时信任给API Server颁发数字证书的CA

3 认证功能测试

静态令牌认证(一般只是简单测试,了解令牌认证原理,很少用来做真正的令牌认证使用)

静态令牌认证的基础配置
  ◼ 令牌信息保存于文本文件中
    ◆文件格式为CSV,每行定义一个用户,由“令牌、用户名、用户ID和所属的用户组”四个字段组成,用户组为可选字段
    ◆格式:token,user,uid,"group1,group2,group3" #组如果单个可以不加引号
  ◼ 由kube-apiserver在启动时通过--token-auth-file选项加载
  ◼ 加载完成后的文件变动,仅能通过重启程序进行重载,因此,相关的令牌会长期有效
  ◼ 客户端在HTTP请求中,通过“Authorization Bearer TOKEN”标头附带令牌信息以完成认证
配置示例
  ① 生成token,命令:echo "$(openssl rand -hex 3).$(openssl rand -hex 8)" #一般是这么生成
  ② 生成static token文件
  ③ 配置kube-apiserver加载该静态令牌文件以启用相应的认证功能
  ④ 测试,命令:curl -k -H "Authorization: Bearer TOKEN" -k 
  https://API_SERVER:6443/api/v1/namespaces/default/pods/
  
#示例:(这种方式仅仅用来做测试)
#生成token,分别执行3次
]#echo "$(openssl rand -hex 3).$(openssl rand -hex 8)"
f56cac.a4374aa9ad9a3618
442dc3.7301e1bcd991ea25
3967cd.cbe6373ffba2aac0

[root@master01 ~]#cd /etc/kubernetes/
[root@master01 kubernetes]#mkdir authfiles
[root@master01 kubernetes]#cd authfiles/
[root@master01 authfiles]#vim tokens.csv
f56cac.a4374aa9ad9a3618,tom,10001,kubeusers
442dc3.7301e1bcd991ea25,jerry,10002,kubeusers
3967cd.cbe6373ffba2aac0,trump,20001,kubeadmins
#kubeadm部署下,api-server是静态pod,启动加载下方路径文件(会监视该路径,任何yaml文件变动都会重建该pod)
]#cd /etc/kubernetes/manifests/
[root@master01 manifests]#ls
etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

#把kube-apiserver.yaml复制出去,修改,不让api-server重启比较好
[root@master01 manifests]#cp kube-apiserver.yaml /root/kube-apiserver.yaml.org
[root@master01 manifests]#cd
#拷贝一份,以防改错
[root@master01 ~]#cp kube-apiserver.yaml.org kube-apiserver.yaml
[root@master01 ~]#vim kube-apiserver.yaml
...
spec:
  containers:
  - command:
  - --token-auth-file=/etc/kubernetes/authfiles/tokens.csv #追加
  ...
    volumeMounts:
    - mountPath: /etc/kubernetes/authfiles/tokens.csv #容器内挂载点
      name: static-token-file
      readOnly: true
  ...
  volumes:
  ...
  - hostPath:
      path: /etc/kubernetes/authfiles/tokens.csv #这里把宿主机整个目录挂载也可以
      type: File #如果上面填文件夹,这里写DirectoryOrCreate
    name: static-token-file
status: {}

[root@master01 ~]#cp kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml
#kubelet会发现文件变了,会重载该文件并重建pod

#可以查看pods
[root@master01 ~]#crictl pods
#或者用该命令查看(可以看到kube-apiserver-master01被重启了)
[root@master01 ~]#kubectl get pods -n kube-system

#测试
#模拟集群外部通过token连接,也可以在windows或其他机器下载k8s客户端通过验证连接
# 跳过服务端证书(tls)校验,insecure-skip-tls-verify跳过tls验证
[root@node01 ~]#kubectl --server=https://10.0.0.151:6443 --token="f56cac.a4374aa9ad9a3618" --insecure-skip-tls-verify=true get pods
Error from server (Forbidden): pods is forbidden: User "tom" cannot list resource "pods" in API group "" in the namespace "default"
#返回说明已经识别出10001,只是因为没有给tom权限,所有无法查看pod
#每个工作节点下也有ca证书
[root@node01 ~]#ls /etc/kubernetes/pki
ca.crt

#正常检验服务端证书,通过ca证书连接
[root@node01 ~]#kubectl --server=https://10.0.0.151:6443 --token="f56cac.a4374aa9ad9a3618" --certificate-authority=/etc/kubernetes/pki/ca.crt get pods

#也可以直接通过curl命令验证(认证成功了,就是没有权限)
[root@node01 ~]#curl -k -H "Authorization Bearer f56cac.a4374aa9ad9a3618" https://10.0.0.151:6443
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}

X509 数字证书认证

X509客户端认证依赖于PKI证书体系,kubeadm部署Kubernetes集群时会自动生成所需要的证书,它们位于/etc/kubernetes/pki目录下
依赖到的PKI体系
  ◼ 如下图
  ◼ 另外,对Service Account的token进行签名还需要用到一个可选的密钥对儿
  
#重点关注api server的ca,也就是api server节点上的ca

#apiserver支持开启自动签署的功能,kubeadm部署默认开启。每次节点join到apiserver,自动发签署请求到apiserver,apiserver立即给节点签署
#每个节点收到证书以后,都会放在如下目录下
[root@node01 kubelet]#cd /var/lib/kubelet/pki/
[root@node01 pki]#ls
kubelet-client-2024-11-16-04-26-26.pem  kubelet-client-current.pem  kubelet.crt  kubelet.key

  X509证书客户端认证测试

X509数字证书认证到API Server的测试,步骤
  ① 创建证书签署请求
  ② 由Kubernetes CA签署证书
  ③ 用户使用证书认证到API Server
创建由Kubernetes CA签署的证书
  ◼ 创建证书签署请求
    ① openssl genrsa -out mason.key 2048 # 生成私钥
    #生成证书签署请求
    ② openssl req -new -key myuser.key -out mason.csr -subj "/CN=mason/O=developers"
  ◼ 创建CertificateSignRequest资源
    ◆kubectl apply -f certificatesignrequest-mason.yaml
    ◆kubectl get csr
  ◼ 签署证书(方式一)
    ◆kubectl certificate approve mason
  ◼ 获取证书,保存为证书文件
    ◆kubectl get csr mason -o jsonpath='{.status.certificate}'| \
      base64 -d > mason.crt 
创建由Kubernetes CA签署的证书(续)
  ◼ 签署证书(方式二),直接基于Kubernetes CA签署并生成证书文件
    ◆openssl x509 -req -days 10 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in ./mason.csr -out ./mason.crt
认证测试
  ◼ 将mason.crt、mason.key和ca.crt复制到某部署了kubectl的主机上,即可进行测试
    ◆这里以k8s-node01为示例;只需要复制mason.crt和mason.key即可,因为集群工作节点上已经有cr.crt文件
    ◆命令:scp -rp ./{mason.crt,mason.key} k8s-node01:/root/
  ◼ 在k8s-node01上发起访问测试
    ◆使用kubectl测试:kubectl get pods --client-certificate=/root/mason.crt --client-key=/root/mason.key --server=https://kubeapi.magedu.com:6443/ --certificate-authority=/etc/kubernetes/pki/ca.crt
    ◆也可以使用curl命令进行测试


#CertificateSignRequest资源示例
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: mason
spec:
  # request字段的值,是csr文件内容经base64编码后的结果
  # 用于生成编码的命令:cat mason.csr | base64 | tr -d "\n"
  request: …
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 864000 # ten days 证书过期时间
  usages: #可用于哪种认证
  - client auth #客户端认证


#数字证书认证测试:(方式一)
#生成秘钥
[root@master01 certificate-sign-request-demo]#openssl genrsa -out mason.key 2048
#创建证书签署请求csr   CN:用户名    O:组
]#openssl req -new -key mason.key -out mason.csr -subj "/CN=mason/O=kubeusers"
#读出mason.csr内容,base64编码,去除换行符,写入yaml中的spec.request中
[root@master01 certificate-sign-request-demo]#cat mason.csr |base64|tr -d '\n'
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2FUQ0NBVkVDQVFBd0pERU9NQXdHQTFVRUF3d0ZiV0Z6YjI0eEVqQVFCZ05WQkFvTUNXdDFZbVYxYzJWeQpjekNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMdGxwVVpkK0tvSXVtZ1RBaWpGCjh2ckJ2TkpuMVhIS2EwS3VLdlUvWUs3RTQ2cXJmRm05SW5GQ0dyT3VhRWt4Wmwwd3VvMitqNU91N2VxWmxuMUIKdSsreXZWSjd3bU1uZ3hmYkJPUlpabWp0d2ZMcTE2WmtQcEs2V1BIeFhjZ2tSU0pidXgyTCtTdDlja1Z2dGF6ZApVODR2NXc3SUg4RkVtNnd2L3JlN2JsQW1YL0RxaG55RkRvd1dxSUJFMlB5TWtaSjlCV3Y5Q2FQODdYV3h4K0ljCmdiZ1hJbzR1RmdlL3Z2cmc4VnVuQXBSUWZtWVk0RURZQkw4NDFjNlc0OWdIMHR1OGw0U3Q4S1dYRWs4NlZmNmQKRmJVcmFETWI2YUE0YU05WEJTNjUzdUZYNE5yQndnQjRXTFFDY29weUZybEQzZjNmY3UzQXgveWVWMW9ncmp6bAprZHNDQXdFQUFhQUFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUEwY2EwWjZYZFoyQ0Q1a0FmSlRxWjVsWHBLCnU1cTNpMndsTmJ1ZVoxbjBQdmIyQU5TNnlUOE1EL3ZZNG8zL0UrTVI3TGRLZ283ZFd3cTJUSkNjenl5UVFRYUoKa1U2aTZKVG1nTEFFQnEvcndQZnJWeXQra3Rja24yeGtrZHRpdTJnOFBSbTRmNnZQYlhYWVRTVm5WWTlxSU8zRQpxajkrNWtFTElUajhrM0Z5d2RPdmRIZ3UwazNwYWZWQjNQTC9rM2RGaU1VOTVLR1lZUHg2Nkd6a3NPYXVCTkVjCjQ0ZkJVMmRyQUJsQ2YvSjJFSXVZQSthTnZrdFIra0tra1pFd3lqRml0TUdyamhJenloUmFaR3NFdERVZjh0d2kKY1BNUUJ3ZkZvUWE3R3FqU04yVDU2UHJaTERiejJqNCt4NU9leC9vWUNJVlpBMkpqY1BoVklESFh0TGdYCi0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=

[root@master01 certificate-sign-request-demo]#vim certificatesignrequest-mason.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: mason
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2FUQ0NBVkVDQVFBd0pERU9NQXdHQTFVRUF3d0ZiV0Z6YjI0eEVqQVFCZ05WQkFvTUNXdDFZbVYxYzJWeQpjekNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMdGxwVVpkK0tvSXVtZ1RBaWpGCjh2ckJ2TkpuMVhIS2EwS3VLdlUvWUs3RTQ2cXJmRm05SW5GQ0dyT3VhRWt4Wmwwd3VvMitqNU91N2VxWmxuMUIKdSsreXZWSjd3bU1uZ3hmYkJPUlpabWp0d2ZMcTE2WmtQcEs2V1BIeFhjZ2tSU0pidXgyTCtTdDlja1Z2dGF6ZApVODR2NXc3SUg4RkVtNnd2L3JlN2JsQW1YL0RxaG55RkRvd1dxSUJFMlB5TWtaSjlCV3Y5Q2FQODdYV3h4K0ljCmdiZ1hJbzR1RmdlL3Z2cmc4VnVuQXBSUWZtWVk0RURZQkw4NDFjNlc0OWdIMHR1OGw0U3Q4S1dYRWs4NlZmNmQKRmJVcmFETWI2YUE0YU05WEJTNjUzdUZYNE5yQndnQjRXTFFDY29weUZybEQzZjNmY3UzQXgveWVWMW9ncmp6bAprZHNDQXdFQUFhQUFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUEwY2EwWjZYZFoyQ0Q1a0FmSlRxWjVsWHBLCnU1cTNpMndsTmJ1ZVoxbjBQdmIyQU5TNnlUOE1EL3ZZNG8zL0UrTVI3TGRLZ283ZFd3cTJUSkNjenl5UVFRYUoKa1U2aTZKVG1nTEFFQnEvcndQZnJWeXQra3Rja24yeGtrZHRpdTJnOFBSbTRmNnZQYlhYWVRTVm5WWTlxSU8zRQpxajkrNWtFTElUajhrM0Z5d2RPdmRIZ3UwazNwYWZWQjNQTC9rM2RGaU1VOTVLR1lZUHg2Nkd6a3NPYXVCTkVjCjQ0ZkJVMmRyQUJsQ2YvSjJFSXVZQSthTnZrdFIra0tra1pFd3lqRml0TUdyamhJenloUmFaR3NFdERVZjh0d2kKY1BNUUJ3ZkZvUWE3R3FqU04yVDU2UHJaTERiejJqNCt4NU9leC9vWUNJVlpBMkpqY1BoVklESFh0TGdYCi0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
  signerName: kubernetes.io/kube-apiserver-client #交给kube-apiserver签署,且给客户端签署
  expirationSeconds: 864000  # ten days
  usages:
  - client auth
  
[root@master01 certificate-sign-request-demo]#kubectl apply -f certificatesignrequest-mason.yaml
#查看csr,等待签署
[root@master01 certificate-sign-request-demo]#kubectl get csr
NAME    AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
mason   31s   kubernetes.io/kube-apiserver-client   kubernetes-admin   10d                 Pending
#手动进行签署
[root@master01 certificate-sign-request-demo]#kubectl certificate approve mason
#查看csr,变为已签署
[root@master01 certificate-sign-request-demo]#kubectl get csr
NAME    AGE     SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
mason   4m54s   kubernetes.io/kube-apiserver-client   kubernetes-admin   10d                 Approved,Issued

#证书还不能用,需要下载到本地才能用
#查看证书,证书在status.certificate中,把这一段取出来保存成证书
]#kubectl get csr mason -o yaml
#取出来后base64直接解码
]#kubectl get csr mason -o jsonpath={.status.certificate}| base64 -d
-----BEGIN CERTIFICATE-----
MIIDCjCCAfKgAwIBAgIRALiwpij3plU3j73z0LI8xGowDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yNDEyMDQxMTE4MzdaFw0yNDEyMTQx
MTE4MzdaMCQxEjAQBgNVBAoTCWt1YmV1c2VyczEOMAwGA1UEAxMFbWFzb24wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7ZaVGXfiqCLpoEwIoxfL6wbzS
Z9VxymtCrir1P2CuxOOqq3xZvSJxQhqzrmhJMWZdMLqNvo+Tru3qmZZ9Qbvvsr1S
e8JjJ4MX2wTkWWZo7cHy6temZD6Suljx8V3IJEUiW7sdi/krfXJFb7Ws3VPOL+cO
yB/BRJusL/63u25QJl/w6oZ8hQ6MFqiARNj8jJGSfQVr/Qmj/O11scfiHIG4FyKO
LhYHv7764PFbpwKUUH5mGOBA2AS/ONXOluPYB9LbvJeErfCllxJPOlX+nRW1K2gz
G+mgOGjPVwUuud7hV+DawcIAeFi0AnKKcha5Q93933LtwMf8nldaIK485ZHbAgMB
AAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0j
BBgwFoAU+l0zAcbVsOWsFvnVhlAAQ2Wpsb0wDQYJKoZIhvcNAQELBQADggEBAH0O
qYP4LQR4V4h76C20QbVBCeZasgrWkVDNDLnPrCCk27VHHfQInVXt2cTC0YefIEYY
H4LufQZlWCG+ujNAqRj9Jf/3lE7oILtFIyoMYGn7riGcHMfRjEqamCcyRw9ZYOLn
mDCe8z79l3m9mYJ6F10k8jesRsJKzbzeiy0Jlvn4BnsDZvnLVeEHEYF9EAsT0SE0
q2pRerc2DDvDvjkUQC4leH0z1ZbIxqC0BKxbD7bAE0JlZLN95zf4S5C/+PSrKXqN
MHZZt9hTuVI8GQ6bDxnDeyIH4lRADnQR+o75c4lBfgjP5Flxb6etcgA4PpyWT9WZ
dwHKbA4sE90wHXLfQSw=
-----END CERTIFICATE-----
#保存起来
]#kubectl get csr mason -o jsonpath={.status.certificate}| base64 -d > mason.crt
[root@master01 certificate-sign-request-demo]#ls
certificatesignrequest-mason.yaml  mason.crt  mason.csr  mason.key  README.md

#客户端用该证书mason.crt访问测试
#把mason.crt,mason.key拷贝到客户端上
[root@master01 certificate-sign-request-demo]#scp mason.crt root@10.0.0.152:/tmp/
[root@master01 certificate-sign-request-demo]#scp mason.key root@10.0.0.152:/tmp/
#测试,跳过tls验证。识别出mason用户名了
[root@node01 tmp]#kubectl --server=https://10.0.0.151:6443 --client-key=./mason.key --client-certificate=./mason.crt --insecure-skip-tls-verify=true get pods
Error from server (Forbidden): pods is forbidden: User "mason" cannot list resource "pods" in API group "" in the namespace "default"


#数字证书认证测试2:(方式二)
#如果能进入apiserver主节点,且为超级管理员。可直接手动签证书(没法回收),发给客户端,就不用上面这么麻烦了
[root@master01 ~]#cd /etc/kubernetes/pki/
apiserver.crt              apiserver-kubelet-client.crt  etcd                    front-proxy-client.key
apiserver-etcd-client.crt  apiserver-kubelet-client.key  front-proxy-ca.crt      sa.key
apiserver-etcd-client.key  ca.crt                        front-proxy-ca.key      sa.pub
apiserver.key              ca.key                        front-proxy-client.crt
[root@master01 pki]#openssl genrsa -out miller.key 2048
#生成证书签署请求
[root@master01 pki]#openssl req -new -key ./miller.key -out ./miller.csr -subj "/CN=miller/O=kubeadmins"
#直接基于Kubernetes CA签署并生成证书文件(CAcreateserial:生成签署序列号 in:读进 out输出)
]#openssl x509 -req -days 10 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in ./miller.csr -out ./miller.crt
Certificate request self-signature ok
subject=CN = miller, O = kubeadmins

#客户端用该证书访问测试
#miller.crt,miller.key拷贝到客户端上
[root@master01 certificate-sign-request-demo]#scp miller.crt miller.key root@10.0.0.152:/tmp/
#测试,跳过tls验证。识别出miller用户名了
[root@node01 tmp]#kubectl --server=https://10.0.0.151:6443 --client-key=./miller.key --client-certificate=./miller.crt --insecure-skip-tls-verify=true get pods
Error from server (Forbidden): pods is forbidden: User "miller" cannot list resource "pods" in API group "" in the namespace "default"

 

4 Kubeconfig

kubeconfig基础

kubeconfig是YAML格式的文件,用于存储身份认证信息,以便于客户端加载并认证到API Server
  ◼ kubeconfig保存有认证到一至多个Kubernetes集群的相关配置信息,并允许管理员按需在各配置间灵活切换
    ◆clusters:Kubernetes集群访问端点(API Server)列表
    ◆users:认证到API Server的身份凭据列表
    ◆contexts:将每一个user同可认证到的cluster建立关联的上下文列表
    ◆current-context:当前默认使用的context
客户端程序加载的kubeconfig文件的途径及次序
  ◼ --kubeconfig选项
  ◼ KUBECONFIG环境变量:其值是包含有kubeconfig文件的列表
  ◼ 默认路径:$HOME/.kube/config

  设定kubeconfig命令

命令:kubectl config SUBCOMMAND [options]
  ◼ 打印加载的kubeconfig
    ◆view
  ◼ cluster相关的子命令
    ◆get-clusters
    ◆set-cluster
    ◆delete-cluster
  ◼ user相关的子命令
    ◆get-users
    ◆set-credentials #用户添加凭据
    ◆delete-user
  ◼ context相关的子命令
    ◆ get-contexts
    ◆ set-context
    ◆ delete-context
    ◆ rename-context
  ◼ current-context相关的子命令
    ◆ current-context
    ◆ use-context
    
#查看加载的kubeconfig
[root@master01 ~]#kubectl config view
apiVersion: v1
clusters:
- cluster: #有几个集群
    certificate-authority-data: DATA+OMITTED #该server签署的证书信息(隐藏)
    server: https://kubeapi.magedu.com:6443 #server地址
  name: kubernetes
contexts:
- context:
    cluster: kubernetes #访问哪个集群
    user: kubernetes-admin #以哪个身份
  name: kubernetes-admin@kubernetes #定义个名字
current-context: kubernetes-admin@kubernetes #当前默认使用的context是谁
kind: Config
preferences: {}
users: #用户账号
- name: kubernetes-admin
  user:
    client-certificate-data: DATA+OMITTED #客户端证书(隐藏)
    client-key-data: DATA+OMITTED #客户端私钥(隐藏)

#打印原始格式信息,显示上面的隐藏信息(私钥不要泄露)
[root@master01 ~]#kubectl config view --raw
#可以直接查看kubeconfig文件,看到的信息也是未加密的
[root@master01 pki]#cat /root/.kube/config

设定kubeconfig示例

示例1:为静态令牌认证的用户设定一个自定义的kubeconfig文件
  ① 定义Cluster
    ◆提供包括集群名称、API Server URL和信任的CA的证书相关的配置;clusters配置段中的各列表项名称需要惟一;
    ◆命令:
#集群名字kube-test;kubeconfig指明保存在哪个kubeconfig文件中;embed-certs:true为后面的crt内容存入kubeconfig中,fales为不存,每次去路径下加载(建议true,以免文件依赖)
kubectl config set-cluster kube-test --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://kubeapi.magedu.com:6443" --kubeconfig=$HOME/.kube/kubeusers.conf
  ② 定义User
    ◆添加身份凭据,使用静态令牌文件认证的客户端提供令牌令牌即可
    ◆命令:kubectl config set-credentials jerry --token="$JERRY_TOKEN" --kubeconfig=$HOME/.kube/kubeusers.conf
  ③ 定义Context
    ◆为用户jerry的身份凭据与kube-test集群建立映射关系
    ◆命令:kubectl config set-context jerry@kube-test --cluster=kube-test --user=jerry --kubeconfig=$HOME/.kube/kubeusers.conf
  ④ 设定Current-Context
    ◆命令: kubectl config use-context jerry@kube-test --kubeconfig=$HOME/.kube/kubeusers.conf


#实际操作示例
#添加集群mykube;kubeconfig指明保存在哪个kubeconfig文件中;embed-certs:true为后面的crt内容存入kubeconfig中,fales为不存,每次去路径下加载(建议true,以免文件依赖)
[root@master01 ~]#kubectl config set-cluster mykube --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://10.0.0.151:6443" --kubeconfig=./kubeusers.conf
#查看生成的kubeconfig
[root@master01 ~]#kubectl config view --kubeconfig=./kubeusers.conf
#只看集群信息
[root@master01 ~]#kubectl config get-clusters --kubeconfig=./kubeusers.conf
NAME
mykube

#添加用户账号
#添加前面令牌认证的用户tom (kubeconfig指定添加到哪个文件里,不指就是默认文件)
kubectl config set-credentials tom --token="f56cac.a4374aa9ad9a3618" --kubeconfig=./kubeusers.conf
#只显示用户
[root@master01 ~]#kubectl config get-users --kubeconfig=./kubeusers.conf
NAME
tom

#添加context,名称一般为用户名@集群名
[root@master01 ~]#kubectl config set-context tom@mykube --cluster=mykube --user=tom --kubeconfig=./kubeusers.conf
#查看生成的kubeconfig
[root@master01 ~]#kubectl config view --kubeconfig=./kubeusers.conf
#到此为止,认证凭据就完成了,只是每次要指明用哪个kubeconfig

#测试,选择kubeconfig,指定context
[root@master01 ~]#kubectl get pods --kubeconfig=./kubeusers.conf --context='tom@mykube'
Error from server (Forbidden): pods is forbidden: User "tom.10001" cannot list resource "pods" in API group "" in the namespace "default"

#设定指定kubeconfig使用的默认context,这样就不用每次指定了
[root@master01 ~]#kubectl config use-context 'tom@mykube' --kubeconfig=./kubeusers.conf

#测试,选择kubeconfig
[root@master01 ~]#kubectl get pods --kubeconfig=./kubeusers.conf

#把kubeusers.conf设置为环境变量,免得每次都要加载
[root@master01 ~]#export KUBECONFIG="/root/kubeusers.conf"
[root@master01 ~]#kubectl get pods
Error from server (Forbidden): pods is forbidden: User "tom.10001" cannot list resource "pods" in API group "" in the namespace "default"
#使用默认kubeconfig,就得加参数了
[root@master01 ~]#kubectl get pods --kubeconfig=/etc/kubernetes/admin.conf 
#撤销该变量,以免管理员账户用不了
[root@master01 ~]#unset KUBECONFIG


#添加用户账号jerry(前面令牌认证)
[root@master01 ~]#kubectl config set-credentials jerry --token="442dc3.7301e1bcd991ea25" --kubeconfig=./kubeusers.conf
#让jerry也能访问集群
[root@master01 ~]#kubectl config set-context jerry@mykube --cluster=mykube --user=jerry --kubeconfig=./kubeusers.conf

#添加X509证书验证用户mason
[root@master01 ~]#cd learning-k8s-master/examples/authn_and_authz/certificate-sign-request-demo/
]#kubectl config set-credentials mason --client-certificate=./mason.crt --client-key=./mason.key --embed-certs=true --kubeconfig=/root/kubeusers.conf
#让mason也能访问集群
[root@master01 ~]#kubectl config set-context mason@mykube --cluster=mykube --user=mason --kubeconfig=/root/kubeusers.conf
#查看
]#kubectl config view --kubeconfig=/root/kubeusers.conf
#测试,选择kubeconfig,指定context
[root@master01 ~]#kubectl get pods --kubeconfig=/root/kubeusers.conf --context='mason@mykube'

#使用多个kubeconfig,需要通过指定环境变量来实现(优先级自左而右,名称如果相同,采用左面的,默认context一样逻辑)
[root@master01 ~]#export KUBECONFIG="/root/kubeusers.conf:/etc/kubernetes/admin.conf"
#修改默认context
]#kubectl config use-context 'kubernetes-admin@kubernetes'

 

5 Service Account

Service Account基础

为何需要Service Account?
  ◼ Kubernetes原生应用(kubernetes-native)托管运行于Kubernetes之上,通常需要直接与API Server进行交互以获
取必要的信息
  ◼ API Server同样需要对这类来自于Pod资源中客户端程序进行身份验证,Service Account也就是设计专用于这类场
景的账号
  ◼ ServiceAccount是API Server支持的标准资源类型之一

在Pod上使用Service Account
  ◼ 自动设定:Service Account通常由API Server自动创建并通过 ServiceAccount准入控制器自动关联到集群中创建的每个Pod上
  ◼ 自定义:在Pod规范上,使用serviceAccountName指定要使用的特定ServiceAccount

ServiceAccount资源

ServiceAccount是Kubernetes API上的标准资源类型
  ◼ 基于资源对象保存ServiceAccount的数据
  ◼ 认证信息保存于ServiceAccount对象专用的Secret中(v1.23及之前的版本)
  ◼ 隶属名称空间级别,专供集群上的Pod中的进程访问API Server时使用
Kubernetes基于三个组件完成Pod上serviceaccount的自动化
  ◼ ServiceAccount Admission Controller:负责完成Pod上的ServiceAccount的自动化
    ◆为每个名称空间生成一个默认的default ServiceAccount及其依赖到的Secret对象(如果用得到)
    ◆为未定义serviceAccountName的Pod资源自动附加名称空间下的serviceaccounts/default;
    ◆为定义了serviceAccountName的Pod资源检查其引用的目标对象是否存在
  ◼ Token Controller #为每一个ServiceAccount自动生成token
  ◼ ServiceAccount Controller
 提示:需要用到特殊权限时,可为Pod指定要使用的自定义ServiceAccount资源对象

ServiceAccount的Secret和Token

 ServiceAccount使用专用的Secret对象(Kubernetes v1.23-)存储相关的敏感信息
  ◼ Secret对象的类型标识为“kubernetes.io/serviceaccount”
  ◼ 该Secret对象会自动附带认证到API Server用到的Token,也称为ServiceAccount Token
 ServiceAccount Token的不同实现方式
  ◼ Kubernetes v1.20-
    ◆系统自动生成专用的Secret对象,并基于secret卷插件关联至相关的Pod;
    ◆Secret中会自动附带Token,且永久有效;
  ◼ Kubernetes v1.21-v1.23:
    ◆系统自动生成专用的Secret对象,并通过projected卷插件关联至相关的Pod;
    ◆Pod不会使用Secret上的Token,而是由Kubelet向TokenRequest API请求生成,默认有效期为一年,且每小时更新一次;
  ◼ Kubernetes v1.24+:
    ◆系统不再自动生成专用的Secret对象
    ◆由Kubelet负责向TokenRequest API请求生成Token

ServiceAccount中的数据

 ServiceAccount专用的Secret对象有三个固定的数据项,它们的键名称分别为
  ◼ ca.crt:Kubernetes CA的数字证书
  ◼ namespace:该ServiceAccount可适用的名称空间
  ◼ token:认证到API Server的令牌,其生成方式曾多次变动
 Kubernetes v1.21及之后的版本中,Pod加载上面三种数据的方式,改变为基于projected卷插件,通过三个数据源(source)分别进行
  ◼ serviceAccountToken:提供由Kubelet负责向TokenRequest API请求生成的Token
  ◼ configMap:经由kube-root-ca.crt这个ConfigMap对象的ca.crt键,引用Kubernetes CA的证书
  ◼ downwardAPI:基于fieldRef,获取当前Pod所处的名称空间
 特殊场景
  ◼ 若需要一个永不过期的Token,可手动创建ServiceAccount专用类型的Secret,并将其关联到ServiceAccount之上

    ServiceAccount: #挂载路径
        /var/run/secrets/kubernetes.io/serviceaccount/

#例:
#进入容器
[root@master01 ~]#kubectl exec -it demoapp-8699b9895b-bljbb -- /bin/sh
#serviceaccount挂载点路径(多个版本中一直没变)
[root@demoapp-8699b9895b-bljbb /]# cd /var/run/secrets/kubernetes.io/serviceaccount/
[root@demoapp-8699b9895b-bljbb /run/secrets/kubernetes.io/serviceaccount]# ls
ca.crt     namespace  token
#容器内部进行访问
]# TOKEN=$(cat token)
]# curl -k -H "Authorization: Bearer ${TOKEN}" https://kubernetes.default.svc.cluster.local

#serviceaccount过长,我们通常不会用来与系统交互访问使用

#创建自定义的serviceaccount
#创建名称空间
[root@master01 ~]#kubectl create namespace jenkins
#自动生成serviceaccount,configmap
[root@master01 ~]#kubectl get sa,cm -n jenkins
NAME                     SECRETS   AGE
serviceaccount/default   0         35s
NAME                         DATA   AGE
configmap/kube-root-ca.crt   1      35s
#创建serviceaccount
[root@master01 ~]#kubectl create serviceaccount jenkins-master -n jenkins

总结

Kubernetes用户账号:
    User Account: 集群外部认证组件管理,API Server只需要信任该认证服务即可;
    Service Account:Kubernetes内置的资源类型,名称空间级别;
        system:serviceaccount:NAMESPACE:NAME 

 

鉴权体系与RBAC

1 Kubernetes的鉴权体系

API Server中的鉴权框架及启用的鉴权模块负责鉴权
  ◼ 支持的鉴权模块
    ◆Node:专用的授权模块,它基于kubelet将要运行的Pod向kubelet进行授权;
    ◆ABAC:通过将属性(包括资源属性、用户属性、对象和环境属性等)组合 在一起的策略,将访问权限授予用户;
    ◆RBAC:基于企业内个人用户的角色来管理对计算机或网络资源的访问的鉴权方法;
    ◆Webhook:用于支持同Kubernetes外部的授权机制进行集成;
  ◼ 另外两个特殊的鉴权模块是AlwaysDeny和AlwaysAllow;
配置方法
  ◼ 在kube-apiserver上使用 --authorization-mode 选项进行定义
    ◆kubeadm部署的集群,默认启用了Node和RBAC
  ◼ 多个模块彼此间以逗号分隔

 

2 RBAC鉴权模型

RBAC: 
    主谓宾:
        Subject: User Account, Service Account, Group 
        Action: create, delete, update, get, deletecollction, list, watch 
            Read: get/list/watch 
            Write: create/delete/deletecollection/patch/update 
        Object: Resources, non-resource url 
            Namespace级别资源类型:Role
            Namesapce级别资源类型和Cluster级别资源类型:ClusterRole

                授予名称空间级别资源的权限: 主 --> RoleBinding --> Role <-- 谓宾
                授予集群级别资源的: 主 --> ClusterRoleBinding --> ClusterRole <-- 谓宾
                    集群级别资源类型的权限:整个集群上的集群级别的资源
                    名称级别资源类型的权限:整个集群上的所有名称空间内的名称空间级别的资源

                授予名称空间级别资源的权限:主 --> RoleBinding --> ClusterRole <-- 谓宾

        Role/ClusterRole/RoleBinding/ClusterRoleBinding是API Server内置的标准资源类型:
            Role和RoleBinding:名称空间级别
            ClusterRole和ClusterRoleBinding:集群级别

   创建Role/ClusterRole/RoleBinding/ClusterRoleBinding:
        kubectl create

#总结
RoleBinding和ClusterRoleBinding绑定一个ClusterRole的区别:
    ClusterRoleBinding:得到的是ClusterRole定义的所有权限,包括集群级别的资源类型的授权,以及全部名称空间上的名称空间级别资源类型的授权;
    RoleBinding:得到的仅仅是RoleBinding自身所有名称空间上的仅限于名称空间级别的资源类型的授权;

#示例 (使用Role和RoleBinding):
#创建一个角色,读权限,要读哪些资源   (角色是名称空间类型资源,不指默认default)
#watch就是-w实时观察 例: kubectl get pods -w
[root@master01 ~]#kubectl create role reader --verb=get,list,watch --resource=deployments,pods,services -n default
#创建rolebinding,指定用户Tom为reader角色(不能跨名称空间,rolebinding只能绑同一名称空间下的role,tom不属于任何名称空间)
[root@master01 ~]#kubectl create rolebinding tom-as-reader --role=reader --user=tom -n default

#测试,把前面在主节点创建的kubeconfig复制到其他节点上,其他节点通过kubeconfig使用tom用户
[root@master01 ~]#scp kubeusers.conf root@10.0.0.152:/tmp/
#在节点上定义环境变量
[root@node01 tmp]#export KUBECONFIG='/tmp/kubeusers.conf'
#查看当前加载的kubeconfig信息
[root@node01 tmp]#kubectl config view
#设置默认用户
[root@node01 tmp]#kubectl config use-context tom@mykube
Switched to context "tom@mykube".
#查看当前用户
[root@node01 tmp]#kubectl config current-context
tom@mykube
#查看default空间下(只能看defult名称空间下)
[root@node01 tmp]#kubectl get pods
[root@node01 tmp]#kubectl get pods,services,deployments -n default
[root@node01 tmp]#kubectl describe pods demoapp-8699b9895b-bljbb
#没有dev名称空间权限
[root@node01 tmp]#kubectl get pods -n jenkins
#没有删权限
[root@node01 tmp]#kubectl delete pods demoapp-8699b9895b-bljbb
#临时切换一个用户
[root@node01 tmp]#kubectl get pods --context="jerry@mykube"

#给组授权
#参考前面最后一列配置的组
[root@master01 ~]#cat /etc/kubernetes/authfiles/tokens.csv 
f56cac.a4374aa9ad9a3618,tom,10001,kubeusers
442dc3.7301e1bcd991ea25,jerry,10002,kubeusers
3967cd.cbe6373ffba2aac0,trump,20001,kubeadmins
#kubeusers组内用户都有权限
[root@master01 ~]#kubectl create rolebinding kubeusers-as-reader --role=reader --group=kubeusers -n default
#测试,jerry用户
[root@node01 tmp]#kubectl get pods --context="jerry@mykube"
NAME                       READY   STATUS    RESTARTS      AGE
demoapp-8699b9895b-bljbb   1/1     Running   3 (18m ago)   2d4h
demoapp-8699b9895b-n5vcb   1/1     Running   3 (18m ago)   2d4h

#给serviceaccount授权
#创建serviceaccount
#[root@master01 ~]#kubectl create serviceaccount mysa
#上面已经创建了serviceaccount在jenkins名称空间下
[root@master01 ~]#kubectl get sa -n jenkins
NAME             SECRETS   AGE
default          0         21h
jenkins-master   0         21h
#注意:serviceaccount自己所引用的权限是可以跨名称空间的
#授予jenkins名空间下:jenkins-master 用户能在default名称空间下读pod的权限,而不是读当前名称空间
[root@master01 ~]#kubectl create rolebinding jenkins-master-as-reader --role=reader --serviceaccount=jenkins:jenkins-master -n default

#测试
[root@master01 ~]#kubectl run mypod --image=ikubernetes/demoapp:v1.0 --restart=Never --dry-run=client -o yaml > mypod.yaml
[root@master01 ~]#vim mypod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: jenkins #设定namespace
spec:
  containers:
  - image: ikubernetes/demoapp:v1.0
    name: mypod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
  serviceAccountName: jenkins-master #设定serviceAccount
#创建pod
[root@master01 ~]#kubectl apply -f mypod.yaml
#进入交互接口做测试
[root@master01 ~]#kubectl exec -it mypod -n jenkins -- /bin/sh
[root@mypod /]# cd /var/run/secrets/kubernetes.io/serviceaccount/
]# ls
ca.crt     namespace  token
]# TOKEN=$(cat token)
#访问default命名空间下pods
]# curl -k -H "Authorization: Bearer ${TOKEN}" https://kubernetes.default/api/v1/namespaces/default/pods/
#访问default命名空间下deployments
]# curl -k -H "Authorization: Bearer ${TOKEN}" https://kubernetes.default/apis/apps/v1/namespaces/default/deployments

#也可以把token复制出来,用交互式认证测试
#在容器外用kubectl --server ... --token ... get pods的方式测试


#示例 (使用ClusterRole和ClusterRoleBinding):
#创建clusterrole(clusterrole本身是集群级别,不用指名称空间) 资源sts为statefulset
[root@master01 ~]#kubectl create clusterrole cluster-reader --verb=get,list,watch --resource=sts,pvc,pv,sc
#创建clusterrolebinding绑定mason(使用x509证书认证)
[root@master01 ~]#kubectl create clusterrolebinding mason-as-cluster-reader --clusterrole=cluster-reader --user=mason

#测试
#在节点上选择mason连接测试 (集群资源权限)
[root@node01 tmp]#kubectl get sc --context='mason@mykube'
[root@node01 tmp]#kubectl get pv --context='mason@mykube'
[root@node01 tmp]#kubectl get pvc --context='mason@mykube'
[root@node01 tmp]#kubectl get pvc -n dev --context='mason@mykube'


#示例 (交叉绑定,RoleBinding去绑ClusterRole)
#rolebinding没有指名称空间就是default,jerry没有集群资源权限,只有当前所在名称空间权限
[root@master01 ~]#kubectl create rolebinding jerry-as-cluster-reader --clusterrole=cluster-reader --user=jerry
#测试
#jerry没有权限看kube-system名称空间(没有default空间以外的权限)
[root@node01 tmp]#kubectl get pvc -n kube-system --context='jerry@mykube'
#看default空间没问题
[root@node01 tmp]#kubectl get pvc --context='jerry@mykube'
#没有权限看集群资源
[root@node01 tmp]#kubectl get pvc --context='jerry@mykube'

默认的ClusterRole及ClusterRoleBinding

启用RBAC鉴权模块时,API Server会自动创建一组ClusterRole和ClusterRoleBinding对象
  ◼ 多数都以“system:”为前缀,也有几个面向用户的ClusterRole未使用该前缀,如cluster-admin、admin等
  ◼ 它们都默认使用“kubernetes.io/bootstrapping: rbac-defaults”这一标签
默认的ClusterRole大体可以分为如下5个类别
  ◼ API发现相关的角色
    ◆包括system:basic-user、system:discovery和system:public-info-viewer
  ◼ 面向用户的角色 #需要了解
    ◆包括cluster-admin、admin、edit和view
  ◼ 核心组件专用的角色
    ◆包括system:kube-scheduler、system:volume-scheduler、system:kube-controller-manager、system:node和system:node-proxier等
  ◼ 其它组件专用的角色
    ◆包括system:kube-dns、system:node-bootstrapper、system:node-problem-detector和system:monitoring等
  ◼ 内置控制器专用的角色

面向用户的角色

用于交互式用户授权目的的几个角色 (注:管理员用户组新版从system:masters变为cluster-admins)

内置的面向用户的ClusterRole:
    cluster-admin, admin, edit, view 

#cluster-admin: 集群管理员
#admin: 名称空间下的管理员

#让miller成为集群管理员,用系统内置的cluster-admin(不用建,直接引用)
[root@master01 ~]#kubectl create clusterrolebinding miller-as-cluster-admin --clusterrole=cluster-admin --user=miller
#查看系统内置的clusterrole(里面也有自己建的)
[root@master01 ~]#kubectl get clusterrole

#授权trump为jenkins名称空间下管理员
[root@master01 ~]#kubectl create rolebinding trump-as-ns-admin --clusterrole=edit --user=trump -n jenkins
#测试
[root@node01 ~]#kubectl --server=https://10.0.0.151:6443 --token='3967cd.cbe6373ffba2aac0' get pods -n jenkins
[root@node01 ~]#kubectl --server=https://10.0.0.151:6443 --token='3967cd.cbe6373ffba2aac0' get secret -n jenkins
#没有权限看default空间
[root@node01 ~]#kubectl --server=https://10.0.0.151:6443 --token='3967cd.cbe6373ffba2aac0' get secret -n default

 

kuboard

国人研发k8s控制网页

#官网
https://www.kuboard.cn/install/v3/install.html
#可以用docker部署,也可以用k8s部署,这里用k8s部署

#部署kuboard示例:
#这里选择openebs(也可用其他存储类),用openebs-rwx(在hostpath基础上+nfs实现多路读写)
#安装openebs环境
#部署pod
[root@master01 ~]#kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
#查看openebs下的pods,等所有都运行起来就可以用了
[root@master01 ~]#kubectl get pods -n openebs
#kuboard需要ReadWriteMany(RWX),rwx用存储级冗余比较好些,在jiva的基础(jiva也是单路读写)上加nfs
#再部署jiva环境,用于多存储环境(存储级冗余)
[root@master01 ~]#kubectl apply -f https://openebs.github.io/charts/jiva-operator.yaml
#查看openebs下的jiva的pod完成
[root@master01 ~]#kubectl get pods -n openebs

#定义jiva卷策略
[root@master01 ~]#cd /root/learning-k8s-master/OpenEBS/jiva-csi
[root@master01 jiva-csi]#vim openebs-jivavolumepolicy-demo.yaml
apiVersion: openebs.io/v1alpha1
kind: JivaVolumePolicy    #安装jiva创建的新的jivavolumepolicy
metadata:
  name: jivavolumepolicy-demo
  namespace: openebs #一般放在这个名称空间下
spec:
  replicaSC: openebs-hostpath #复制时使用的存储类,这里用基于目录存储(上面用的本地卷方式相同)
  target:
    # This sets the number of replicas for high-availability
    # replication factor <= no. of (CSI) nodes
    replicationFactor: 2 #复制因子,数据打算冗余几份

[root@master01 jiva-csi]#kubectl apply -f openebs-jivavolumepolicy-demo.yaml
#查看创建的jivavolumepolicy资源类型
[root@master01 jiva-csi]#kubectl get jivavolumepolicy -n openebs 
NAME                    AGE
jivavolumepolicy-demo   32s
#创建存储类
[root@master01 jiva-csi]#vim openebs-jiva-csi-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: openebs-jiva-csi
provisioner: jiva.csi.openebs.io
allowVolumeExpansion: true #是否支持卷扩缩容(使用路径不支持,用LVM支持)
parameters:
  cas-type: "jiva"
  policy: "jivavolumepolicy-demo" #在哪个policy管控jiva存储卷
  
[root@master01 jiva-csi]#kubectl apply -f openebs-jiva-csi-storageclass.yaml
[root@master01 jiva-csi]#kubectl get sc

#jiva还是单路读写,在它的基础上增加nfs功能变为多路读写
#部署nfs-operator
[root@master01 jiva-csi]#kubectl apply -f https://openebs.github.io/charts/nfs-operator.yaml
#查看nfs相关组件
[root@master01 jiva-csi]#kubectl get pods -n openebs
#查看存储类,会多出openebs-rwx存储类,默认用hostpath(也可以,我们修改为jiva更好些)
[root@master01 jiva-csi]#kubectl get sc
NAME               PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION
...
openebs-rwx        openebs.io/nfsrwx              Delete          Immediate              false       
#查看openebs-rwx,使用的后端是hostpath,我们这里改成jiva多储存(这里不进行演示了,直接用hostpath实验)
]#kubectl get sc openebs-rwx -o yaml

#使用storageclass提供持久化
#获取部署 Kuboard 所需的 YAML 文件
]#curl -o kuboard-v3.yaml https://addons.kuboard.cn/kuboard/kuboard-v3-storage-class.yaml
[root@master01 ~]#vim kuboard-v3.yaml
...
data:
  #kuboard访问路径,这里通过ingress对外暴露地址(ingress有固定入口还需要metallb)
  KUBOARD_ENDPOINT: 'http://kuboard.magedu.com'
...
      storageClassName: openebs-rwx #修改存储类
      accessModes: [ "ReadWriteMany" ]
...
metadata:
  name: kuboard-data-pvc
  namespace: kuboard #追加名称空间
spec:
  storageClassName: openebs-hostpath #这里单路读写,用hostpath没事
  accessModes:
    - ReadWriteOnce

#安装MetalLB(可以不部署,静态指定ExternalIP)
[root@master01 ~]#kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml
#确认pod都运行起来
[root@master01 ~]#kubectl get pods -n metallb-system

#地址池里必须是集群节点地址范围,并且是其他节点没有使用的地址
[root@master01 MetalLB]#vim metallb-ipaddresspool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: localip-pool
  namespace: metallb-system #metallb自己的名称空间
spec:
  addresses: #确保地址没人用
  - 10.0.0.51-10.0.0.80
  autoAssign: true #自动配置在某个节点上
  avoidBuggyIPs: true #避免使用全0或全1的ip
#创建地址池
[root@master01 MetalLB]#kubectl apply -f metallb-ipaddresspool.yaml

#做公告模式
[root@master01 MetalLB]#vim metallb-l2advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: localip-pool-l2a
  namespace: metallb-system
spec:
  ipAddressPools:
  - localip-pool
  interfaces: #通过这个接口对外发ARP(自问自答)
  - ens33 #网卡地址(如果多个节点网卡名不同,那都列在这)
#创建对应资源
[root@master01 MetalLB]#kubectl apply -f metallb-l2advertisement.yaml

#部署ingress
]#kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/cloud/deploy.yaml
#等待pod运行起来
[root@master01 ~]#kubectl get pods -n ingress-nginx
#查看ingress绑定的地址10.0.0.52
[root@master01 ~]#kubectl get svc -n ingress-nginx 
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.96.135.77   10.0.0.52     80:32563/TCP,443:30464/TCP   5d6h

#部署kuboard(如果拉取镜像错误,可以替换dockhub的镜像,如eipwork/etcd)
[root@master01 ~]#kubectl apply -f kuboard-v3.yaml
#查看,Pending是因为openebs提供前要进行初始化
[root@master01 ~]#kubectl get pods -n kuboard
NAME                          READY   STATUS    RESTARTS   AGE
kuboard-etcd-0                1/1     Running   0          34m
kuboard-etcd-1                1/1     Running   0          33m
kuboard-etcd-2                1/1     Running   0          33m
kuboard-v3-69bd874899-krgvl   1/1     Running   0          34m
#查看pvc
[root@master01 ~]#kubectl get pvc -n kuboard
#查看service,kuboard-v3对外node为30080
[root@master01 ~]#kubectl get svc -n kuboard
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                     
kuboard-etcd   ClusterIP   10.109.205.51   <none>        2379/TCP,2380/TCP                           
kuboard-v3     NodePort    10.99.194.153   <none>        80:30080/TCP,10081:30081/TCP,10081:30081/UDP 

#创建ingress
[root@master01 ~]#kubectl create ingress kuboard --rule='kuboard.magedu.com/*'=kuboard-v3:80 --class=nginx -n kuboard
#过一会,会关联上地址
[root@master01 ~]#kubectl get ingress -n kuboard
NAME      CLASS   HOSTS                ADDRESS     PORTS   AGE
kuboard   nginx   kuboard.magedu.com   10.0.0.52   80      83s

#配置hosts文件,浏览器输入测试  admin/Kuboard123
10.0.0.52 kuboard.magedu.com

使用kuboard

#可以管理多集群,点击添加集群
#第一种token,要在kuboard-v3.yaml中创建使用一个serviceaccount,绑定到管理员cluster-admin上(默认为dafault不符合)

#第二种KubeConfig认证,把管理员的KubeConfig读出来
[root@master01 ~]#cat /etc/kubernetes/admin.conf
#把里面的信息复制出来贴上去,里面的server: https://kubeapi.magedu.com:6443改成https://10.0.0.151:6443,不然可能解析不了地址连接不上
#下面的ApiServer 地址 也改为 https://10.0.0.151:6443
#上面名称输入 kubernetes
#上面描述输入 local kubernetes cluster
#确定即可载入整个集群
#右侧选择访问集群时所使用的身份,这里选 serviceaccount kuboard-admin  做集群管理员

#点左侧集群管理/概要
#可以在名称空间下,deployment点击扩容缩容(自动伸缩要先创建hpa,后面会讲)

 

网络插件及流量转发机制

1 Pod网络的解决方案

Kubernetes网络模型

Kubernetes集群上会存在三个分别用于节点、Pod和Service的网络
  ◼ 三个网络于集群节点上完成交汇
  ◼ 由节点内核中的路由模块,以及iptables/netfilter和ipvs等完成网络间的流量转发

 Kubernetes的Pod网络

Kubernetes将Pod网络功能通过CNI委托给了外部的插件,该类插件主要负责解决如下4个问题
  ◼ 同一Pod内容器间的通信(Container to Container)
  ◼ Pod间的通信(Pod to Pod)
  ◼ Service到Pod间的通信(Service to Pod)
  ◼ 集群外部与Service之间的通信(external to Service)
  
Pod网络:
    子网: 
        10.244.0.0/16:再次划分子网
            子网掩码长度:24
                可划分成的子网数:2^8 #节点数
                    10.244.0.0/24 - 10.244.255.0/24
                每个子网可使用的地址:2^8-2 #节点上的pod数
                    每子网可用的地址数为254个;
                    
    通信网络:
        overlay:隧道网络,叠加网络 #请求报文目标地址的封装上再封装一层目标节点地址,进行转发
        underlay:承载网络,底层网络
            routing:路由网络 #通过节点路由转发到目标路由,再到pod
            ipvlan/macvlan:VLAN网络 #通过物理网卡进行虚拟,让pod持有物理网卡,类似桥接(性能好,物理交换机得支持,内核得支持ipvlan/macvlan模块)

CNI网络插件基础

 CNI的全称为“容器网络接口”,它是容器引擎与遵循该规范网络插件的中间层,专用于为容器配置网络子系统
简单来说,目前的CNI规范主要由NetPlugin(网络插件)和IPAM两个插件API组成
  ◼ 网络插件也称Main插件,负责创建/删除网络以及向网络添加/删除容器
    ◆它专注于连通容器与容器之间以及容器与宿主机之间的通信,同容器相关网络设备通常都由该类插件所创建,例如bridge、ipvlan、macvlan、loopback、ptp、veth以及vlan等虚拟设备;
  ◼ IPAM的全称“IP Address Management”,该类插件负责创建/删除地址池以及分配/回收容器的IP地址
    ◆目前,该类型插件的实现主要有host-local和dhcp两个,前一个基于预置的地址范围进行地址分配,而后一个通过dhcp
协议获取地址;

将Pod接入Pod网络:#由网络插件完成
    创建出Pod网络
    创建Pod时,给Pod注入虚拟网络接口
    给虚拟网络接口分配IP地址
    将Pod的虚拟网络接口接入到Pod网络中

  配置容器网络接口的常用方法

不同的容器虚拟化网络解决方案中为Pod的网络名称空间创建虚拟接口设备的方式也会有所不同,目前,较为注流的实现方式有虚拟以太网设备(veth)、多路复用及
硬件交换三种 ◼ veth设备:创建一个网桥,并为每个容器创建一对虚拟以太网接口(veth),一个接入容器内部,另一个留置于根名称空间内添加为Linux内核桥接功能或
OpenVSwitch(OVS)网桥的从设备
#要封装和解封装,性能消耗5%-10%(无特殊要求,2.4以后版本都行,使用范围更广,用的更多的一种方案) ◼ 多路复用:多路复用可以由一个中间网络设备组成,它暴露多个虚拟接口,使用数据包转发规则来控制每个数据包转到的目标接口 #软件模拟占用网卡(要求内核
支持),性能消耗3%-5%(要更新的内核3.8甚至4.5以后,所以容器技术ubuntu系统多)
◆MACVLAN技术为每个虚拟接口配置一个MAC地址并基于此地址完成二层报文收发,IPVLAN则是分配一个IP地址并共享单个MAC并根据目标IP完成容器报文转发; ◼ 硬件交换:现今市面上有相当数量的NIC都支持单根I/O虚拟化(SR-IOV),它是创建虚拟设备的一种实现方式,每个虚拟设备自身表现为一个独立的PCI设备,
并有着自己的VLAN及硬件强制关联的QoS;SR-IOV提供了接近硬件级别的性能;#硬件模拟占用网卡(需要高级网卡支持),性能达99% #通常配第一种veth pair,对性能有极致要求的配MACVLAN或SR-IOV #如果k8s建在公有云上,公有云通常有优化自己底层网络通讯的专用网络插件(如果华为云部署k8s,应该用华为云专用k8s的网络插件)

 

Kubernetes的网络解决方案

NetPlugin目前常用的实现方案有叠加网络(Overlay Network)和承载网络(Underlay Network)两类

Overlay网络模型

 VXLAN(Virtual eXtensible Local Area Network,虚拟扩展局域网)
  ◼ 目前最流行的叠加网络隧道协议之一
  ◼ 也是由IETF定义的NVO3(Network Virtualization over Layer 3)标准技术之一
  ◼ 采用L2 over L4(MAC-in-UDP)的报文封装模式,将二层报文用三层协议进行封装,可实现二层网络在三层
范围内进行扩展

#建Overlay网络模型,每个节点都有隧道设备Tunnel device,发出端隧道设备封装请求,接收端隧道设备拆封装。节点有路由表,只有跨节点pod通讯才会经过隧道。
同节点pod通过虚拟交换机cni0完成了,不经过隧道

Underlay网络模型

容器网络中的承载网络是指借助驱动程序将宿主机的底层网络接口直接暴露给容器使用的一种网络构 建技术,较为常见的解决方案有macvlan、ipvlan和直接路由等

MACVLAN

◼ MACVLAN支持在同一个以太网接口上虚拟出多个网络接口,每个虚拟接口都拥有惟一的MAC地址,并可按
需配置IP地址
◼ MACVLAN允许传输广播和多播流量,它要求物理接口工作于混杂模式 #有风险,什么mac地址都接收,可能被攻击
◼ 与Bridge模式相比,MACVLAN不再依赖虚拟网桥、NAT和端口映射,它允许容器以虚拟接口方式直接连接
至物理接口
#需要内核好像3.8版本以后

  IPVLAN

#共享物理网卡mac地址,但ip不同。相当于所有节点的pod共享物理网卡的mac地址
◼ IPVLAN类似于MACVLAN,它同样创建新的虚拟网络接口并为每个接口分配惟一的IP地址,不同之处在于,
每个虚拟接口将共享使用物理接口的MAC地址,从而不再违反防止MAC欺骗的交换机的安全策略,且不要求
在物理接口上启用混杂模式
#需要的内核版本更高,好像4.5版本以后

 Direct Routing(直接路由)

◼ 放弃跨主机的容器在L2的连通性,而专注于通过路由协议解决它们在L3的通信的解决方案通常可简称为“直
接路由”模型
◼ 跨主机的容器间通信,需要借助于主机上的路由表指示完成报文路由,因此每个主机的物理接口地址都有可
能被引用为另一个主机路由报文时的“下一跳(nexthop)”,这就要求各主机的物理接口必须位于同一个L2网络中

 

posted @ 2024-12-07 19:26  战斗小人  阅读(34)  评论(0编辑  收藏  举报