入口访问控制
本任务演示如何使用授权策略在 Istio 入站网关上实施基于 IP 的访问控制。
开始之前
在开始此任务之前,请执行以下操作
阅读 Istio 授权概念。
使用 Istio 安装指南 安装 Istio。
在命名空间
foo
中部署工作负载httpbin
,并启用 sidecar 注射。$ kubectl create ns foo $ kubectl label namespace foo istio-injection=enabled $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n foo
通过入站网关公开
httpbin
。
使用以下命令验证
httpbin
工作负载和入站网关是否按预期工作$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200
将流量导入 Kubernetes 和 Istio
所有将流量导入 Kubernetes 的方法都涉及在所有工作节点上打开一个端口。实现此目的的主要功能是NodePort
服务和LoadBalancer
服务。即使是 Kubernetes Ingress
资源也必须由一个 Ingress 控制器支持,该控制器将创建NodePort
或LoadBalancer
服务。
NodePort
只是在每个工作节点上打开 30000-32767 范围内的端口,并使用标签选择器来识别要将流量发送到的 Pod。您必须手动在工作节点前面创建某种负载均衡器或使用轮循 DNS。LoadBalancer
就像NodePort
一样,但它还会创建一个环境特定的外部负载均衡器来处理将流量分发到工作节点。例如,在 AWS EKS 中,LoadBalancer
服务将创建一个 Classic ELB,并将您的工作节点作为目标。如果您的 Kubernetes 环境没有LoadBalancer
实现,那么它将表现得像NodePort
一样。Istio 入站网关创建LoadBalancer
服务。
如果处理来自NodePort
或LoadBalancer
流量的 Pod 未在接收流量的工作节点上运行会怎样?Kubernetes 有自己的内部代理称为 kube-proxy,它接收数据包并将它们转发到正确的节点。
原始客户端的源 IP 地址
如果数据包通过外部代理负载均衡器和/或 kube-proxy,则客户端的原始源 IP 地址将丢失。以下小节描述了一些策略,用于为不同负载均衡器类型保留原始客户端 IP 以用于日志记录或安全目的。
作为参考,以下是在流行的托管 Kubernetes 环境中,Istio 使用LoadBalancer
服务创建的负载均衡器类型。
云提供商 | 负载均衡器名称 | 负载均衡器类型 |
---|---|---|
AWS EKS | 经典弹性负载均衡器 | TCP 代理 |
GCP GKE | TCP/UDP 网络负载均衡器 | 网络 |
Azure AKS | Azure 负载均衡器 | 网络 |
IBM IKS/ROKS | 网络负载均衡器 | 网络 |
DO DOKS | 负载均衡器 | 网络 |
TCP/UDP 代理负载均衡器
如果您使用的是 TCP/UDP 代理外部负载均衡器(AWS Classic ELB),它可以使用 PROXY 协议 将原始客户端 IP 地址嵌入到数据包数据中。外部负载均衡器和 Istio 入站网关必须都支持 PROXY 协议才能使其工作。
这是一个示例配置,它演示了如何在 AWS EKS 上使入站网关支持 PROXY 协议。
网络负载均衡器
如果您使用的是保留客户端 IP 地址的 TCP/UDP 网络负载均衡器(AWS 网络负载均衡器、GCP 外部网络负载均衡器、Azure 负载均衡器)或使用轮循 DNS,则可以使用externalTrafficPolicy: Local
设置在 Kubernetes 内部保留客户端 IP,方法是绕过 kube-proxy 并阻止它将流量发送到其他节点。
更新入站网关以设置externalTrafficPolicy: Local
,以便在入站网关上保留原始客户端源 IP,请使用以下命令
HTTP/HTTPS 负载均衡器
如果您使用的是 HTTP/HTTPS 外部负载均衡器(AWS ALB、GCP),它可以将原始客户端 IP 地址放入 X-Forwarded-For 标头中。Istio 可以通过一些配置从该标头中提取客户端 IP 地址。请参阅 配置网关网络拓扑。如果在 Kubernetes 前面使用单个负载均衡器,则可以使用以下快速示例
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogEncoding: JSON
accessLogFile: /dev/stdout
defaultConfig:
gatewayTopology:
numTrustedProxies: 1
基于 IP 的允许列表和拒绝列表
何时使用ipBlocks
与remoteIpBlocks
:如果您使用 X-Forwarded-For HTTP 标头或 PROXY 协议来确定原始客户端 IP 地址,则应在您的AuthorizationPolicy
中使用remoteIpBlocks
。如果您使用externalTrafficPolicy: Local
,则应在您的AuthorizationPolicy
中使用ipBlocks
。
负载均衡器类型 | 客户端 IP 的来源 | ipBlocks 与remoteIpBlocks |
---|---|---|
TCP 代理 | PROXY 协议 | remoteIpBlocks |
网络 | 数据包源地址 | ipBlocks |
HTTP/HTTPS | X-Forwarded-For | remoteIpBlocks |
- 以下命令创建 Istio 入站网关的授权策略
ingress-policy
。以下策略将action
字段设置为ALLOW
,以允许ipBlocks
中指定的 IP 地址访问入站网关。列表中不存在的 IP 地址将被拒绝。ipBlocks
支持单个 IP 地址和 CIDR 表示法。
验证对入站网关的请求是否被拒绝
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403
将您的原始客户端 IP 地址分配给一个环境变量。如果您不知道它,您可以使用以下命令在 Envoy 日志中找到它
- 更新
ingress-policy
以包含您的客户端 IP 地址
验证对入站网关的请求是否被允许
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200
更新
ingress-policy
授权策略以将action
键设置为DENY
,以便ipBlocks
中指定的 IP 地址不允许访问入站网关
验证对入站网关的请求是否被拒绝
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403
您可以使用在线代理服务使用不同的客户端 IP 访问入站网关,以验证请求是否被允许。
如果您没有获得预期的响应,请查看入站网关日志,其中应显示 RBAC 调试信息
清理
- 删除授权策略
删除命名空间
foo
$ kubectl delete namespace foo