9.1 k8s安全框架
- K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
- Authentication(鉴权)
- Authorization(授权)
- Admission Control(准入控制)
- 客户端要想访问K8s集群API Server,一般需要证书、Token或者用户名+密码;如果Pod访问,需要ServiceAccount
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的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求。
启用一个准入控制器:
kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger ...
关闭一个准入控制器:
kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...
查看默认启用:
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:将集群角色绑定到主体
1、案例1:default名称空间的读取权限
场景:为指定用户授权访问不同命名空间权限,例如新入职一个小弟,希望让他先熟悉K8s集群,为了安全性,先不能给他太大权限,因此先给他授权访问default命名空间Pod读取权限。
步骤:
- 用K8S CA签发客户端证书
- 生成kubeconfig授权文件
- 创建RBAC权限策略
- 指定kubeconfig文件测试权限:kubectl get pods —kubeconfig=./aliang.kubeconfig
使用CA签发客户端证书
cat crets.sh
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
#cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cat > aliang.json <<EOF
{
"CN": "aliang",
"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 web.aliangedu.cn-csr.json | cfssljson -bare web.javademo.com
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
生成授权文件
# 设置集群
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.6.20:6443 \
--kubeconfig=aliang.kubeconfig
# 设置客户端认证
kubectl config set-credentials aliang \
--client-key=aliang-key.pem \
--client-certificate=aliang.pem \
--embed-certs=true \
--kubeconfig=aliang.kubeconfig
# 设置默认上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=aliang \
--kubeconfig=aliang.kubeconfig
# 设置当前使用配置-这一步是必须的否则报未指定8080端口错误
kubectl config use-context kubernetes --kubeconfig=aliang.kubeconfig
# 查看pod
kubectl get pod --kubeconfig=aliang.kubeconfig # 没有授予访问权限
Error from server (Forbidden): pods is forbidden: User "aliang" cannot list resource "pods" in API group "" in the namespace "default"
创建RBAC策略
创建角色(权限集合)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # api组,例如apps组,空值表示是核心API组,像namespace、pod、service、pv、pvc都在里面
resources: ["pods"] #资源名称(复数),例如pods、deployments、services
verbs: ["get", "watch", "list"] # 资源操作方法
将用户与角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User # 主体
name: aliang # 主体名称
apiGroup: rbac.authorization.k8s.io
roleRef: # 绑定的角色
kind: Role
name: pod-reader # 角色名称
apiGroup: rbac.authorization.k8s.io
指定kubeconfig文件测试权限
kubectl get pod --kubeconfig=aliang.kubeconfig
认证流程
2、cka真题-服务账号
题目
环境:
kubectl config use-context k8s
Context:
为部署管道创建一个新的ClusterRole并将其绑定到范围为特定的namespace的特定的ServiceAccount。
Task:
创建一个名为deployment-clusterrole且仅允许创建一下资源类型的新的ClusterRole:
Deployment
StatefulSet
DaemonSet
现有namespace app-team1中创建一个名为cicd-token的新的ServiceAccount。
限于namespace app-team1,将新的ClusterRole deployment-clusterrole绑定到新的ServiceAccount cicd-token
解
命令创建
# 创建clusterrole
kubectl create clusterrole deployment-clusterrole --verb=create --resource=Deployment,StatefulSet,DaemonSet
# app-team1名称空间创建SA
kubectl create serviceaccount cicd-token -n app-team1
# 创建RoleBinding绑定clusterrole到SA
kubectl create rolebinding deployment-clusterrole-binding --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token -n app-team1
# 测试服务账号权限
kubectl --as=system:serviceaccount:app-team1:cicd-token \
get pods -n app-team1
yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-token
namespace: app-team1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-clusterrole
rules:
- apiGroups: ["","apps"]
resources: ["pods","deployments","daemonsets","statefulsets"]
verbs: ["create","get","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployment-clusterrole-binding
namespace: app-team1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deployment-clusterrole
subjects:
- kind: ServiceAccount
name: cicd-token
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/
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
案例1:拒绝其他命名空间Pod访问
准备环境:
附:准备环境快捷命令
kubectl run busybox --image=busybox -n test -- sleep 12h
kubectl run web --image=nginx -n test
kubectl exec busybox -n test -- ping 10.244.169.169
需求:test命名空间下所有pod可以互相访问,也可以访问其他命名空间Pod,但其他命名空间不能访问test命名空间Pod。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-other-pod-policy
namespace: test
spec:
podSelector: {} # 空,本命名空间下所有的pod添加策略
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # 空,本命名空间下所有的pod
案例2:同一个命名空间下应用之间限制访问
需求:将test命名空间携带run=web标签的Pod隔离,只允许test命名空间携带run=client1标签的Pod访问80端口
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-selector-pod-policy
namespace: test
spec:
podSelector:
matchLabels:
run: web # 当前名称空间下具有run=web标签的pod添加策略
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
run: client1 # 本名称空间下有run=client1标签的pod访问
ports:
- protocol: TCP
port: 80 # 访问80端口
k label pod/busybox -n test --overwrite run=client1
k exec busybox -n test -- telnet 10.244.169.169 80
案例3:只允许指定命名空间中的应用访问
需求:只允许dev命名空间中的Pod访问test命名空间中的pod 80端口
命名空间打标签: kubectl label namespace dev name=dev
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-ns-pod-policy
namespace: test
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: dev
ports:
- protocol: TCP
port: 80 # 访问80端口