Control Egress Traffic task 演示了在服务网格内的应用如何访问外部(k8s集群外)的HTTP和HTTPS服务。快速提醒:默认情况下,启用Istio的应用不能访问集群外部的URL。为了启用这种访问,必须定义 ServiceEntry ,或者必须经过配置 direct access to external services (直接访问外部服务)。
TLS Origination for Egress Traffic task示范了如何允许应用在外部服务需要HTTPS的时候发送HTTP请求。
这个task展示如何配置Istio以通过被称为 Egress Gateway 的专用服务来引导egress流量。我们实现了与TLS Origination for Egress Traffic task中相同的功能,只是这次我们通过增加egress gateway来完成。
Use case
考虑一个组织有严格的安全需求。根据这些需求,离开服务网格的所有流量必须流经一组专用节点。这些节点将运行在专用机器上,与用于在集群中运行应用的其余节点分开运行。特殊节点将用于出口流量的策略执行,并且将比其他节点更加彻底地进行监控。
Istio 0.8引入了ingress和egress网关地概念( ingress and egress gateways)。Ingress网关允许你定义所有入站流量流经地服务网格的入口点。Egress 网关是一个对称的概念,它定义了网格的出口点。egress网关允许Istio功能(例如监控和路由规则)应用于网格的出站流量。
另一个用例是应用程序节点没有公共IPs的集群,因此运行在网格内的服务无法访问Internet。定义egress网关,引导所有出口流量通过egress网关,并将公网IP分配给出口网关节点,允许应用节点以受控方式访问外部服务。
Before you begin
- 安装Istio
- 启动 sleep 示例应用,作为外部调用的测试源。
如果你开启了自动注入sidecar,执行
kubectl apply -f samples/sleep/sleep.yaml
否则,你不得不在部署sleep 应用前手动注入sidecar:
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
注意: 任何你能 curl 和exec 的pod都可以。
- 创建一个shell变量来保存将请求发送到外部服务的源pod的名称。如果我们使用sleep例子,我们运行:
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
Define an egress Gateway and direct HTTP traffic through it
首先让我们管理没有创建TLS的HTTP流量。
1.Ϊ edition.cnn.com 创建一个egress Gateway
,端口80:
cat <<EOF | istioctl create -f - kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "edition.cnn.com" EOF
2.Ϊ edition.cnn.com
定义一个ServiceEntry
,和一个管理通过egress网关流量的VirtualService
:
cat <<EOF | istioctl create -f - apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: cnn spec: hosts: - edition.cnn.com ports: - number: 80 name: http-port protocol: HTTP - number: 443 name: https protocol: HTTPS resolution: DNS --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-through-egress-gateway spec: hosts: - edition.cnn.com gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 80 weight: 100 - match: - gateways: - istio-egressgateway port: 80 route: - destination: host: edition.cnn.com port: number: 80 weight: 100 EOF
3.向 http://edition.cnn.com/politics
发送一个HTTP请求。
kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 301 Moved Permanently ... location: https://edition.cnn.com/politics ... HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 ... Content-Length: 151654 ...
输出应该和 TLS Origination for Egress Traffic task中,没有创建TLS的输出相同。
4.检查 istio-egressgateway pod 的日志,看到与我们请求相对应的一行。如果istio部署在命名空间 istio-system
中,打印日志的命令是:
kubectl logs $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') egressgateway -n istio-system | tail
我们应该看到和我们请求相关的一行,类似下面:
[2018-06-14T11:46:23.596Z] "GET /politics HTTP/1.1" 301 - 0 0 3 1 "172.30.146.87" "curl/7.35.0" "ab7be694-e367-94c5-83d1-086eca996dae" "edition.cnn.com" "151.101.193.67:80"
注意,我们只将端口80的流量重定向到egress网关,到端口看443的HTTPS流量直接进入了 edition.cnn.com。
Let’s clean up
让我们在执行下一步前移除之前的定义:
istioctl delete gateway istio-egressgateway istioctl delete serviceentry cnn istioctl delete virtualservice direct-through-egress-gateway
Perform TLS origination with the egress Gateway
让我们使用egress Gateway 执行创建TLS,和 TLS Origination for Egress Traffic task相同。注意在这个情况下,TLS创建将由egress网关服务器完成,而不是之前task中的sidecar进行。
1.Ϊ edition.cnn.com 创建一个egress Gateway
,端口443:
cat <<EOF | istioctl create -f - kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: http-port-for-tls-origination protocol: HTTP hosts: - "edition.cnn.com" EOF
2.Ϊ edition.cnn.com
定义一个ServiceEntry
,和一个管理通过egress网关流量的VirtualService
:
cat <<EOF | istioctl create -f - apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: cnn spec: hosts: - edition.cnn.com ports: - number: 80 name: http-port protocol: HTTP - number: 443 name: http-port-for-tls-origination protocol: HTTP resolution: DNS --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-through-egress-gateway spec: hosts: - edition.cnn.com gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 443 weight: 100 - match: - gateways: - istio-egressgateway port: 443 route: - destination: host: edition.cnn.com port: number: 443 weight: 100 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-tls-for-edition-cnn-com spec: host: edition.cnn.com trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com EOF
3.向 http://edition.cnn.com/politics
发送一个HTTP请求。
kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 200 OK ... content-length: 150793 ...
输出应该和 TLS Origination for Egress Traffic task中,创建TLS的输出相同:没有 301 Moved Permanently 信息。
4.检查 istio-egressgateway pod 的日志,看到与我们请求相对应的一行。如果istio部署在命名空间 istio-system
中,打印日志的命令是:
kubectl logs $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') egressgateway -n istio-system | tail
我们应该看到和我们请求相关的一行,类似下面:
"[2018-06-14T13:49:36.340Z] "GET /politics HTTP/1.1" 200 - 0 148528 5096 90 "172.30.146.87" "curl/7.35.0" "c6bfdfc3-07ec-9c30-8957-6904230fd037" "edition.cnn.com" "151.101.65.67:443"
Additional security considerations
注意,在Istio中定义egress网关本身并不会为egress网关服务运行的节点提供任何特殊处理。集群管理员或者云提供商需要在专用节点上部署egress网关,并引入其他安全措施,以使这些节点比网格中的其余部分更安全。
另外请注意,Istio本身并不能安全地强制所有egress流量实际上流经egress网关,Istio只能通过它的sidecar代理来实现这种流量控制。如果恶意应用会攻击附属于应用pod的sidecar代理,则它可能会绕过sidecar代理。绕过sidecar代理后,恶意应用可能尝试绕过egress网关离开服务网格,以逃避Istio的控制和监视。由集群管理员和云提供商强制确保没有流量绕过egress网关离开网格。这种强制性必须由Istio的外部机制执行。例如,防火墙可以拒绝来源不是egress网关的所有流量。 Kubernetes network policies 还可以禁止所有不属于egress网关的出口流量。另一种可能的安全措施涉及配置网络,使得应用节点无法访问互联网,这样就无需通过网关监控和控制出口流量。这种网络配置的例子是专门将公共IPs分配给网关。
Cleanup
1.移除我们之前创建的Istio配置记录:
istioctl delete gateway istio-egressgateway istioctl delete serviceentry cnn istioctl delete virtualservice rewrite-port-for-edition-cnn-com istioctl delete destinationrule originate-tls-for-edition-cnn-com
2.关闭sleep服务:
kubectl delete -f samples/sleep/sleep.yaml