一、ServiceEntry实战场景

1.1 部署 Istio 提供的 sleep 示例

[root@master01 ~]# cd /root/10/istio-1.20.8/
[root@master01 istio-1.20.8]# istioctl kube-inject -f samples/sleep/sleep.yaml 
#修改镜像为国内镜像
[root@master01 istio-1.20.8]# grep -rni "image:" samples/sleep/sleep.yaml 
55:        image: registry.cn-hangzhou.aliyuncs.com/github_images1024/curl:latest 

#应用
[root@master01 istio-1.20.8]# kubectl apply -f samples/sleep/sleep.yaml 

#验证
[root@master01 istio-1.20.8]# kg -f   samples/sleep/sleep.yaml 
NAME                   SECRETS   AGE
serviceaccount/sleep   1         42s

NAME            TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
service/sleep   ClusterIP   192.168.237.142   <none>        80/TCP    42s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/sleep   1/1     1            1           42s

1.2 部署 busybox

[root@master01 ~]# cd /root/10/istioyaml/
[root@master01 istioyaml]# vim busybox-dp.yaml
apiVersion: v1
kind: Service
metadata:
  name: busybox
spec:
  type: ClusterIP
  selector:
    app: httpd
  ports:
  - name: httpd
    port: 80
    targetPort: 80 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: busybox
        image: registry.cn-hangzhou.aliyuncs.com/abroad_images/busybox:1.28
        imagePullPolicy: IfNotPresent       
        command: ["/bin/sh","-c","echo 'this is busybox-httpd' > /var/www/index.html;httpd -f -h /var/www"]
        ports:
        - containerPort: 80

部署:

[root@master01 istioyaml]# kubectl apply -f busybox-dp.yaml

1.3 测试验证

[root@master01 istioyaml]# kubectl get pods | grep busybox
busybox-777955d56f-59vng                   2/2     Running   0               17s

# 使用sleep来访问外部服务
[root@master01 istioyaml]# kubectl get pods | grep sleep
sleep-5bb5cb8b67-m8m4g                     2/2     Running   0               6m9s

# 验证访问
[root@master01 istioyaml]# kubectl exec sleep-5bb5cb8b67-m8m4g  -- curl -sI http://www.baidu.com
HTTP/1.1 200 OK
accept-ranges: bytes
cache-control: private, no-cache, no-store, proxy-revalidate, no-transform
content-length: 277
content-type: text/html
date: Thu, 17 Apr 2025 07:32:22 GMT
etag: "575e1f59-115"
last-modified: Mon, 13 Jun 2016 02:50:01 GMT
pragma: no-cache
server: envoy
x-envoy-upstream-service-time: 30

# 使用sleep来访问busybox
[root@master01 istioyaml]# kubectl exec sleep-5bb5cb8b67-m8m4g  -- curl -sI http://busybox.default.svc.cluster.local
HTTP/1.1 200 OK
content-type: text/html
date: Thu, 17 Apr 2025 07:33:03 GMT
accept-ranges: bytes
last-modified: Thu, 17 Apr 2025 07:30:52 GMT
content-length: 22
x-envoy-upstream-service-time: 5
server: envoy

1.4 管理到外部服务的流量

# 定义资源
[root@master01 istioyaml]# vim httpbin-se.yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  ports:
  - number: 80                       # 访问http://httpbin.org
    name: http
    protocol: HTTP
  resolution: DNS                     # 使用DNS解析
  location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3  
kind: VirtualService
metadata:
  name: httpbin-ext
spec:
  hosts:
    - httpbin.org
  http:
  - timeout: 3s     # 设置调用外部服务 httpbin.org 的超时时间为3秒,即我调用外部服务后,如果3秒内未返回结果,即认为超时
    route:
      - destination:
          host: httpbin.org
        weight: 100

部署:

[root@master01 istioyaml]# kubectl apply -f httpbin-se.yaml

# 验证
[root@master01 istioyaml]# kg -f  httpbin-se.yaml
NAME                                           HOSTS             LOCATION        RESOLUTION   AGE
serviceentry.networking.istio.io/httpbin-ext   ["httpbin.org"]   MESH_EXTERNAL   DNS          15s

NAME                                             GATEWAYS   HOSTS             AGE
virtualservice.networking.istio.io/httpbin-ext              ["httpbin.org"]   15s

首先是 ServiceEntry 部分,它定义了一个名为 "httpbin-ext" 的服务入口。在该配置 中,指定了要访问的主机 "httpbin.org "。端口部分定义了一个端口号为80 的 HTTP 端 口。resolution 属性设置为 DNS,表示使用 DNS 解析进行主机解析。location 属性设 置为 MESH_EXTERNAL,表示该服务入口是在 Istio 所管理的外部网格之外。

接下来是 VirtualService 部分,它定义了一个名为 "httpbin-ext" 的虚拟服务。在该配置 中,hosts 属性指定了要路由的主机名即 "httpbin.org"。http 部分定义了一个超时为 3 秒的策略,并指定了路由目标为 "httpbin.org ",权重为100。

1.5 验证访问

# 当前能正常访问
[root@master01 istioyaml]# kubectl exec sleep-5bb5cb8b67-m8m4g  -- curl -sI http://httpbin.org
HTTP/1.1 200 OK
date: Thu, 17 Apr 2025 07:37:43 GMT
content-type: text/html; charset=utf-8
content-length: 9593
server: envoy
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 424

# 设置httpbin延迟5s后,返回结果,因为时间超过3秒了,故而会认为超时,504代表网关超时
[root@master01 istioyaml]# kubectl exec sleep-5bb5cb8b67-m8m4g -c sleep -- curl -sSI httpbin.org/delay/5
HTTP/1.1 504 Gateway Timeout
content-length: 24
content-type: text/plain
date: Thu, 17 Apr 2025 07:39:07 GMT
server: envoy

二、WorkloadEntry案例

2.1 Gateway

[root@master01 istioyaml]# vim gateway-3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'

部署:

[root@master01 istioyaml]# kaf gateway-3.yaml

#验证
[root@master01 istioyaml]# kg -f  gateway-3.yaml
NAME      AGE
gateway   5s

2.2 WorkloadEntry

[root@master01 istioyaml]# vim customers-we.yaml
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadEntry
metadata:
  name: details-vm-2
spec:
  address: 10.0.0.51 # 外部地址
  ports:
    number: 3000
  labels:
    app: details-legacy
    instance-id: vm1

部署:

[root@master01 istioyaml]# kubectl apply -f customers-we.yaml

# 验证
[root@master01 istioyaml]# kg -f customers-we.yaml
NAME           AGE   ADDRESS
details-vm-2   19s   10.0.0.51

2.3 ServiceEntry

[root@master01 istioyaml]# vim customers-se.yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: details-svc
spec:
  hosts:
  - details.zhang-qing.com
  location: MESH_INTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
    targetPort: 3000
  resolution: DNS
  workloadSelector:
    labels:
      app: details-legacy

部署:

[root@master01 istioyaml]# kubectl apply -f customers-se.yaml

# 验证
[root@master01 istioyaml]# kg -f  customers-se.yaml
NAME          HOSTS                        LOCATION        RESOLUTION   AGE
details-svc   ["details.zhang-qing.com"]   MESH_INTERNAL   DNS          2m9s

2.4 VirtualService

[root@master01 istioyaml]# vim customers-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ssdemo
spec:
  gateways:
  - gateway
  hosts:
  - '*'
  http:
  - match:
    - uri:
        prefix: /
    rewrite:
      uri: /
    route:
    - destination:
        host: details.zhang-qing.com # 对应上 ServiceEntry hosts的字段
        port:
          number: 80
    timeout: 300s

部署:

[root@master01 istioyaml]# kubectl apply -f customers-vs.yaml

# 验证
[root@master01 istioyaml]# kg -f customers-vs.yaml
NAME     GATEWAYS      HOSTS   AGE
ssdemo   ["gateway"]   ["*"]   30s

2.5 测试验证

10.0.0.51外部主机搭建grafana

#启动容器
[root@jenkins-01 ~]# docker run -d -p 3000:3000 registry.cn-hangzhou.aliyuncs.com/abroad_images/grafana:9.3.2

#查看容器
[root@jenkins-01 ~]# docker ps  | grep grafana
0339321f3a60        registry.cn-hangzhou.aliyuncs.com/abroad_images/grafana:9.3.2                      "/run.sh"                7 minutes ago       Up 7 minutes        0.0.0.0:3000->3000/tcp                                       beautiful_nobel

#验证
[root@jenkins-01 ~]# curl localhost:3000
<a href="/login">Found</a>.

测试验证

#10.0.0.51主机上进行测试
[root@jenkins-01 ~]# curl localhost:3000
<a href="/login">Found</a>.

#通过ServiceEntry引入Istio服务网格,details.zhang-qing.com需要提前做好域名映射,映射的IP地址为10.0.0.12
[root@master01 istioyaml]# curl -H "Host: details.zhang-qing.com" http://10.0.0.12

<a href="/login">Found</a>.

2.6 环境清理

[root@master01 istioyaml]# kubectl delete -f busybox-dp.yaml -f httpbin-se.yaml  -f gateway-3.yaml -f customers-we.yaml -f customers-se.yaml -f customers-vs.yaml -f customers-vs.yaml 

三、Sidecar实战场景

client 可以访问网格内 istio-system 和 default 名称空间下的所有 Service

apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: client
  namespace: default
spec:
  workloadSelector:
    labels:
      run: client
  egress:
    - hosts:
        - "./*"
        - "istio-system/*"

client 仅可以访问网格内的 proxy 服务,不能直接访问 demoapp 服务

apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: client
  namespace: default
spec:
  workloadSelector:
    labels:
      app: client
  outboundTrafficPolicy:
    mode: REGISTRY_ONLY
  egress:
    - port:
        number: 80
        protocol: HTTP
        name: proxy
      hosts:
        - "./*"

四、EnvoyFilter实战场景

Istio / Envoy Filter 案例

4.1 添加 HTTP 响应头

需求:在应用程序中添加 HTTP 响应头可以提高 Web 应用程序的安全性。本示例介绍如何通过定义 EnvoyFilter 添加HTTP 响应头。

#部署服务sleep
##通过服务sleep发起请求,调用服务helloworld的/hello完成相应功能的验证。
[root@master01 ~]# cd /root/10/istio-1.20.8/samples/
#3修改镜像为国内镜像
[root@master01 samples]# grep -rni "image:" sleep/sleep.yaml 
55:        image: registry.cn-hangzhou.aliyuncs.com/github_images1024/curl:latest 
##部署
[root@master01 samples]# kubectl apply -f sleep/sleep.yaml 
##验证
[root@master01 samples]# kubectl get -f sleep/sleep.yaml 
NAME                   SECRETS   AGE
serviceaccount/sleep   1         66m

NAME            TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
service/sleep   ClusterIP   192.168.237.142   <none>        80/TCP    66m

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/sleep   1/1     1            1           66m

#部署服务helloworld
##替换镜像为国内镜像
[root@master01 samples]# grep -rin "image:"  helloworld/helloworld.yaml 
36:        image: registry.cn-hangzhou.aliyuncs.com/abroad_images/examples-helloworld-v1:latest 
65:        image: registry.cn-hangzhou.aliyuncs.com/abroad_images/examples-helloworld-v2:latest 
##部署
[root@master01 samples]# kubectl apply -f helloworld/helloworld.yaml 
##验证
[root@master01 samples]# kubectl get -f helloworld/helloworld.yaml 
NAME                 TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
service/helloworld   ClusterIP   192.168.220.198   <none>        5000/TCP   74s

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/helloworld-v1   1/1     1            1           74s
deployment.apps/helloworld-v2   1/1     1            1           74s

#部署helloworld gateway
##部署
[root@master01 samples]# kubectl apply -f helloworld/helloworld-gateway.yaml
##验证
[root@master01 samples]# kubectl get -f helloworld/helloworld-gateway.yaml
NAME                                             AGE
gateway.networking.istio.io/helloworld-gateway   2m44s

NAME                                            GATEWAYS                 HOSTS   AGE
virtualservice.networking.istio.io/helloworld   ["helloworld-gateway"]   ["*"]   2m44s

HTTP 响应头:

OWASP(Open Web Application Security Project) 提供了最佳实践指南和编程框架,描述了如何使用安全响应头保护应用程序的安全。

HTTP 响应头的基准配置如下:

HTTP响应 头 默认值 描述
Content- Security- Policy frame-ancestors none; 防止其他网站进行 Clickjacking攻击。
X-XSS- Protection 1;mode=block 激活浏览器的XSS过 滤器(如果可用),检测到XSS时阻止渲 染。
X-Content- Type- Options Nosniff 禁用浏览器的内容嗅探。
Referrer- Policy no-referrer 禁用自动发送引荐来源。
X- Download- Options noopen 禁用旧版本IE中的自动打开下载功能。
X-DNS- Prefetch- Control off 禁用对页面上的外部链接的推测性DNS解析。
Server envoy 由Istio的入口网关自动设置。
X- Powered- by 无默认值 去掉该值来隐藏潜在 易受攻击的应用程序 服务器的名称和版本。
Feature- Policy camera ‘none’; microphone ‘none’;geolocation ‘none’;encrypted- media ‘none’;payment ‘none’;speaker ‘none’;usb ‘none’; 控制可以在浏览器中使用的功能和API。

创建 Envoyfilter:

[root@master01 ~]# cd /root/10/istioyaml/
[root@master01 istioyaml]# vim helloworld-ef.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ef-add-response-headers-into-sidecar
spec:
  workloadSelector:
    # select by label in the same namespace
    labels:
      app: helloworld
  configPatches:
    # The Envoy config you want to modify
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value: # lua filter specification
        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
          inlineCode: |-
            function envoy_on_response(response_handle)
                function hasFrameAncestors(rh)
                s = rh:headers():get("Content-Security-Policy");
                delimiter = ";";
                defined = false;
                for match in (s..delimiter):gmatch("(.-)"..delimiter) do
                    match = match:gsub("%s+", "");
                    if match:sub(1, 15)=="frame-ancestors" then
                    return true;
                    end
                end
                return false;
                end
                if not response_handle:headers():get("Content-Security-Policy") then
                csp = "frame-ancestors none;";
                response_handle:headers():add("Content-Security-Policy", csp);
                elseif response_handle:headers():get("Content-Security-Policy") then
                if not hasFrameAncestors(response_handle) then
                    csp = response_handle:headers():get("Content-Security-Policy");
                    csp = csp .. ";frame-ancestors none;";
                    response_handle:headers():replace("Content-Security-Policy", csp);
                end
                end
                if not response_handle:headers():get("X-Frame-Options") then
                response_handle:headers():add("X-Frame-Options", "deny");
                end
                if not response_handle:headers():get("X-XSS-Protection") then
                response_handle:headers():add("X-XSS-Protection", "1; mode=block");
                end
                if not response_handle:headers():get("X-Content-Type-Options") then
                response_handle:headers():add("X-Content-Type-Options", "nosniff");
                end
                if not response_handle:headers():get("Referrer-Policy") then
                response_handle:headers():add("Referrer-Policy", "no-referrer");
                end
                if not response_handle:headers():get("X-Download-Options") then
                response_handle:headers():add("X-Download-Options", "noopen");
                end
                if not response_handle:headers():get("X-DNS-Prefetch-Control") then
                response_handle:headers():add("X-DNS-Prefetch-Control", "off");
                end
                if not response_handle:headers():get("Feature-Policy") then
                response_handle:headers():add("Feature-Policy",
                                                "camera 'none';"..
                                                "microphone 'none';"..
                                                "geolocation 'none';"..
                                                "encrypted-media 'none';"..
                                                "payment 'none';"..
                                                "speaker 'none';"..
                                                "usb 'none';");
                end
                if response_handle:headers():get("X-Powered-By") then
                response_handle:headers():remove("X-Powered-By");
                end
            end

部署:

[root@master01 istioyaml]# kubectl apply -f helloworld-ef.yaml

# 验证
[root@master01 istioyaml]# kgf helloworld-ef.yaml
NAME                                   AGE
ef-add-response-headers-into-sidecar   4m47s

这是一个 Istio 的 EnvoyFilter 配置示例。它使用 Lua 过滤器来修改入站请求的响应头。

该示例配置了多个安全相关的响应头字段,如 Content-Security-Policy 、 X-Frame-Options 、 X-XSS-Protection 等,以增强应用程序的安全性。

这段 Lua 脚本会在收到响应后对响应头进行检查和修改。如果响应头中不存在Content-Security-Policy ,则添加一个设为 "frame-ancestors none;" 的 Content Security-Policy 头。如果响应头中存在 Content-Security-Policy 但没有"frame-ancestors",则在现有 Content-Security-Policy 头的末尾添加 "frame-ancestors none;"。

除此之外,这个配置中涉及的一些响应头字段及其作用:

  • Content-Security-Policy:用于控制资源加载策略,此处添加 "frame- ancestors none;" 来防止点击劫持。
  • X-Frame-Options:防止网页被嵌入到其他网页的框架中,设置为 "deny"。
  • X-XSS-Protection:启用浏览器的跨站脚本攻击(XSS)过滤器。
  • X-Content-Type-Options:防止浏览器尝试猜测响应内容的 MIME 类型。
  • Referrer-Policy:控制请求 header 中的 Referer 字段,在此设置为 "no- referrer",不发送 Referer 信息。
  • X-Download-Options:禁止浏览器直接打开下载文件,而是强制用户保存文件。 X-DNS-Prefetch-Control:禁止浏览器进行 DNS 预解析。
  • Feature-Policy:用于限制网页使用特定的功能,此处限制了相机、麦克风、地理位置等功能的使用。

该配置还会移除响应头中的 "X-Powered-By" 字段,以减少泄露信息的风险。还可以可 以帮助应用程序保护自身免受某些常见的安全风险,例如:点击劫持(clickjacking)、 跨站脚本攻击(XSS)、跨站点请求伪造(CSRF)等。

验证:

1)进入 sleep 服务容器内:

[root@master01 istioyaml]# kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}') -c sleep sh

2)调用 /hello 接口。接口响应头中包含额外添加的响应头,则说明创建的EnvoyFilter 生效。

~ $ curl -i helloworld:5000/hello

#回显内容
HTTP/1.1 200 OK
server: envoy
date: Thu, 17 Apr 2025 09:05:57 GMT
content-type: text/html; charset=utf-8
content-length: 60
x-envoy-upstream-service-time: 74
content-security-policy: frame-ancestors none;
x-frame-options: deny
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer
x-download-options: noopen
x-dns-prefetch-control: off
feature-policy: camera 'none';microphone 'none';geolocation 'none';encrypted-media 'none';payment 'none';speaker 'none';usb 'none';

4.2 Istio-ingress网关层面

让如上功能在 istio-ingress 网关层面生效:

[root@master01 istioyaml]# vim istio-ingress-rf.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ef-add-response-headers-into-ingressgateway
spec:
  workloadSelector:
    # select by label in the same namespace
    labels:
      istio: ingressgateway
  configPatches:
    # The Envoy config you want to modify
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value: # lua filter specification
        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
          inlineCode: |-
            function envoy_on_response(response_handle)
                function hasFrameAncestors(rh)
                s = rh:headers():get("Content-Security-Policy");
                delimiter = ";";
                defined = false;
                for match in (s..delimiter):gmatch("(.-)"..delimiter) do
                    match = match:gsub("%s+", "");
                    if match:sub(1, 15)=="frame-ancestors" then
                    return true;
                    end
                end
                return false;
                end
                if not response_handle:headers():get("Content-Security-Policy") then
                csp = "frame-ancestors none;";
                response_handle:headers():add("Content-Security-Policy", csp);
                elseif response_handle:headers():get("Content-Security-Policy") then
                if not hasFrameAncestors(response_handle) then
                    csp = response_handle:headers():get("Content-Security-Policy");
                    csp = csp .. ";frame-ancestors none;";
                    response_handle:headers():replace("Content-Security-Policy", csp);
                end
                end
                if not response_handle:headers():get("X-Frame-Options") then
                response_handle:headers():add("X-Frame-Options", "deny");
                end
                if not response_handle:headers():get("X-XSS-Protection") then
                response_handle:headers():add("X-XSS-Protection", "1; mode=block");
                end
                if not response_handle:headers():get("X-Content-Type-Options") then
                response_handle:headers():add("X-Content-Type-Options", "nosniff");
                end
                if not response_handle:headers():get("Referrer-Policy") then
                response_handle:headers():add("Referrer-Policy", "no-referrer");
                end
                if not response_handle:headers():get("X-Download-Options") then
                response_handle:headers():add("X-Download-Options", "noopen");
                end
                if not response_handle:headers():get("X-DNS-Prefetch-Control") then
                response_handle:headers():add("X-DNS-Prefetch-Control", "off");
                end
                if not response_handle:headers():get("Feature-Policy") then
                response_handle:headers():add("Feature-Policy",
                                                "camera 'none';"..
                                                "microphone 'none';"..
                                                "geolocation 'none';"..
                                                "encrypted-media 'none';"..
                                                "payment 'none';"..
                                                "speaker 'none';"..
                                                "usb 'none';");
                end
                if response_handle:headers():get("X-Powered-By") then
                response_handle:headers():remove("X-Powered-By");
                end
            end

部署:

[root@master01 istioyaml]# kubectl apply -f istio-ingress-rf.yaml

通过 ingress 访问 hello 接口。接口响应头中包含额外添加的响应头,则说明创建的EnvoyFilter 生效。

[root@master01 istioyaml]# curl -i http://10.0.0.12/hello
HTTP/1.1 200 OK
server: istio-envoy
date: Thu, 17 Apr 2025 09:08:46 GMT
content-type: text/html; charset=utf-8
content-length: 60
x-envoy-upstream-service-time: 67
content-security-policy: frame-ancestors none;
x-frame-options: deny
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer
x-download-options: noopen
x-dns-prefetch-control: off
feature-policy: camera 'none';microphone 'none';geolocation 'none';encrypted-media 'none';payment 'none';speaker 'none';usb 'none';

Hello version: v1, instance: helloworld-v1-77ccfb9cbb-mkdld

4.3 通过EnvoyFilter进行JWT认证

需求:对于发往指定服务的指定路径的http请求,不再向服务转发请求,而是立即返回固定的响应内容。

[root@master01 istioyaml]# vim helloworld-direct-response.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: jwt-helloworld
spec:
  workloadSelector:
    labels:
      app: helloworld
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.jwt_authn
          typedConfig:
            '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
            providers:
              origins-0:
                forward: true
                issuer: testing@secure.istio.io
                localJwks:
                  inlineString: "{ \"keys\":\n   [ \n     {\n       \"e\":\"AQAB\",\n
                    \      \"kid\":\"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ\",\n
                    \      \"kty\":\"RSA\",\n       \"n\":\"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ\"\n
                    \    }\n   ]\n}\n"
                payloadInMetadata: testing@secure.istio.io
            rules:
            - match:
                prefix: /
              requires:
                requiresAny:
                  requirements:
                  - providerName: origins-0
                  - allowMissing: {}

部署:

[root@master01 istioyaml]# kubectl apply -f helloworld-direct-response.yaml

1)进入 sleep 服务容器内。

[root@master01 istioyaml]# kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')  -c sleep sh

2)使用 -H "Authorization: Bearer xxxx" 传入错误的 hearder 信息。返回结果为401,则说明创建的 EnvoyFilter 生效。

~ $ curl -i -H "Authorization: Bearer xxxx" http://10.0.0.12/hello
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="http://10.0.0.12/hello", error="invalid_token"
content-length: 79
content-type: text/plain
content-security-policy: frame-ancestors none;
x-frame-options: deny
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer
x-download-options: noopen
x-dns-prefetch-control: off
feature-policy: camera 'none';microphone 'none';geolocation 'none';encrypted-media 'none';payment 'none';speaker 'none';usb 'none';
date: Thu, 17 Apr 2025 09:11:08 GMT
server: envoy
x-envoy-upstream-service-time: 6

3)输入正确的 Authorization 数据:

#设置TOKEN
~ $ TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAi
OiJKV1QifQ.eyJleHAiOjM1MzczOTExMDQsImdyb3VwcyI6WyJncm91cDEiLCJncm91cDIiXSwiaWF0IjoxNTM3MzkxMTA0LCJpc3MiOiJ0
ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyIsInNjb3BlIjpbInNjb3BlMSIsInNjb3BlMiJdLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5
pbyJ9.EdJnEZSH6X8hcyEii7c8H5lnhgjB5dwo07M5oheC8Xz8mOllyg--AHCFWHybM48reunF--oGaG6IXVngCEpVF0_P5DwsUoBgpPmK1
JOaKN6_pe9sh0ZwTtdgK_RP01PuI7kUdbOTlk uUi2AO-qUyOm7Art2POzo36DLQlUXv8Ad7NBOqfQaKjE9ndaPWT7aexUsBHxmgiGbz1Sy
LH879f7uHYPbPKlpHU6P9S-DaKnGLaEchnoKnov7ajhrEhGXAQRukhDPKUHO9L30oPIr5IJllEQfHYtt6IZvlNUGeLUcif3wpry1R5tBXRi
cx2sXMQ7LyuDremDbcNy_iE76Upg'

#重新测试访问
~ $ curl -i -H "Authorization: Bearer ${TOKEN}" http://10.0.0.12/hello
HTTP/1.1 200 OK
server: envoy
date: Thu, 17 Apr 2025 09:20:01 GMT
content-type: text/html; charset=utf-8
content-length: 60
x-envoy-upstream-service-time: 59
content-security-policy: frame-ancestors none;
x-frame-options: deny
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer
x-download-options: noopen
x-dns-prefetch-control: off
feature-policy: camera 'none';microphone 'none';geolocation 'none';encrypted-media 'none';payment 'none';speaker 'none';usb 'none';

Hello version: v2, instance: helloworld-v2-5f7b5b7754-pzstc