第8章:Kubernetes 安全
Kubernetes 安全
1. Kubernetes 安全框架
• 访问K8S集群的资源需要过三关:认证、鉴权、准入控制
• 普通用户若要安全访问集群API Server,往往需要证书、
Token或者用户名+密码;Pod访问,需要ServiceAccount
• K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段
都支持插件方式,通过API Server配置来启用插件。
1. Authentication(鉴权)
2. Authorization(授权)
3. Admission Control(准入控制)
2. 认证,授权,准入控制
鉴权(Authentication)
三种客户端身份认证:
• HTTPS 证书认证:基于CA证书签名的数字证书认证
• HTTP Token认证:通过一个Token来识别用户
• HTTP Base认证:用户名+密码的方式认证
授权(Authorization)
RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作。
根据API请求属性,决定允许还是拒绝。
• user:用户名
• group:用户分组
• extra:用户额外信息
• API
• 请求路径:例如/api,/healthz
• API请求方法:get,list,create,update,patch,watch,delete
• HTTP请求方法:get,post,put,delete
• 资源
• 子资源
• 命名空间
• API组
准入控制(Admission Control)
Adminssion Control实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求。
3. 基于角色的权限访问控制:RBAC
RBAC(Role-Based Access Control,基于角色的访问控制),允许通过Kubernetes API动态配置策略。
角色
• Role:授权特定命名空间的访问权限
• ClusterRole:授权所有命名空间的访问权限
角色绑定
• RoleBinding:将角色绑定到主体(即subject)
• ClusterRoleBinding:将集群角色绑定到主体
主体(subject)
• User:用户
• Group:用户组
• ServiceAccount:服务账号
4. 案例:为指定用户授权访问不同命名空间权限
示例:为aliang用户授权default命名空间Pod读取权限
1. 用K8S CA签发客户端证书
2. 生成kubeconfig授权文件
3. 创建RBAC权限策略
证书内容生成
[root@k8s-m1 rbac]# cat cert.sh cat > ca-config.json <<EOF { "signing": { "default": { "expiry": "87600h" }, "profiles": { "kubernetes": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "87600h" } } } } EOF cat > lewen-csr.json <<EOF { "CN": "lewen", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "k8s", "OU": "System" } ] } EOF cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -profile=kubernetes lewen-csr.json | cfssljson -bare lewen
k8s签发证书
[root@k8s-m1 rbac]# cat kubeconfig.sh kubectl config set-cluster kubernetes \ --certificate-authority=/etc/kubernetes/pki/ca.crt \ --embed-certs=true \ --server=https://10.0.0.23:6443 \ --kubeconfig=lewen.kubeconfig # 设置客户端认证 kubectl config set-credentials lewen \ --client-key=lewen-key.pem \ --client-certificate=lewen.pem \ --embed-certs=true \ --kubeconfig=lewen.kubeconfig # 设置默认上下文 kubectl config set-context kubernetes \ --cluster=kubernetes \ --user=lewen \ --kubeconfig=lewen.kubeconfig # 设置当前使用配置 kubectl config use-context kubernetes --kubeconfig=lewen.kubeconfig
创建用户访问权限
[root@k8s-m1 rbac]# cat rbac.yaml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-reader rules: - apiGroups: ["","apps"] resources: ["pods","services","deployments"] verbs: ["get", "watch", "list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: read-pods namespace: default subjects: - kind: User name: lewen apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
测试访问
把生成的 lewen.kubeconfig 拷贝到 root/.kube/config
就可以访问资源了
5. 网络策略概述
网络策略(Network Policy),用于限制Pod出入流量,提供Pod级别和Namespace级别网络访问控制。
一些应用场景:
• 应用程序间的访问控制。例如微服务A允许访问微服务B,微服务C不能访问微服务A
• 开发环境命名空间不能访问测试环境命名空间Pod
• 当Pod暴露到外部时,需要做Pod白名单
• 多租户网络环境隔离
Pod网络入口方向隔离:
• 基于Pod级网络隔离:只允许特定对象访问Pod(使用标签定义),允许白名单上的IP地址或者IP段访问Pod
• 基于Namespace级网络隔离:多个命名空间,A和B命名空间Pod完全隔离。
Pod网络出口方向隔离:
• 拒绝某个Namespace上所有Pod访问外部
• 基于目的IP的网络隔离:只允许Pod访问白名单上的IP地址或者IP段
• 基于目标端口的网络隔离:只允许Pod访问白名单上的端口
6. 案例:对项目Pod出入流量访问控制
需求1:将default 命名空间携带run=web-nginx-0811标签的Pod隔离,只允 许default命名空间携带run=client标签的Pod访问80端口。
[root@k8s-m1 chp8]# cat test-network-policy.yml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: matchLabels: app: web-nginx-0811 policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: run: client ports: - protocol: TCP port: 80
# 创建一个pod用来测试 kubectl run -l run=client --image=busybox -- sh [root@k8s-m1 ~]# kubectl get pod sh --show-labels # 查看pod的标签,要和网络策略里面的一直 NAME READY STATUS RESTARTS AGE LABELS sh 1/1 Running 0 96s run=client # 查看一下限流pod的IP地址 [root@k8s-m1 chp8]# kubectl get ep web-nginx-0811 NAME ENDPOINTS AGE web-nginx-0811 10.244.111.212:80,10.244.111.213:80,10.244.111.220:80 8d # 然后去到允许访问的pod里面,发起测试 [root@k8s-m1 ~]# kubectl exec sh -it -- sh / # ls bin dev etc home proc root sys tmp usr var # 能够成功获取页面 / # wget 10.244.111.213 Connecting to 10.244.111.213 (10.244.111.213:80) saving to 'index.html' index.html 100% |*************| 612 0:00:00 ETA 'index.html' saved # 测试一下端口 / # telnet 10.244.111.213 80 Connected to 10.244.111.213 Connection closed by foreign host # 创建另外一个非允许的标签 pod kubectl run -l run=client-other -it --image=busybox -- bash [root@k8s-m1 ~]# kubectl get pod bash --show-labels NAME READY STATUS RESTARTS AGE LABELS bash 1/1 Running 0 96s run=client-other # 发现其他非允许的pod 无法访问 web-nginx-0811 [root@k8s-m1 ~]# kubectl exec bash -it -- sh / # wget 10.244.111.213 Connecting to 10.244.111.213 (10.244.111.213:80) wget: can't connect to remote host (10.244.111.213): Connection timed out / # telnet 10.244.111.213 80
需求2:default命名空间下所有pod可以互相访问,也可以访问其他命名空间Pod,但其他命名空间不能访问 default命名空间Pod
[root@k8s-m1 chp8]# cat deny-from-other-namespaces.yml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-from-other-namespaces namespace: default spec: podSelector: {} policyTypes: - Ingress ingress: - from: - podSelector: {}
# 创建一个 kube-system 命名空间的 [root@k8s-m1 chp8]# kubectl run client2 -it --image=busybox -n kube-system -- sh / # ping 10.244.111.213 PING 10.244.111.213 (10.244.111.213): 56 data bytes 64 bytes from 10.244.111.213: seq=0 ttl=63 time=0.271 ms 64 bytes from 10.244.111.213: seq=1 ttl=63 time=0.115 ms 64 bytes from 10.244.111.213: seq=2 ttl=63 time=0.113 ms ^C --- 10.244.111.213 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.113/0.166/0.271 ms / # wget 10.244.111.213 Connecting to 10.244.111.213 (10.244.111.213:80) saving to 'index.html' index.html 100% |*********************************************| 612 0:00:00 ETA 'index.html' saved # 创建执行命令后,不通了 [root@k8s-m1 chp8]# kubectl apply -f deny-from-other-namespaces.yml networkpolicy.networking.k8s.io/deny-from-other-namespaces created / # ping 10.244.111.213 PING 10.244.111.213 (10.244.111.213): 56 data bytes ^C --- 10.244.111.213 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss / # wget 10.244.111.213 Connecting to 10.244.111.213 (10.244.111.213:80) ^C # 创建一个默认名称空间的pod,发现可以访问 [root@k8s-m1 chp8]# kubectl run client-default -it --image=busybox -- sh If you don't see a command prompt, try pressing enter. / # ping 10.244.111.213 PING 10.244.111.213 (10.244.111.213): 56 data bytes 64 bytes from 10.244.111.213: seq=0 ttl=63 time=0.110 ms 64 bytes from 10.244.111.213: seq=1 ttl=63 time=0.064 ms 64 bytes from 10.244.111.213: seq=2 ttl=63 time=0.073 ms ^C --- 10.244.111.213 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.064/0.082/0.110 ms / # wget 10.244.111.213 Connecting to 10.244.111.213 (10.244.111.213:80) saving to 'index.html' index.html 100% |*********************************************| 612 0:00:00 ETA 'index.html' saved / #
课后作业
1、完成案例1:为指定用户授权访问不同命名空间权限
2、完成案例2:对项目Pod出入流量访问控制