我有一个多租户集群,其中多租户是通过命名空间实现的。每个租户都有自己的命名空间。来自租户的pod不能与其他租户的pod通信。但是,每个租户中的一些pod都必须使用入口将服务公开到Internet。
这是我走了多远(我正在使用Calico):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant1-isolate-namespace
namespace: tenant1
spec:
policyTypes:
- Ingress
podSelector: {} # Select all pods in this namespace
ingress:
- from:
- namespaceSelector:
matchLabels:
name: tenant1 # white list current namespace
为每个命名空间(tenant1
、tenant2
、…)部署,这限制了其命名空间内pod之间的通信。但是,这会阻止来自库贝-system
命名空间的pod与此命名空间中的pod通信。
但是,库贝-system
命名空间默认没有任何标签,因此我无法专门将此命名空间列入白名单。
我通过手动给它一个标签找到了解决此问题的(脏)方法:
kubectl label namespace/kube-system permission=talk-to-all
并将白名单规则添加到网络策略:
...
- from:
- namespaceSelector:
matchLabels:
permission: talk-to-all # allow namespaces that have the "talk-to-all privilege"
有没有更好的解决方案,而无需手动给库贝-system
一个标签?
编辑:我试图另外添加一个“或”规则,以专门允许来自标签为“app=nginx-ingress”的pod的通信,但运气不好:
- from
...
- podSelector:
matchLabels:
app: nginx-ingress # Allow pods that have the app=nginx-ingress label
ApiVersion:networking.k8s.io/v1
命名空间选择器旨在仅按标签匹配命名空间。无法按名称选择命名空间。
podSelector只能选择与NetworkPolicy对象位于同一命名空间中的pod。对于位于不同命名空间的对象,只能选择整个命名空间。
以下是库伯内特斯网络政策实施的示例:
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
按照这个链接阅读一个很好的解释网络政策的整个概念,或者这个链接观看讲座。
ApiVersion:projectcalico.org/v3
CalicoAPI为您提供了编写NetworkPolicy规则的更多选项,因此,在某些时候,您可以以更少的努力和令人震惊的方式实现您的目标。
例如,使用网络策略的Calico实现,您可以:
但是,您仍然只能通过标签匹配命名空间。
考虑阅读Calico留档了解详情。
以下是Calico网络策略实施的示例:
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-tcp-6379
namespace: production
spec:
selector: role == 'database'
types:
- Ingress
- Egress
ingress:
- action: Allow
protocol: TCP
source:
selector: role == 'frontend'
destination:
ports:
- 6379
egress:
- action: Allow
事实上,tenant1
pod将需要访问库贝-system
命名空间中的库贝-dns
。
一种不需要标记库贝-system
命名空间的方法是以下策略。尽管库贝-dns
可以在任何命名空间中使用这种方法,因此它可能不适合您。
---
# Default deny all ingress & egress policy, except allow kube-dns
# All traffic except this must be explicity allowed.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny-all-except-kube-dns
namespace: tenant1
spec:
podSelector: {}
egress:
- to:
- podSelector:
matchLabels:
k8s-app: kube-dns
- ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
policyTypes:
- Ingress
- Egress
然后,您还需要一个“允许所有名称空间策略”,如下所示:
---
# Allow intra namespace traffic for development purposes only.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-intra-namespace
namespace: tenant1
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
egress:
- to:
- podSelector: {}
policyTypes:
- Ingress
- Egress
最后,您需要添加特定的策略,例如入口规则。最好用特定的规则替换allo-intra-namespace
策略以适应单个pod,您的tenant1
可以做到这一点。
这些内容改编自本网站:https://github.com/ahmetb/kubernetes-network-policy-recipes
我使用默认法兰绒CNI的k3os。它在库贝-system命名空间上有默认标签:
$ kubectl describe ns kube-system
Name: kube-system
Labels: kubernetes.io/metadata.name=kube-system
Annotations: <none>
Status: Active
这对我有用:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
这是我的完整yaml,它允许所有外部流量和库贝-system命名空间中的库贝-dns用于egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-egress
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16