首页 > 其他分享 >day34 基于ServiceEntry,Sidecar,Envoy Filter实战场--深入剖析Istio的安全策略(10.8-10.9)

day34 基于ServiceEntry,Sidecar,Envoy Filter实战场--深入剖析Istio的安全策略(10.8-10.9)

时间:2024-01-14 18:44:28浏览次数:32  
标签:ServiceEntry http name -- 安全策略 istio headers handle response

10.8-1-基于ServiceEntry,Sidecar,Envoy Filter实战场

一、ServiceEntry实战场景

1.1 部署Istio提供的sleep示例

istioctl kube-inject -f samples/sleep/sleep.yaml | kubectl apply -f -

1.2 部署busybox

#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: 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

应用yaml:

kubectl apply -f busybox-dp.yaml

 1.3 测试验证

kubectl get pods



# 使用sleep来访问外部服务
# kubectl exec sleep-7cf9595556-r5ppq -- curl -sI  http://www.baidu.com


# 使用sleep来访问busybox
# kubectl exec sleep-7cf9595556-r5ppq -- curl -sI http://busybox.default.svc.cluster.local

 1.4 部署到外部服务的流量

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

应用yaml

kubectl apply -f httpbin-se.yaml

首先是 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 验证访问

# 当前能正常访问
# kubectl exec sleep-7cf9595556-gv4wh -c sleep -- curl -sSI httpbin.org


# 设置httpbin延迟5秒后,返回结果,因为时间超过3秒了,故而会认为超时
# kubectl exec sleep-7cf9595556-gv4wh -c sleep -- curl -sSI httpbin.org/delay/5

二、WorkloadEntry案例

2.1、Gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'
kubectl apply -f gateway.yaml

2.2、WorkloadEntry

apiVersion: networking.istio.io/v1alpha3
kind: WorkloadEntry
metadata:
  name: details-vm-2
spec:
  address: 192.10.192.14 # 外部地址
  ports:
    number: 3000
  labels:
    app: details-legacy
    instance-id: vm1
kubectl apply -f customers-we.yaml

2.3、ServiceEntry 

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: details-svc
spec:
  hosts:
  - details.kubernets.cn
  location: MESH_INTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
    targetPort: 3000
  resolution: DNS
  workloadSelector:
    labels:
      app: details-legacy
kubectl apply -f customers-se.yaml

2.4、VirtualService

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ssdemo
spec:
  gateways:
  - gateway
  hosts:
  - '*'
  http:
  - match:
    - uri:
        prefix: /
    rewrite:
      uri: /
    route:
    - destination:
        host: details.kubernets.cn # 对应上 ServiceEntry hosts的字段
        port:
          number: 80
    timeout: 300s

2.5、测试验证

##原192.10.192.14主机上测试:
# curl localhost:3000
<a href="/login">Found</a>.
##通过ServiceEntry引入Istio服务网格
# curl -H "Host: details.kubernets.cn" http://192.10.192.224;
<a href="/login">Found</a>.

三、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:
    - "./*"

10.8-2-基于ServiceEntry,Sidecar,Envoy Filter实战场

四、EnvoyFilter实战场景

官网: Istio / Envoy Filter

4.1、添加 HTTP 响应头

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

##通过服务 sleep 发起请求,调用服务 helloworld 的 /hello 完成相应功能的验证。
# kubectl apply -f samples/sleep/sleep.yaml
1)部署服务 helloworld。
# kubectl apply -f samples/helloworld/helloworld.yaml
2)部署 helloworld gateway。
# kubectl apply -f samples/helloworld/helloworld-gateway.yaml

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

HTTP响应头 默认值  描述
ContentSecurity-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-Contro 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: 

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
kubectl apply -f helloworld-ef.yaml

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

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

验证:

1)进入 sleep 服务容器内: 

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

4.2、Istio-ingress网关层面

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

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
kubectl apply -f istio-ingress-rf.yaml

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

curl -i http://192.10.192.224/hello

4.3、通过EnvoyFilter进行JWT认证

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

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: [email protected]
                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: [email protected]
            rules:
            - match:
                prefix: /
              requires:
                requiresAny:
                  requirements:
                  - providerName: origins-0
                  - allowMissing: {}
kubectl apply -f helloworld-direct-response.yaml

1)进入 sleep 服务容器内。

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://192.10.192.224/hello

3)输入正确的 Authorization 数据:

TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjM1MzczOTExMDQsImdyb3VwcyI6WyJncm91cDEiLCJncm91cDIiXSwiaWF0IjoxNTM3MzkxMTA0LCJpc3MiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyIsInNjb3BlIjpbInNjb3BlMSIsInNjb3BlMiJdLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.EdJnEZSH6X8hcyEii7c8H5lnhgjB5dwo07M5oheC8Xz8mOllyg--AHCFWHybM48reunF--oGaG6IXVngCEpVF0_P5DwsUoBgpPmK1JOaKN6_pe9sh0ZwTtdgK_RP01PuI7kUdbOTlkuUi2AOqUyOm7Art2POzo36DLQlUXv8Ad7NBOqfQaKjE9ndaPWT7aexUsBHxmgiGbz1SyLH879f7uHYPbPKlpHU6P9SDaKnGLaEchnoKnov7ajhrEhGXAQRukhDPKUHO9L30oPIr5IJllEQfHYtt6IZvlNUGeLUcif3wpry1R5tBXRicx2sXMQ7LyuDremDbcNy_iE76Upg

$ curl -i -H "Authorization: Bearer ${TOKEN}" http://192.10.192.224/hello
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 59
server: istio-envoy
date: Thu, 10 Aug 2023 04:35:12 GMT
x-envoy-upstream-service-time: 175

Hello version: v2, instance: helloworld-v2-54df5f84b-mf8wt

 

10.9-1-深入剖析Istio的安全策略(1)

一、前言

在Kubernetes集群中,可以使用token进行认证,或者使用kubeconfig进行认证;对于istio来说,有两种认证方式:对等认证 和 请求认证。
Istio需要安全功能来解决微服务架构中的一系列安全挑战和需求。以下是一些主要原因:

  1. 加密通信:在微服务架构中,服务之间的通信很容易受到窃听、篡改和伪造请求等攻击。通过使用加密技术,如TLS(Transport Layer Security),可以确保在服务之间传输的数据是加密的,从而防止敏感信息的泄露。
  2. 身份验证和授权:在服务网格中,存在大量的微服务实例,这些实例可能是动态的。因此,确保服务之间的身份是可信的,并进行适当的授权,是确保系统安全的
    关键。通过身份验证和授权机制,Istio可以确保只有经过验证的服务可以相互通信,并根据访问策略对请求进行授权。
  3.  访问控制:微服务架构中的服务通常需要根据角色、权限和策略来限制对资源的访问。通过提供访问控制功能,Istio可以帮助实现细粒度的访问控制策略,以保护服务免受未经授权的访问和恶意行为。
  4.  遥测和审计:保持对服务的监控、记录和审计是确保系统的安全性和合规性的重要方面。Istio的安全功能可以收集服务间通信的遥测数据,如流量日志和度量指标,从而支持故障排除、性能优化和安全审计等任务。

通过提供这些安全功能,Istio帮助组织构建更加安全、可靠和合规的微服务架构,降低了安全风险,并为开发人员和运维人员提供了强大的工具来管理和保护服务之间的通信。

二、Istio安全控制

Istio提供了对等认证(Peer Authentication)和请求认证(Request Authentication)两个层次的安全机制。 

2.1、对等认证(PeerAuthentication)

对等认证:用于服务到服务的认证,在零信任网络中,Envoy 给服务之间的通讯加密,只有服务双方才能看到请求内容和响应结果。 

在 Istio 中,默认情况下,服务之间的通信不会被加密或进行身份验证。比如说, A服务通过 http 请求 B 服务,流量经过 Envoy A 时,Envoy A 直接将流量发送到Envoy B 中,流量不会进行加密处理,也就是明文请求。 

Istio 的 Peer Authentication 主要解决以下问题:

  • 保护服务A到服务B的通信。
  • 提供密钥管理系统,通讯加密需要使用证书,而证书会过期,所以需要一个管理系统自动颁发证书、替换证书等。
  • 为每个服务提供强大的身份标识,以实现跨群集和云的互操作性。 

工作方式:
Istio 的 PeerAuthentication 是一种安全策略,用于对服务网格内的工作负载之间的通信进行双向 TLS(mTLS)验证。
来看如下这张图:

1. Pod A作为客户端向Pod B作为服务器发起连接请求。
2. Pod A将发送TLS握手请求到Pod B。
3. Pod B将其证书发送给Pod A,证书包含了Pod B的公钥。
4. Pod A验证Pod B证书的有效性,包括验证证书的签名、有效期等。
5. 如果Pod B的证书验证通过,Pod A将生成一个随机的密钥,并使用Pod B的公钥进
行加密,然后将加密后的密钥发送给Pod B。
6. Pod B使用自己的私钥解密Pod A发送的密钥,得到共享密钥。
7. 一旦双方建立了共享密钥,Pod A和Pod B就可以使用该密钥进行后续通信的加密和解密。

这个过程中,Istio使用X.509证书进行对等认证。证书可以是使用自签名、Istio CA或外部证书颁发机构颁发的。验证证书的过程包括检查证书的签名、有效期以及基于策略的授权检查,以确保通信双方的身份经过验证。
PeerAuthentication 例子:
下面是一个简单的 PeerAuthentication 示例:
我们可以创建 PeerAuthentication 资源,首先在每个命名空间中分别执行严格模式。然后,我们可以在根命名空间(在我们的例子中是 istio-system )创建一个策略,在整个服务网格中执行该策略: 

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

此外,我们还可以指定 selector 字段,将策略仅应用于网格中的特定工作负载。
下面的例子对具有 指定标签 的应用启用 STRICT 模式:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: customers
    mtls:
      mode: STRICT

mtls: 定义双向 TLS 的模式,有三种模式。

  • STRICT : 强制执行 mTLS,要求客户端和服务器使用 TLS 进行通信。这需要客户端和服务器具有有效的证书。
  • PERMISSIVE : 允许客户端使用TLS或纯文本进行通信。这对于逐步迁移到 mTLS的场景非常有用。
  • DISABLE : 禁用 mTLS,不要求客户端和服务器使用 TLS 进行通信。

注意:每个命名空间也只能有一个命名空间范围的 Peer 认证策略。当同一网格或命名空间配置多个网格范围或命名空间范围的 Peer 认证策略时,Istio 会忽略较新的策略。
当多个特定于工作负载的 Peer 认证策略匹配时,Istio 将选择最旧的策略。

2.2、请求认证(RequestAuthentication)

Istio 的 RequestAuthentication 是一种安全策略,用于验证和授权客户端访问Istio服务网格中的服务。
RequestAuthencation 需要搭配一个 AuthorizationPolicy来 使用。
RequestAuthentication 和 AuthorizationPolicy 这两个策略用于验证和授权客户端访问服务网格中的服务。
RequestAuthentication 负责验证客户端提供的 JWT,而 AuthorizationPolicy 负责基于角色的访问控制(RBAC),允许定义细粒度的权限以限制对特定服务、方法和路径的访问。 

RequestAuthencation 的定义:
下面是一个完整的 RequestAuthentication 示例:

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: my-request-authentication
  namespace: my-namespace
spec:
  jwtRules:
  - issuer: "https://accounts.google.com"
    audiences:
    - "my-audience-1"
    - "my-audience-2"
    jwksUri: "https://www.googleapis.com/oauth2/v3/certs"
    jwtHeaders:
    - "x-jwt-assertion"
    - "x-jwt-assertion-original"
    jwtParams:
    - "access_token"
    forward: true

如果只针对命名空间中的部分应用,可以使用:

selector:
  matchLabels:
    app: my-app

在 RequestAuthentication 中,jwtRules 是一个配置项,用于定义如何验证和处理 JWT。

一个典型的 jwtRules 配置可能包括以下几个部分:

  • issuer: 发行者,表示JWT的发行方,例如:https://accounts.google.com。这个字段用于验证JWT的iss(发行者)声明。
  • audiences: 受众列表,表示接受JWT的一组实体。这个字段用于验证JWT的aud(受众)声明。例如:["my-audience-1", "my-audience-2"]
  • jwksUri: JSON Web Key Set(JWKS)的URL,用于获取JWT签名公钥。Istio会从这个URL下载公钥,用于验证JWT的签名。例如:https://www.googleapis.com/oauth2/v3/certs
  • jwtHeaders: 一个字符串数组,表示可以从HTTP请求头中获取JWT的头名称。默认情况下,Istio会从"Authorization"头中获取令牌。例如:["x-jwt-assertion","x-jwt-assertion-original"]
  • jwtParams: 一个字符串数组,表示可以从HTTP请求参数中获取JWT的参数名称。例如:["access_token"]
  • forward : 一个布尔值,表示是否将JWT转发给上游服务。默认值为false,表示JWT令牌不会转发给上游服务。如果设置为true,则Istio会将令牌添加到请求头中,并转发给上游服务。

通过正确配置 jwtRules,Istio 可以对请求中的 JWT 进行验证,确保客户端访问服务网格中的服务时具有适当的授权。 

10.9-2-深入剖析Istio的安全策略(2)

三、实战一:基于Istio的安全控制

在这个实验中,我们将部署示例应用程序(Web Frontend 和 Customers 服务): 

  • Web 前端的部署将不包含 Envoy 代理 sidecar;
  • 而 Customers 服务将被注入 sidecar;
  • 通过这个设置,我们将看到 Istio 如何同时发送 mTLS 和 纯文本流量,以及如何将TLS 模式改为 STRICT。 

让我们从部署一个 Gateway 资源开始:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'
kubectl apply -f gateway.yaml 部署网关。

接下来,我们将创建 Web Frontend 和 Customers 服务的部署以及相关的 Kubernetes 服务。

在开始部署之前,我们将禁用 default 命名空间中的自动 sidecar 注入,这样代理就不会被注入到 Web 前端部署中。
在我们部署 Customers 服务之前,我们将再次启用注入。

kubectl label namespace default istio-injection-

禁用注入后,部署 web-frontend :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-frontend
  template:
    metadata:
      labels:
        app: web-frontend
        version: v1
    spec:
      containers:
        - image: gcr.io/tetratelabs/web-frontend:1.0.0
          imagePullPolicy: Always
          name: web
          ports:
            - containerPort: 8080
          env:
            - name: CUSTOMER_SERVICE_URL
              value: 'http://customers.default.svc.cluster.local'
---
kind: Service
apiVersion: v1
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  selector:
    app: web-frontend
  ports:
    - port: 80
      name: http
      targetPort: 8080
      
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: web-frontend
spec:
  hosts:
    - '*'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: web-frontend.default.svc.cluster.local
            port:
              number: 80

应用yaml

kubectl apply -f web-frontend.yaml

如果我们看一下正在运行的 Pod,我们应该看到有一个 Pod 正在运行一个容器,由READY 栏显示 1/1 : 

# kubectl get po

启用自动注入: 

kubectl label namespace default istio-injection=enabled

部署 Customers 服务的 v1 版本: 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: customers-v1
  labels:
    app: customers
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customers
      version: v1
  template:
    metadata:
      labels:
        app: customers
        version: v1
    spec:
      containers:
        - image: gcr.io/tetratelabs/customers:1.0.0
          imagePullPolicy: Always
          name: svc
          ports:
            - containerPort: 3000
---
kind: Service
apiVersion: v1
metadata:
  name: customers
  labels:
    app: customers
spec:
  selector:
    app: customers
  ports:
    - port: 80
      name: http
      targetPort: 3000
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: customers
spec:
  hosts:
    - 'customers.default.svc.cluster.local'
  http:
    - route:
        - destination:
            host: customers.default.svc.cluster.local
            port:
              number: 80

应用yaml

kubectl  apply -f customers-v1.yaml

我们应该有两个应用程序的部署在运行——customers 服务将有两个容器,而 Web 前端服务将有一个: 

# kubectl get po

如果我们尝试从 GATEWAY_URL 访问网页,我们会得到带有客服人员回应的网页。
访问 GATEWAY_URL 之所以有效,是因为采用了许可模式,纯文本流量被发送到没有代理的服务。在这种情况下,入口网关将纯文本流量发送到 Web 前端,因为没有代理。
如果我们用 http://kiali-istio.kubernets.cn/ 打开 Kiali,看一下 Graph,你会发现 Kiali检测到 从入口网关到 Web 前端的调用。
模拟调用:

for i in {1..5000}; do curl -s -o /dev/null -w "%{http_code}\n" http://192.10.192.224; sleep 0.5; done

然而,对 Customers 服务的调用是来自未知的服务。这是因为 Web 前端旁边没有代理,Istio 不知道这个服务是谁、在哪里、是什么。
然后在 kiali 面板中的 Display 选项中下拉选择 Security。

让我们更新 Customers 的 VirtualService 并将网关附加到它上面。这将使我们能够直接调用 Customers 的服务。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: customers
spec:
  hosts:
    - 'customers.default.svc.cluster.local'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: customers.default.svc.cluster.local
            port:
              number: 80

应用yaml

kubectl  apply -f vs-customers-gateway.yaml

现在 我们可以指定 Host 头了,我们就可以通过入口网关( GATEWAY_URL )将请求发 送到 Customers 服务: 

$ curl -H "Host: customers.default.svc.cluster.local" http://192.10.192.224

为了通过 Ingress 给 Web 前端和 Customers 服务产生一些流量,打开两个终端窗口,分别运行一条命令: 

// Terminal 1
$ while true; do curl -H "Host: customers.default.svc.cluster.local" http://192.10.192.224; done
...

// Terminal 2
$ while true; do curl http://192.10.192.224; done

打开 Kiali,看一下图表。在 Display 下拉菜单中,确保我们选中 Security 选项。你应该
看到一个类似于下图的图表。 

也就是说未来所有的流量从入口网关到 Customers 服务之间有一个挂锁图标,这意味着流量是使用 mTLS 发送的。
然而,在未知的(web 前端)和 Customers 服务之间,以及 istio-ingressgateway 和 web 前端之间,都没有挂锁。
Istio 在没有注入 sidecar 的情况下向服务发送纯文本流量。
让我们看看如果我们在 STRICT 模式下启用 mTLS 会发生什么。我们预计从前端到Customers 服务的调用会开始失败,因为没有注入代理来进行 mTLS 通信。另一方面,从入口网关到 Customers 服务的调用将继续工作。

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT

应用yaml

kubectl apply  -f strict-mtls.yaml

如果我们仍然在运行请求循环,我们将开始看到来自 web 前端的 ECONNRESET 错误信息。这个错误表明,Customers 端关闭了连接。
在我们的例子中,这是因为它期待着一个 mTLS 连接。

curl http://192.10.192.224

curl -H "Host: customers.default.svc.cluster.local" http://192.10.192.224

另一方面,我们直接向 Customers 服务发出的请求继续工作,因为 Customers 服务旁边有一个 Envoy 代理在运行,它可以进行 mTLS。
如果我们删除之前部署的 PeerAuthentication 资源( kubectl deletepeerauthentication default ),Istio 就会恢复到默认状态(PERMISSIVE 模式),错误也会消失。
资源清理:
删除 Deployment、Service、VirtualService 和 Gateway: 

kubectl delete deploy web-frontend customers-v1
kubectl delete svc customers web-frontend
kubectl delete vs.networking.istio customers web-frontend
kubectl delete gateway.networking.istio gateway

四、实战(2):基于Istio的安全控制

在这个实验中,我们将部署示例应用程序(Web Frontend 和 Customers 服务):

  • Web 前端及 Customers 服务均包含 Envoy 代理 sidecar;
  • 通过配置 RequestAuthorization 这个设置,我们将看到访问认证。

让我们从部署一个 Gateway 资源开始: 

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'

应用yaml

kubectl apply -f gateway2.yaml

部署 web-frontend :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-frontend
  template:
    metadata:
      labels:
        app: web-frontend
        version: v1
    spec:
      containers:
        - image: gcr.io/tetratelabs/web-frontend:1.0.0
          imagePullPolicy: Always
          name: web
          ports:
            - containerPort: 8080
          env:
            - name: CUSTOMER_SERVICE_URL
              value: 'http://customers.default.svc.cluster.local'
---
kind: Service
apiVersion: v1
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  selector:
    app: web-frontend
  ports:
    - port: 80
      name: http
      targetPort: 8080
      
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: web-frontend
spec:
  hosts:
    - '*'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: web-frontend.default.svc.cluster.local
            port:
              number: 80

应用yaml

kubectl apply -f web-frontend2.yaml

部署 Customers 服务:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: customers-v1
  labels:
    app: customers
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customers
      version: v1
  template:
    metadata:
      labels:
        app: customers
        version: v1
    spec:
      containers:
        - image: gcr.io/tetratelabs/customers:1.0.0
          imagePullPolicy: Always
          name: svc
          ports:
            - containerPort: 3000
---
kind: Service
apiVersion: v1
metadata:
  name: customers
  labels:
    app: customers
spec:
  selector:
    app: customers
  ports:
    - port: 80
      name: http
      targetPort: 3000
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: customers
spec:
  hosts:
    - 'customers.default.svc.cluster.local'
  http:
    - route:
        - destination:
            host: customers.default.svc.cluster.local
            port:
              number: 80

应用yaml

kubectl apply -f  customers2.yaml

创建 RequestAuthorization 实现:

apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
  name: "jwt-example"
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  jwtRules:
  - issuer: "[email protected]"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/master/security/tools/jwt/samples/jwks.json"
    outputPayloadToHeader: "X-Jwt-Playload"
    forwardOriginalToken: true

应用yaml

kubectl apply -f web-frontend-ra.yaml

验证:

export INGRESS_HOST=192.10.192.224
curl $INGRESS_HOST/ -s -o /dev/null -w "%{http_code}\n"

既然定义了认证策略,为什么不提供 JWT 会允许访问? 这个行为需要注意,可能和预期的认知有差异,这是因为认证策略定义的是认证的行为,当没有提供 JWT 时,它并不能断言认证成功或失败,因为没有进行认证的断言。如果想实现必须提供有效的 JWT 才允许访问,则需要通过在“授权策略”中指定必须存在主体,具体请了解“授权策略”,这里就不展开了。
提供无效的 JWT: 

curl --header "Authorization: Bearer deadbeef" $INGRESS_HOST/ -s - o /dev/null -w "%{http_code}\n"

 

五、总结

通过对等认证和请求认证的组合使用,Istio 提供了强大的安全机制。
对等认证:确保服务之间的通信是安全可信的;
请求认证:允许细粒度的访问控制和身份验证,确保只有经过授权的请求可以访问相应的资源。
这些认证机制帮助保护应用程序免受未经授权的访问和潜在的安全威胁。
在配置 Istio 时,可以根据需要启用或禁用对等认证和请求认证,并定义适当的访问策略以确保系统的安全性。

标签:ServiceEntry,http,name,--,安全策略,istio,headers,handle,response
From: https://www.cnblogs.com/pythonlx/p/17951138

相关文章

  • 车机必备软件-小白点EasyTouch(类似苹果的悬浮球,返回,清理垃圾,杀进程)
    简介有些小伙伴升级车机后,由于部分软件打开后处于全屏状态无法返回,这里我教大家如何解决。解决办法就是:在车机上安装这款小白点软件,这款软件体积小巧,不占内存,操作也十分方便,它能帮助你快速回到主屏幕和返回上一个界面。界面展示caplay界面普通车机界面软件功能1、主屏......
  • 肝不好能吃猪肉吗
    肝病能吃猪肉吗肝病患者可以吃猪肉,但是要避免吃得过于油腻。肝病是指发生在肝脏的病变,包括肝炎、肝硬化、肝脏肿瘤等。对于肝病患者是否能吃猪肉,需要依据肝病的具体病情、患者既往史等方面来综合判断。如果患者的肝病并不严重,并没有导致肝功能明显受损或发生不可逆性的肝细胞坏......
  • django restframework
    传送门:https://www.bilibili.com/video/BV1xj411C7ws?p=6&spm_id_from=pageDriver&vd_source=502f63a6c3f07b2d0c4afd71ff535497原始的djangorestframework......
  • python面向对象之类的内置方法
    【引入】Python的Class机制内置了很多特殊的方法来帮助使用者高度定制自己的类这些内置方法都是以双下划线开头和结尾的,会在满足某种条件时自动触发__init__ :初始化类时触发__del__ :删除类时触发__new__ :构造类时触发__str__ :str函数或者print函数触发__repr__ :repr或......
  • 远程桌面连接出现了内部错误怎么解决?
    远程桌面连接是一种非常方便的工具,可以让用户从远程访问其他计算机的桌面界面。但是,有时候在连接远程桌面时会出现内部错误,导致无法连接或者连接后无法正常使用。小德将分析远程桌面连接出现内部错误的原因和解决方法。1.确认网络连接在使用远程桌面连接之前,首先需要确保计算机之......
  • 按键开关机的锂电池充放电解决方案
    一、产品概述TP4562是一款集成线性充电管理、同步升压转换、电池电量指示和多种保护功能的单芯片电源管理SOC,为锂电池的充放电提供完整的单芯片电源解决方案。TP4562内部集成了线性充电管理模块、同步升压放电管理模块、电量检测与LED指示模块、保护模块、按键模块和自动关机模......
  • lightgbm 数据比较少怎么办
    当使用LightGBM处理相对较少的数据时,可以考虑以下一些方法:调整参数:在训练LightGBM模型时,可以通过调整参数来适应小规模的数据集。例如,减少num_leaves、max_depth等参数,以降低模型的复杂性。使用更轻量级的模型:如果数据集很小,可以考虑使用较小规模的模型,例如降低num_leaves或使用......
  • TinyGPT-V:2.8B参数引领轻量级多模态AI
    前言在当前多模态大型语言模型(MLLM)快速发展的背景下,TinyGPT-V的出现标志着一个重要的技术突破。这款轻量级模型以其2.8B参数的设计,在AI领域引起广泛关注,成为GPT-4V等模型的高效替代方案。Huggingface模型下载:https://huggingface.co/Tyrannosaurus/TinyGPT-VAI快站模型免费加速下载......
  • Windows合集
    使用技巧:1.dos窗口(磁盘操作系统)2.显示或隐藏桌面通用图标:搜索框输入icon3.显示扩展名:(区分文件类型)计算机-组织-布局-菜单栏-工具-文件夹选项-查看-隐藏文件拓展名勾掉4.telnetip地址端口号可以查看对方是否开启端口服务端口号Mysql端口号:3306Rdp远程桌面连接:3......
  • MySQL修改安全策略时报错:ERROR 1193 (HY000): Unknown system variable ‘validate_pa
    我使用的版本是MySQL5.73,环境是LinuxCentOS7,其他版本不知道是否可行,望谅解。当我们想设置简单的密码的时候,看了别人发的如何修改安全策略的代码,如下:setglobalvalidate_password_policy=0;setglobalvalidate_password_length=1;但是当我们使用的时候,却报了这样一个......