概述

首先需要了解这三种机制的区别:

  • 认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证,
  • 授权(Authorization)是对资源的授权,k8s中的资源无非是容器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个pod),授权检查都会通过访问策略比较该请求上下文的属性,(比如用户,资源和Namespace),根据授权规则判定该资源(比如某namespace下的pod)是否是该客户可访问的。
  • 准入(Admission Control)机制是一种在改变资源的持久化之前(比如某些资源的创建或删除,修改等之前)的机制。
    在k8s中,这三种机制如下图:
    k8s-authorition
    k8s-authorition
    k8s的整体架构也是一个微服务的架构,所有的请求都是通过一个GateWay,也就是kube-apiserver这个组件(对外提供REST服务),由图中可以看出,k8s中客户端有两类,一种是普通用户,一种是集群内的Pod,这两种客户端的认证机制略有不同,后文会详述。但无论是哪一种,都需要依次经过认证,授权,准入这三个机制。
    截图来自华为CCE云课堂
    截图来自华为CCE云课堂

kubernetes 中的认证机制

需要注意的是,kubernetes虽然提供了多种认证机制,但并没有提供user 实体信息的存储,也就是说,账户体系需要我们自己去做维护。当然,也可以接入第三方账户体系(如谷歌账户),也可以使用开源的keystone去做整合。kubernetes 支持多种认证机制,可以配置成多个认证体制共存,这样,只要有一个认证通过,这个request就认证通过了。下面列举的是官网几种常见认证机制:

  • X509 Client Certs
  • Static Token File
  • Bootstrap Tokens
  • Static Password File
  • Service Account Tokens
  • OpenID Connect Tokens

这里我主要还是理解一下常用认证方式:

X509 Client Certs

也叫作双向数字证书认证,HTTPS证书认证,是基于CA根证书签名的双向数字证书认证方式,是所有认证方式中最严格的认证。默认在kubeadm创建的集群中是enabled的,可以在master node上查看kube-apiserver的pod配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ cat /usr/lib/systemd/system/kube-apiserver.service
..........
..........

ExecStart=/usr/local/bin/kube-apiserver \
--v=2 \
--logtostderr=true \
--allow-privileged=true \
--bind-address=0.0.0.0 \
--secure-port=6443 \
--insecure-port=0 \
--advertise-address=192.168.56.110 \
--service-cluster-ip-range=10.96.0.0/12 \
--service-node-port-range=30000-32767 \
--etcd-servers=https://192.168.56.111:2379,https://192.168.56.112:2379,https://192.168.56.113:2379 \
--etcd-cafile=/etc/etcd/ssl/etcd-ca.pem \
--etcd-certfile=/etc/etcd/ssl/etcd.pem \
--etcd-keyfile=/etc/etcd/ssl/etcd-key.pem \
--client-ca-file=/etc/kubernetes/pki/ca.pem \
--tls-cert-file=/etc/kubernetes/pki/apiserver.pem \
--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem \
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver.pem \
--kubelet-client-key=/etc/kubernetes/pki/apiserver-key.pem \
..........
..........

相关的三个启动参数:

  • client-ca-file: 指定CA根证书文件为/etc/kubernetes/pki/ca.pem
  • tls-private-key-file: 指定ApiServer私钥文件为/etc/kubernetes/pki/apiserver-key.pem
  • tls-cert-file:指定ApiServer证书文件为/etc/kubernetes/pki/apiserver.pem

请求中需要带有由该证书签名的证书,才能认证通过,客户端签署的证书里包含user,group信息,具体为证书的subject.CommonName(username)以及subject.Organization(group)

x509
x509

Service Account Tokens

Service Account Token 是一种比较特殊的认证机制,适用于上文中提到的pod内部服务需要访问apiserver的认证情况,默认enabled。
还是看上文中apiserver 的启动配置参数有–service-account-key-file,如果没有指明文件,默认使用–tls-private-key-file的值,即API Server的私钥。

ServiceAccount工作流程
ServiceAccount工作流程

通过控制器ServiceAccountController会去list,watch k8s apiserver对于命名空间的创建、删除;
就会在新创建的名称空间下创建一个名为”default”的service account;

TokenController 根据创建的ServiceAccount下面关联生成一个带有Token的secret。
Admission 是在通过认证进行鉴权的一个阶段,那么他会默认给当前名称空间下的pod打上,当前名称空间的那个ServiceAccount。

service accout本身是作为一种资源在k8s集群中,我们可以通过命令行获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ kubectl get sa --all-namespaces

NAMESPACE NAME SECRETS AGE
default default 1 16d
kube-system default 1 16d
kube-public default 1 16d
kube-system attachdetach-controller 1 16d
kube-system bootstrap-signer 1 16d
kube-system calico-node 1 16
...........
...........

$ kubectl describe serviceaccount/default -n kube-system
Name: default
Namespace: kube-system
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-q9s9l
Tokens: default-token-q9s9l
Events: <none>
$ kubectl get secret default-token-q9s9l -o yaml -n kube-system
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJ ...............略
namespace: a3ViZS1zeXN0ZW0=
token: ZXlKaGJHY2lPaUpTVX- ...............略
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: a5568634-f445-11e8-b4c4-000c295134cf
creationTimestamp: 2018-11-30T02:14:19Z
name: default-token-q9s9l
namespace: kube-system
resourceVersion: "337"
selfLink: /api/v1/namespaces/kube-system/secrets/default-token-q9s9l
uid: a56521fd-f445-11e8-aa44-000c29fe5618
type: kubernetes.io/service-account-token
[root@k8s-m1 kubelet]#

可以看到service-account-token的secret资源包含的数据有三部分:

  • ca.crt,这是API Server的CA公钥证书,用于Pod中的Process对API Server的服务端数字证书进行校验时使用的;
  • namespace,这是Secret所在namespace的值的base64编码:# echo -n “kube-system”|base64 => “a3ViZS1zeXN0ZW0=”
  • token:该token就是由service-account-key-file的值签署(sign)生成。

API Server的service account authentication(身份验证)

前面说过,service account为Pod中的Process提供了一种身份标识,在Kubernetes的身份校验(authenticating)环节,以某个service account提供身份的Pod的用户名为:

1
system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)

以上面那个kube-system namespace下的default service account为例,使用它的Pod的username全称为:

1
system:serviceaccount:kube-system:default

默认的service account

Kubernetes会为每个cluster中的namespace自动创建一个默认的service account资源,并命名为”default”.

如果Pod中没有显式指定spec.serviceAccount字段值(自定义Admission),那么Kubernetes会默认将该namespace下的default service account自动mount到在这个namespace中创建的Pod里,那这个操作就是通过上面所说的ServiceAccountAdmission来实现的。
我们以namespace “default”为例,我们查看一下其中的一个Pod的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ kubectl describe pod nginx-64f497f8fd-lkmdr
Name: nginx-64f497f8fd-lkmdr
Namespace: default
......
......
Containers:
......
......
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-d5d8g (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
......
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 27s default-scheduler Successfully assigned default/nginx-64f497f8fd-lkmdr to k8s-m3
Normal Pulling 17s kubelet, k8s-m3 pulling image "nginx"

可以看到,kubernetes将default namespace中的service account “default”的service account token挂载(mount)到了Pod中容器的/var/run/secrets/kubernetes.io/serviceaccount路径下。

深入容器内部,查看mount的serviceaccount路径下的结构:

1
2
3
4
5
6
$ kubectl exec nginx-64f497f8fd-lkmdr -- ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

# 这三个文件与上面提到的service account的token中的数据是一一对应的。

如何创建一个ServiceAccount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 通过命令行直接创建
$ kubectl create sa myk8ssa
serviceaccount/myk8ssa created
$ kubectl describe sa/myk8ssa
Name: mysa
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: mysa-token-kcwqm
Tokens: mysa-token-kcwqm
Events: <none>

# 如何使用?下面我在讨论

kubernetes 中的鉴权机制

目前,k8s 中一共有 4 种鉴权权限模式:

  • Node: 一种特殊目的的授权模式,主要用来让 kubernetes 遵从 node 的编排规则,实际上是 RBAC 的一部分,相当于只定义了 node 这个角色以及它的权限;
  • ABAC: Attribute-based access control;
  • RBAC: Role-based access control;
  • Webhook: 以 HTTP Callback 的方式,利用外部授权接口来进行权限控制;

这里我主要学习总结最常用的鉴权方式—RBAC
RBAC的鉴权策略可以利用 kubectl 或者 Kubernetes API 直接进行配置。RBAC 可以授权给用户,让用户有权进行授权管理,这样就可以无需接触节点,直接进行授权管理。RBAC 在 Kubernetes 中被映射为 API 资源和操作。

RBAC
RBAC

需要理解 RBAC 一些基础的概念和思路,RBAC 是让用户能够访问 Kubernetes API 资源的授权方式。

role
角色是一系列权限的集合,例如一个角色可以包含读取 Pod 的权限和列出 Pod 的权限, ClusterRole 跟 Role 类似,但是可以在集群中到处使用( Role 是 namespace 一级的)。
role binding
RoleBinding 把角色映射到用户,从而让这些用户继承角色在 namespace 中的权限。ClusterRoleBinding 让用户继承 ClusterRole 在整个集群中的权限。

另外还要考虑cluster rolescluster role binding。cluster role和cluster role binding方法跟role和role binding一样,出了它们有更广的scope。

Kubernetes中的RBAC
RBAC 现在被 Kubernetes 深度集成,并使用他给系统组件进行授权。System Roles 一般具有前缀system:,很容易识别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ kubectl get clusterroles --namespace=kube-system
NAME AGE
admin 16d
anonymous-dashboard-proxy-role 16d
calico-node 16d
calicoctl 16d
cluster-admin 16d
edit 16d
system:aggregate-to-admin 16d
system:aggregate-to-edit 16d
system:aggregate-to-view 16d
system:auth-delegator 16d
system:aws-cloud-provider 16d
system:basic-user 16d
system:certificates.k8s.io:certificatesigningrequests:nodeclient 16d
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 16d
system:controller:attachdetach-controller 16d
system:controller:certificate-controller 16d
system:controller:clusterrole-aggregation-controller 16d
system:controller:cronjob-controller 16d
system:controller:daemon-set-controller 16d
system:controller:deployment-controller 16d
system:controller:disruption-controller 16d
system:controller:endpoint-controller 16d
system:controller:expand-controller 16d
......略

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
$ cat >> role.yaml << EOF
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"] # 可用操作资源对象
verbs: ["get", "watch", "list"] # 对上面定义资源有哪些操作权限
EOF

$ cat >> rolebinding.yaml << EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: pod-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: mysa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
EOF

# 执行创建
$ kubectl create -f role.yaml
role.rbac.authorization.k8s.io/pod-reader created
$ kubectl create -f rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/pod-reader-binding created

[root@k8s-m1 ~]# kubectl get role
NAME AGE
pod-reader 36s
[root@k8s-m1 ~]# kubectl describe role pod-reader
Name: pod-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list]
$ kubectl describe rolebinding pod-reader-binding
Name: pod-reader-binding
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: pod-reader
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount mysa default

上面,

  1. 我定义了一个pod-reader的role,其中它的权限定义如上方定义的get,watch,list;
  2. 然后定义了一个pod-reader-binding的rolebinding
    前面提到过;用户通过认证之后就是鉴权,通过SA的认证方式之后拿到userinfo,然后绑定到role里面;那么此时对应的用户权限就是role里面定义的权限,subjects应用的对象类型也可以是User,Group;总之此时这一步就是获取到userinfo信息,然后通过角色绑定。相对应的权限就会赋予该用户。那用户从何而来?下面就需要创建一个用户来访问我们的集群了。

那如何使用我们自己创建的ServiceAccount来登录并且通过自定义的这个RBAC来鉴权呢?这就涉及到了kubeconfig文件生成的问题了

创建kubeconfig

获取上面已创建的ServiceAccount的Seter名称

这里我是在默认namespace下面创建的。

1
2
3
4
5
6
7
8
9
$ kubectl describe sa/myk8ssa
Name: myk8ssa
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: myk8ssa-token-2kntd
Tokens: myk8ssa-token-2kntd
Events: <none>

获取secret下的token,并base64解码获取token明文

1
2
3
$ token=`kubectl get secret myk8ssa-token-2kntd -oyaml |grep token: | awk '{print $2}' | xargs echo -n | base64 -d`
$ echo $token
eyJhbGciOiJSUzI1......略

新增用户guomaoqiu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ kubectl config set-cluster my-k8s --server=https://192.168.56.110:8443 \
--certificate-authority=/etc/kubernetes/pki/ca.pem \
--embed-certs=true
Cluster "my-k8s" set.

$ kubectl config set-credentials guomaoqiu --token=$token
User "guomaoqiu" set.

# 设置上下文
$ kubectl config set-context my-k8s --cluster=kubernetes
Context "my-k8s" created.

# 确认用户信息
$ kubectl config set-context my-k8s --user=guomaoqiu
Context "my-k8s" modified.

验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kubernetes-admin@kubernetes kubernetes kubernetes-admin
* my-k8s kubernetes guomaoqiu

# 将其设置为当前默认上下文:
$ kubectl config use-context my-k8s
Switched to context "my-k8s".

# 获取POD:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-64f497f8fd-4qdnt 1/1 Running 0 10m

# 尝试删除POD:
$ kubectl delete pod nginx-64f497f8fd-4qdnt
Error from server (Forbidden): pods "nginx-64f497f8fd-4qdnt" is forbidden: User "system:serviceaccount:default:myk8ssa" cannot delete pods in the namespace "default"

# 可见,该用户的的权限只有可读,而没有删除的权限;
# 说明配置是成功了的。

# 浏览一下当前我环境中有哪些kubeconfig?
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.110:8443
name: kubernetes
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.110:8443
name: my-k8s
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: guomaoqiu
name: my-k8s
current-context: my-k8s # 当前环境
kind: Config
preferences: {}
users:
- name: guomaoqiu
user:
token:......略
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED

通过namespace我们可以做到不同业务之间的隔离,如果再加上如上这种权限控制将会更加细化、以上实验主要是在默认的namespace下面操作,除此之外也可以新建namespace然后进行验证操作。kubeconfig切换上下文也是非常实用的一种功能。
常用命令:

1
2
3
4
5
6
7
8
kubectl - 使用kubectl来管理Kubernetes集群。
kubectl config set - 在kubeconfig配置文件中设置一个单独的值。
kubectl config set-cluster - 在kubeconfig配置文件中设置一个集群项。
kubectl config set-context - 在kubeconfig配置文件中设置一个环境项。
kubectl config set-credentials - 在kubeconfig配置文件中设置一个用户项。
kubectl config unset - 在kubeconfig配置文件中清除一个单独的值。
kubectl config use-context - 使用kubeconfig中的一个环境项作为当前配置。
kubectl config view - 显示合并后的kubeconfig设置,或者一个指定的kubeconfig配置文件。

kubernetes 中的准入机制

Kubernetes的Admission Control实际上是一个准入控制器(Admission Controller)插件列表,发送到APIServer的请求都需要经过这个列表中的每个准入控制器插件的检查,如果某一个控制器插件准入失败,就准入失败。
更多可查看: http://docs.kubernetes.org.cn/144.html
这里我们主要学习PodSecurityPolicy

安全上下文(Pod SecurityContext)

分为Pod级别和容器级别,容器级别的会覆盖Pod级别的相同设置。
在有PodSecurityPolicy策略的情况下,两者需要配合使用;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cat >> pod-security-policy.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
volumes:
- name: test
emptyDir: {}
containers:
- name: test-pod
image: alpine
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo The app is running! && sleep 36000']
volumeMounts:
- name: test
mountPath: /data/test
securityContext: # 设置容器安全上下文
readOnlyRootFilesystem: false # 容器文件系统是否是只读
privileged: false # 是否为特权容器
runAsUser: 1000 # 进程运行用户UID
EOF

# 执行创建:
$ kubectl create -f pod-security-policy.yaml
pod/test-pod created

# 进入容器验证:
$ kubectl exec -it test-pod sh
/ $ id
uid=1000 gid=0(root)
/ $ ps -ef
PID USER TIME COMMAND
1 1000 0:00 sleep 36000
6 1000 0:00 sh
15 1000 0:00 sh
21 1000 0:00 ps -ef
/ $ sysctl -w net.ipv4.tcp_recovery=2
sysctl: error setting key 'net.ipv4.tcp_recovery': Read-only file system
/ $

# 以上我设置限制了pod是否开启特权模式,并且运行用户uid为1000
# 那么如果在pod级别设置上下文的话,容器级别的会覆盖Pod级别的相同设置(已验证)

其他更多参数参见: https://kubernetes.io/docs/concepts/policy/pod-security-policy/

运行态的安全控制—网络策略(NetworkPolicy)

Kubernetes要求集群中所有pod,无论是节点内还是跨节点,都可以直接通信,或者说所有pod工作在同一跨节点网络,此网络一般是二层虚拟网络,称为pod网络。在安装引导kubernetes时,由选择并安装的network plugin实现。默认情况下,集群中所有pod之间、pod与节点之间可以互通。

网络主要解决两个问题,一个是连通性,实体之间能够通过网络互通。另一个是隔离性,出于安全、限制网络流量的目的,又要控制实体之间的连通性。Network Policy用来实现隔离性,只有匹配规则的流量才能进入pod,同理只有匹配规则的流量才可以离开pod。

但请注意,kubernetes支持的用以实现pod网络的network plugin有很多种,并不是全部都支持Network Policy,为kubernetes选择network plugin时需要考虑到这点,是否需要隔离?可用network plugin及是否支持Network Policy请参考这里

基本原理

Network Policy是kubernetes中的一种资源类型,它从属于某个namespace。其内容从逻辑上看包含两个关键部分,一是pod选择器,基于标签选择相同namespace下的pod,将其中定义的规则作用于选中的pod。另一个就是规则了,就是网络流量进出pod的规则,其采用的是白名单模式,符合规则的通过,不符合规则的拒绝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels: # 规则选择器,选择匹配的POD
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock: # 远端(访问端)IP白名单开放
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector: # 远端(访问端)namespaces白名单开放
matchLabels:
project: myproject
- podSelector: # 远端(访问端)Pod白名单开放
matchLabels:
role: frontend
ports: # 本端(被访问端)允许被访问的端口和协议
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP

对象创建方法与其它如ReplicaSet相同。apiVersion、kind、metadata与其它类型对象含义相同,不详细描述。

  • .spec.PodSelector
    顾名思义,它是pod选择器,基于标签选择与Network Policy处于同一namespace下的pod,如果pod被选中,则对其应用Network Policy中定义的规则。此为可选字段,当没有此字段时,表示选中所有pod。

  • .spec.PolicyTypes
    Network Policy定义的规则可以分成两种,一种是入pod的Ingress规则,一种是出pod的Egress规则。本字段可以看作是一个开关,如果其中包含Ingress,则Ingress部分定义的规则生效,如果是Egress则Egress部分定义的规则生效,如果都包含则全部生效。当然此字段也可选,如果没有指定的话,则默认Ingress生效,如果Egress部分有定义的话,Egress才生效。怎么理解这句话,下文会提到,没有明确定义Ingress、Egress部分,它也是一种规则,默认规则而非没有规则。

  • .spec.ingress与.spec.egress
    前者定义入pod规则,后者定义出pod规则,详细参考这里,这里只讲一下重点。上例中ingress与egress都只包含一条规则,两者都是数组,可以包含多条规则。当包含多条时,条目之间的逻辑关系是“或”,只要匹配其中一条就可以。.spec.ingress[].from
    也是数组,数组成员对访问pod的外部source进行描述,符合条件的source才可以访问pod,有多种方法,如示例中的ip地址块、名称空间、pod标签等,数组中的成员也是逻辑或的关系。spec.ingress[].from.prots表示允许通过的协议及端口号。

  • .spec.egress.to 定义的是pod想要访问的外部destination,其它与ingress相同。

kubernetes 默认NetworkPolicy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#默认禁止所有出口请求
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Egress

# 默认禁止所有入口请求
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress

# 默认允许所有出口请求
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress

# 默认允许所有入口请求
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Ingress

默认策略 无需详解,但请注意,pod与所运行节点之间流量不受Network Policy限制。

示例

下面通过一个真实示例展示Network Policy普通用法。

用Deployment创建nginx pod实例并用service暴露

1
2
3
4
$ kubectl run nginx --image=nginx --replicas=3
deployment.apps/nginx created
$ kubectl expose deployment nginx --port=80
service/nginx exposed

确认创建结果

1
2
3
4
5
6
7
8
9
$ kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-64f497f8fd-9mfd7 1/1 Running 0 2m
pod/nginx-64f497f8fd-nss94 1/1 Running 0 2m
pod/nginx-64f497f8fd-zs926 1/1 Running 0 2m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d
service/nginx ClusterIP 10.111.254.191 <none> 80/TCP 14s

测试nginx服务连通性

1
2
3
4
5
$  kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=3 nginx
Connecting to nginx (10.111.254.191:80) # 说明通的
/ #

通过创建Network Policy对象添加隔离性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ cat >> pod-network-policy.yaml << EOF
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels: # 默认该pod就有run=app这个标签了,我这里无需在从新定义
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
EOF

# 执行创建
$ kubectl create -f pod-network-policy.yaml
networkpolicy.networking.k8s.io/access-nginx created

# 查看具体隔离策略
$ kubectl describe networkpolicy access-nginx
Name: access-nginx
Namespace: default
Created on: 2018-12-17 01:16:57 -0500 EST
Labels: <none>
Annotations: <none>
Spec:
PodSelector: run=nginx
Allowing ingress traffic:
To Port: <any> (traffic allowed to all ports)
From:
PodSelector: access=true
Allowing egress traffic:
<none> (Selected pods are isolated for egress connectivity)
Policy Types: Ingress

测试隔离性

1
2
3
4
5
$ kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=3 nginx
Connecting to nginx (10.111.254.191:80)
wget: download timed out # 已经超时,说明已经不能访问了

为pod添加access: “true”标签后再次测试连通性

1
2
3
4
$ kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=3 nginx
Connecting to nginx (10.111.254.191:80)

参考:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
https://kubernetes.io/docs/reference/access-authn-authz/rbac/
https://kubernetes.io/docs/concepts/services-networking/network-policies/
https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
https://kubernetes.io/docs/concepts/policy/pod-security-policy/