9.1 k8s安全框架

  • K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
    1. Authentication(鉴权)
    2. Authorization(授权)
    3. Admission Control(准入控制)
  • 客户端要想访问K8s集群API Server,一般需要证书、Token或者用户名+密码;如果Pod访问,需要ServiceAccount

9、k8s安全 - 图1

1、鉴权(Authentication)

K8s Apiserver提供三种客户端身份认证:

  • HTTPS 证书认证:基于CA证书签名的数字证书认证(kubeconfig)
  • HTTP Token认证:通过一个Token来识别用户(serviceaccount)
  • HTTP Base认证:用户名+密码的方式认证(1.19版本弃用)

2、授权(Authorization)

RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作

RBAC根据API请求属性,决定允许还是拒绝。

比较常见的授权维度:

  • user:用户名
  • group:用户分组
  • 资源,例如pod、deployment
  • 资源操作方法:get,list,create,update,patch,watch,delete
  • 命名空间
  • API组

3、准入控制(Admission Control)

Adminssion Control实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求。

  1. 启用一个准入控制器:
  2. kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger ...
  3. 关闭一个准入控制器:
  4. kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...
  5. 查看默认启用:
  6. kubectl exec kube-apiserver-k8s-master1 -n kube-system -- kube-apiserver -h | grep enable-admission-plugins

9.2 基于角色的权限访问控制:RBAC

RBAC(Role-Based Access Control,基于角色的访问控制)

是K8s默认授权策略,并且是动态配置策略(修改即时生效)

主体(subject)

  • User:用户
  • Group:组
  • ServiceAccount:服务账号

角色(Role、ClusterRole)

  • Role:授权特定名称空间的访问权限
  • ClusterRole:授权所有名称空间的访问权限

角色绑定(Rolebinding、ClusterRoleBinding)

  • RoleBinding:将角色绑定到主体(即subject)
  • ClusterRoleBinding:将集群角色绑定到主体

9、k8s安全 - 图2

1、案例1:default名称空间的读取权限

场景:为指定用户授权访问不同命名空间权限,例如新入职一个小弟,希望让他先熟悉K8s集群,为了安全性,先不能给他太大权限,因此先给他授权访问default命名空间Pod读取权限

步骤:

  • 用K8S CA签发客户端证书
  • 生成kubeconfig授权文件
  • 创建RBAC权限策略
  • 指定kubeconfig文件测试权限:kubectl get pods —kubeconfig=./aliang.kubeconfig

使用CA签发客户端证书

  1. cat crets.sh
  2. cat > ca-config.json <<EOF
  3. {
  4. "signing": {
  5. "default": {
  6. "expiry": "87600h"
  7. },
  8. "profiles": {
  9. "kubernetes": {
  10. "expiry": "87600h",
  11. "usages": [
  12. "signing",
  13. "key encipherment",
  14. "server auth",
  15. "client auth"
  16. ]
  17. }
  18. }
  19. }
  20. }
  21. EOF
  22. cat > ca-csr.json <<EOF
  23. {
  24. "CN": "kubernetes",
  25. "key": {
  26. "algo": "rsa",
  27. "size": 2048
  28. },
  29. "names": [
  30. {
  31. "C": "CN",
  32. "L": "Beijing",
  33. "ST": "Beijing"
  34. }
  35. ]
  36. }
  37. EOF
  38. #cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
  39. cat > aliang.json <<EOF
  40. {
  41. "CN": "aliang",
  42. "hosts": [],
  43. "key": {
  44. "algo": "rsa",
  45. "size": 2048
  46. },
  47. "names": [
  48. {
  49. "C": "CN",
  50. "L": "BeiJing",
  51. "ST": "BeiJing"
  52. }
  53. ]
  54. }
  55. EOF
  56. #cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes web.aliangedu.cn-csr.json | cfssljson -bare web.javademo.com
  57. cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -profile=kubernetes aliang.json | cfssljson -bare aliang

生成授权文件

  1. # 设置集群
  2. kubectl config set-cluster kubernetes \
  3. --certificate-authority=/etc/kubernetes/pki/ca.crt \
  4. --embed-certs=true \
  5. --server=https://192.168.6.20:6443 \
  6. --kubeconfig=aliang.kubeconfig
  7. # 设置客户端认证
  8. kubectl config set-credentials aliang \
  9. --client-key=aliang-key.pem \
  10. --client-certificate=aliang.pem \
  11. --embed-certs=true \
  12. --kubeconfig=aliang.kubeconfig
  13. # 设置默认上下文
  14. kubectl config set-context kubernetes \
  15. --cluster=kubernetes \
  16. --user=aliang \
  17. --kubeconfig=aliang.kubeconfig
  18. # 设置当前使用配置-这一步是必须的否则报未指定8080端口错误
  19. kubectl config use-context kubernetes --kubeconfig=aliang.kubeconfig
  20. # 查看pod
  21. kubectl get pod --kubeconfig=aliang.kubeconfig # 没有授予访问权限
  22. Error from server (Forbidden): pods is forbidden: User "aliang" cannot list resource "pods" in API group "" in the namespace "default"

创建RBAC策略

创建角色(权限集合)

  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: Role
  3. metadata:
  4. namespace: default
  5. name: pod-reader
  6. rules:
  7. - apiGroups: [""] # api组,例如apps组,空值表示是核心API组,像namespace、pod、service、pv、pvc都在里面
  8. resources: ["pods"] #资源名称(复数),例如pods、deployments、services
  9. verbs: ["get", "watch", "list"] # 资源操作方法

将用户与角色绑定

  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: RoleBinding
  3. metadata:
  4. name: read-pods
  5. namespace: default
  6. subjects:
  7. - kind: User # 主体
  8. name: aliang # 主体名称
  9. apiGroup: rbac.authorization.k8s.io
  10. roleRef: # 绑定的角色
  11. kind: Role
  12. name: pod-reader # 角色名称
  13. apiGroup: rbac.authorization.k8s.io

指定kubeconfig文件测试权限

  1. kubectl get pod --kubeconfig=aliang.kubeconfig

认证流程

9、k8s安全 - 图3

2、cka真题-服务账号

题目

  1. 环境:
  2. kubectl config use-context k8s
  3. Context
  4. 为部署管道创建一个新的ClusterRole并将其绑定到范围为特定的namespace的特定的ServiceAccount
  5. Task
  6. 创建一个名为deployment-clusterrole且仅允许创建一下资源类型的新的ClusterRole
  7. Deployment
  8. StatefulSet
  9. DaemonSet
  10. 现有namespace app-team1中创建一个名为cicd-token的新的ServiceAccount
  11. 限于namespace app-team1,将新的ClusterRole deployment-clusterrole绑定到新的ServiceAccount cicd-token

命令创建

  1. # 创建clusterrole
  2. kubectl create clusterrole deployment-clusterrole --verb=create --resource=Deployment,StatefulSet,DaemonSet
  3. # app-team1名称空间创建SA
  4. kubectl create serviceaccount cicd-token -n app-team1
  5. # 创建RoleBinding绑定clusterrole到SA
  6. kubectl create rolebinding deployment-clusterrole-binding --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token -n app-team1
  7. # 测试服务账号权限
  8. kubectl --as=system:serviceaccount:app-team1:cicd-token \
  9. get pods -n app-team1

yaml

  1. ---
  2. apiVersion: v1
  3. kind: ServiceAccount
  4. metadata:
  5. name: cicd-token
  6. namespace: app-team1
  7. ---
  8. apiVersion: rbac.authorization.k8s.io/v1
  9. kind: ClusterRole
  10. metadata:
  11. name: deployment-clusterrole
  12. rules:
  13. - apiGroups: ["","apps"]
  14. resources: ["pods","deployments","daemonsets","statefulsets"]
  15. verbs: ["create","get","list"]
  16. ---
  17. apiVersion: rbac.authorization.k8s.io/v1
  18. kind: RoleBinding
  19. metadata:
  20. name: deployment-clusterrole-binding
  21. namespace: app-team1
  22. roleRef:
  23. apiGroup: rbac.authorization.k8s.io
  24. kind: ClusterRole
  25. name: deployment-clusterrole
  26. subjects:
  27. - kind: ServiceAccount
  28. name: cicd-token
  29. namespace: app-team1

9.3 网络策略

网络策略通过网络插件 来实现。要使用网络策略,你必须使用支持 NetworkPolicy 的网络解决方案。

默认情况下,Kubernetes 集群网络没任何网络限制,Pod 可以与任何其他 Pod 通信,在某些场景下就需要进行网络控制,减少网络攻击面,提高安全性,这就会用到网络策略。

网络策略(Network Policy):是一个K8s资源,用于限制Pod出入流量,提供Pod级别和Namespace级别网络访问控制。

应用场景:

  • 应用程序间的访问控制,例如项目A不能访问项目B的Pod
  • 开发环境命名空间不能访问测试环境命名空间Pod
  • 当Pod暴露到外部时,需要做Pod白名单
  • 多租户网络环境隔离

规则说明:

  • podSelector:目标Pod,根据标签选择。
  • policyTypes:策略类型,指定策略用于入站、出站流量。
  • Ingress:from是可以访问的白名单,可以来自于IP段、命名空间、Pod标签等,ports是可以访问的端口。
  • Egress:这个Pod组可以访问外部的IP段和端口

实例:https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: test-network-policy
  5. namespace: default
  6. spec:
  7. podSelector:
  8. matchLabels:
  9. role: db
  10. policyTypes:
  11. - Ingress
  12. - Egress
  13. ingress:
  14. - from:
  15. - ipBlock:
  16. cidr: 172.17.0.0/16
  17. except:
  18. - 172.17.1.0/24
  19. - namespaceSelector:
  20. matchLabels:
  21. project: myproject
  22. - podSelector:
  23. matchLabels:
  24. role: frontend
  25. ports:
  26. - protocol: TCP
  27. port: 6379
  28. egress:
  29. - to:
  30. - ipBlock:
  31. cidr: 10.0.0.0/24
  32. ports:
  33. - protocol: TCP
  34. port: 5978

案例1:拒绝其他命名空间Pod访问

准备环境:

  1. 附:准备环境快捷命令
  2. kubectl run busybox --image=busybox -n test -- sleep 12h
  3. kubectl run web --image=nginx -n test
  4. kubectl exec busybox -n test -- ping 10.244.169.169

需求:test命名空间下所有pod可以互相访问,也可以访问其他命名空间Pod,但其他命名空间不能访问test命名空间Pod。

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: deny-other-pod-policy
  5. namespace: test
  6. spec:
  7. podSelector: {} # 空,本命名空间下所有的pod添加策略
  8. policyTypes:
  9. - Ingress
  10. ingress:
  11. - from:
  12. - podSelector: {} # 空,本命名空间下所有的pod

案例2:同一个命名空间下应用之间限制访问

需求:将test命名空间携带run=web标签的Pod隔离,只允许test命名空间携带run=client1标签的Pod访问80端口

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: deny-selector-pod-policy
  5. namespace: test
  6. spec:
  7. podSelector:
  8. matchLabels:
  9. run: web # 当前名称空间下具有run=web标签的pod添加策略
  10. policyTypes:
  11. - Ingress
  12. ingress:
  13. - from:
  14. - podSelector:
  15. matchLabels:
  16. run: client1 # 本名称空间下有run=client1标签的pod访问
  17. ports:
  18. - protocol: TCP
  19. port: 80 # 访问80端口
  1. k label pod/busybox -n test --overwrite run=client1
  2. k exec busybox -n test -- telnet 10.244.169.169 80

案例3:只允许指定命名空间中的应用访问

需求:只允许dev命名空间中的Pod访问test命名空间中的pod 80端口

命名空间打标签: kubectl label namespace dev name=dev

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: deny-ns-pod-policy
  5. namespace: test
  6. spec:
  7. podSelector: {}
  8. policyTypes:
  9. - Ingress
  10. ingress:
  11. - from:
  12. - namespaceSelector:
  13. matchLabels:
  14. name: dev
  15. ports:
  16. - protocol: TCP
  17. port: 80 # 访问80端口