第8章:Kubernetes 安全

Kubernetes 安全

1. Kubernetes 安全框架

 

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

image

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:服务账号

image

4. 案例:为指定用户授权访问不同命名空间权限

示例:为aliang用户授权default命名空间Pod读取权限
1. 用K8S CA签发客户端证书
2. 生成kubeconfig授权文件
3. 创建RBAC权限策略

image

 

证书内容生成

[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
cert.sh

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
kubeconfig.sh

创建用户访问权限

[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
rbac.yaml

测试访问

把生成的 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
test-network-policy.yml
# 创建一个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: {}
deny-from-other-namespaces.yml
# 创建一个 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出入流量访问控制

posted @ 2020-08-20 11:06  元贞  阅读(294)  评论(0编辑  收藏  举报