在 istio 中使用 namespace 进行资源/租户隔离
PaaS 场景中,需要在集群中给客户提供容器部署他们自己开发的代码,如果使用 命名空间 来表示租户,则需要有效隔离租户,让隔壁的租户无法访问本租户的资源。下面的一些策略可以用来实现这种能力。
实验准备
计划部署 2 个租户,tn1 和 tn2,分别部署 httpbin 服务端应用和 wget 测试工具。
以下代码可以直接拷贝食用:
apiVersion: v1
kind: Namespace
metadata:
name: tn1
labels:
name: tn1
spec:
finalizers:
- kubernetes
---
apiVersion: v1
kind: Namespace
metadata:
name: tn2
labels:
name: tn2
spec:
finalizers:
- kubernetes
---
# 在 tn1 中部署 httpbin
apiVersion: v1
kind: Service
metadata:
name: httpbin
namespace: tn1
labels:
app: httpbin
tenant: tn1
spec:
ports:
- port: 80
name: http
selector:
app: httpbin
tenant: tn1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: tn1
labels:
app: httpbin
tenant: tn1
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
tenant: tn1
template:
metadata:
labels:
app: httpbin
tenant: tn1
spec:
containers:
- image: kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
protocol: TCP
---
# 在 tn2 中部署 httpbin
apiVersion: v1
kind: Service
metadata:
name: httpbin
namespace: tn2
labels:
app: httpbin
tenant: tn2
spec:
ports:
- port: 80
name: http
selector:
app: httpbin
tenant: tn2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: tn2
labels:
app: httpbin
tenant: tn2
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
tenant: tn2
template:
metadata:
labels:
app: httpbin
tenant: tn2
spec:
containers:
- image: kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
protocol: TCP
---
# 分别在两个命名空间中部署 alpine/wget 测试程序
apiVersion: apps/v1
kind: Deployment
metadata:
name: wget
namespace: tn1
spec:
replicas: 1
selector:
matchLabels:
app: wget
template:
metadata:
labels:
app: wget
spec:
containers:
- image: alpine
imagePullPolicy: IfNotPresent
name: wget
command: ["tail", "-f", "/dev/null"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wget
namespace: tn2
spec:
replicas: 1
selector:
matchLabels:
app: wget
template:
metadata:
labels:
app: wget
spec:
containers:
- image: alpine
imagePullPolicy: IfNotPresent
name: wget
command: ["tail", "-f", "/dev/null"]
使用 NetworkPolicy 隔离命名空间网络
如果要在 k8s 中使用 NetworkPolicy,需要安装相应的网络组件,在腾讯云 TKE 中,建议安装 kube-router ,只启用其中的 firewall 功能,用于实现 NetworkPolicy。kube-router 是腾讯云 TKE 官方建议的网络插件。
在腾讯云 TKE 上安装 kube-router 请参考这篇文章:https://cloud.tencent.com/developer/article/1583707
1、禁止非当前命名空间的 pod 访问(不同租户之间不能横向穿透)
apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
name: deny-others
namespace: tn1
spec:
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
测试结果
# 在 tn1 的 wget 上测试
# wget -qSO- http://httpbin.tn1/headers
HTTP/1.1 200 OK
server: envoy...
# wget -qSO- http://httpbin.tn2/headers
HTTP/1.1 200 OK
server: envoy...
# 在 tn2 的 wget 上测试
# wget -qSO- http://httpbin.tn1/headers
wget: cant connect to remote host (172.24.253.145): Connection refused...
# wget -qSO- http://httpbin.tn2/headers
HTTP/1.1 200 OK
server: envoy...
2、设置租户之间的东西向访问白名单
在某些情况下,需要让某些租户之间互访,如:同一个公司申请了多个租户。这个也可以是用 NetworkPolicy 来实现。
下面的例子指定了命名空间 tn1 和 tn2 中的 pod 可以访问 tn1 下的 pod,配置如下:
apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
name: deny-others
namespace: tn1
spec:
ingress:
- from:
- namespaceSelector:
matchLabels:
name: tn1
- namespaceSelector:
matchLabels:
name: tn2
podSelector: {}
policyTypes:
- Ingress
注意:以上配置在 tke 1.16 和 kube-router 0.2.4,并且没有自动注入 sidecar 的情况下测试通过。
目前 kube-router 测试在 istio 中测试有 bug。
建议在纯的 K8S 环境下使用 NetworkPoclicy ,在 Istio 中使用 AuthorizationPolicy,这将在下一节中探讨。
附:在 TKE 安装最新版的 kube-router
可以基于官网的配置 https://github.com/cloudnativelabs/kube-router/blob/master/daemonset/kube-router-firewall-daemonset.yaml 需要修改配置文件的地址,具体有:
- 文件名 10-kuberouter.conflist 修改为 10-kuberouter.conf (?)
- /var/lib/kube-router/kubeconfig 修改为 /root/.kube/config
使用 Istio AuthorizationPolicy 隔离资源
使用 istio 的认证策略,前提是有 sidecar。下面的例子中,需要在 namespace 中增加 label: “istio-injection: enabled ”。
禁止命名空间内的 pod 被访问
下面的配置定义了 tn1 中的pod无法被访问:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: tn1
spec:
{}
上述配置,在所有的 pod 无法都访问 tn1 里的服务,他限制了所有的流量:
# wget -qSO- httpbin.tn1/get
HTTP/1.1 403 Forbidden
wget: server returned error: HTTP/1.1 403 Forbidden
租户间横向打通
通过 AuthorizationPolicy 可以轻松对命名空间进行配置:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: tn1
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ['tn1']
上面的配置放开了 tn1 命名空间内的 pod 对 本命名空间的访问。如果需要打通更多指定的命名空间,只需要将相应的名字加入 配置中即可。
更精细的控制
使用 AuthorizationPolicy ,可以针对 http 的 url,method 进行更精细的控制,下面的例子中,仅仅租户 tn1 的 /get api 才允许被 tn2 访问:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: tn1
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ['tn1']
- from:
- source:
namespaces: ['tn2']
to:
- operation:
methods: ["GET"]
paths: ["/get"]
更详细的权限控制可以参考官方文档:https://istio.io/latest/docs/reference/config/security/authorization-policy/
在 istio 中开放出口流量白名单
在本小节,我们尝试使用 istio 中的 ServiceEntry 来完成对指定命名空间的的出集群流量控制。
场景:在 istio 集群中,需要使用 namespace 来隔离资源,为特定 namespace 开放集群外访问白名单。
在 istio 的 Service Entry 文档中,我们可以找到相关的功能,关键字是 exportTo,以下是试验过程:
首先将 Istio 集群的外部访问设置为 REGISTRY_ONLY(修改 ConfigMap 的 istio 配置),腾讯云 TCM 可以直接在控制台设置。
outboundTrafficPolicy:
mode: REGISTRY_ONLY
创建 Service Entry,开放 tn1 命名空间对 baidu 的访问权限。
代码如下:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: baidu-external
namespace: tn1
spec:
hosts:
- www.baidu.com
exportTo:
- "."
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS
location: MESH_EXTERNAL
通过测试:
1 带有 sidecar 的 tn1 命名空间下的 pod 可以访问 (没有 sidecar 的 pod 也可以访问 )。
# wget -qSO- https://www.baidu.com
HTTP/1.1 200 OK
Content-Length: 2443
Content-Type: text/html
Server: bfe
Date: Wed, 05 Aug 2020 08:09:24 GMT
Connection: close
<!DOCTYPE html>
...
2 带有 sidecar 的 其他命名空间下的 pod 不可以访问
# wget -qSO- https://www.baidu.com
ssl_client: www.baidu.com: handshake failed: unexpected EOF
wget: error getting response: Connection reset by peer
达到访问外部资源隔离的目的。
上面的配置中,起到关键作用的是 namespace 和 exportTo 两项配置。
按照官方文档:当前 exportTo 只可以为 “.” 或 “*”,分别对应着 当前命名空间 和 所有命名空间 有效。
- ASP.NET Core的配置(1):读取配置信息
- 权限管理和备份实例
- “协变”、“逆变”与Delegate类型转换
- 如今的人工智能是不是真的已经很聪明了?
- 【Scikit-Learn 中文文档】聚类 - 无监督学习 - 用户指南 | ApacheCN
- Delegate如何进行类型转换?
- 个性化推荐系统(一)---今日头条等的内容划分、分类
- ASP.NET Core的配置(2):配置模型详解
- 如何解决jQuery Validation针对动态添加的表单无法工作的问题?
- 数据结构 链表改进
- 数据结构 栈&队列
- 终端品牌域名过期被拍卖 价值六位数
- TensorFlow 深度学习笔记 TensorFlow实现与优化深度神经网络
- ASP.NET的路由系统:路由映射
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?
- 原创 | codefroces中的病毒,这题有很深的trick,你能解开吗?
- 原创 | git的远程分支是干啥的,和本地的有什么区别?
- 京东技术主导:全新架构的分布式事务Hmily 2.1.1发布
- iOS音视频接入-TRTC接入前期key、秘钥等准备
- 你一定不知道的 Linux 使用技巧
- 当 Python 爬虫搭配起 Bilibili 唧唧,奇怪的生产力出现了
- 一个简单的小技巧,监控网页所有动态标签创建的调用处
- SAP Spartacus storefrontapp index.html的design time和runtime
- OS开发爱好者福利来了:树莓派上编译C语言,顺便掌握一波硬件知识
- 一个简单易用的图标字体库和CSS框架fontawesome
- OLAP 数据平台 Druid 第一步,编写 Spec 配置
- 搭建 Kubernetes 集群 Dashboard 2.0+ 可视化插件
- Kubernetes 集群基本概念
- 未能幸免!安全容器也存在逃逸风险