阿里云服务网格ASM之扩展能力(2):在ASM中支持自定义外部授权

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 前面的系列文档中介绍了如何创建服务网格ASM实例,并介绍了如何将一个应用示例部署到 ASM 实例中,本文在此基础上介绍如何在ASM中支持自定义外部授权。

本系列文章讲讲述阿里云服务网格ASM的一些扩展能力:

欢迎扫码入群进一步交流:
image

背景信息

服务网格中服务间存在着调用请求,这些请求的授权决定可以由运行在网格外部的gRPC服务处理。外部授权过滤器调用授权服务以检查传入请求是否被授权。如果在过滤器中将该请求视为未授权,则该请求将被403(禁止)响应拒绝。

建议将这些授权过滤器配置为过滤器链中的第一个过滤器,以便在其余过滤器处理请求之前对请求进行授权。

关于Envoy的外部授权的其他内容,可以参见External Authorization

gRPC外部服务需要相应的接口,实现该Check()方法。具体来说,external_auth.proto 定义了请求响应上下文:

// A generic interface for performing authorization check on incoming
// requests to a networked service.
service Authorization {
  // Performs authorization check based on the attributes associated with the
  // incoming request, and returns status `OK` or not `OK`.
  rpc Check(v2.CheckRequest) returns (v2.CheckResponse);
}

实现外部授权服务

基于上述gRPC服务接口定义,实现示例外部授权服务如下,在Check()方法中判断Bearer Token值是否以asm-开头。事实上,只要符合该接口定义,可以添加更为复杂的处理逻辑进行检查。

package main

import (
    "context"
    "log"
    "net"
    "strings"

    "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
    auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
    envoy_type "github.com/envoyproxy/go-control-plane/envoy/type"
    "github.com/gogo/googleapis/google/rpc"
    "google.golang.org/grpc"
)

// empty struct because this isn't a fancy example
type AuthorizationServer struct{}

// inject a header that can be used for future rate limiting
func (a *AuthorizationServer) Check(ctx context.Context, req *auth.CheckRequest) (*auth.CheckResponse, error) {
    authHeader, ok := req.Attributes.Request.Http.Headers["authorization"]
    var splitToken []string
    if ok {
        splitToken = strings.Split(authHeader, "Bearer ")
    }
    if len(splitToken) == 2 {
        token := splitToken[1]
        // Normally this is where you'd go check with the system that knows if it's a valid token.

        if strings.HasPrefix(token, "asm-") {
            return &auth.CheckResponse{
                Status: &rpc.Status{
                    Code: int32(rpc.OK),
                },
                HttpResponse: &auth.CheckResponse_OkResponse{
                    OkResponse: &auth.OkHttpResponse{
                        Headers: []*core.HeaderValueOption{
                            {
                                Header: &core.HeaderValue{
                                    Key:   "x-custom-header-from-authz",
                                    Value: "some value",
                                },
                            },
                        },
                    },
                },
            }, nil
        }
    }
    return &auth.CheckResponse{
        Status: &rpc.Status{
            Code: int32(rpc.UNAUTHENTICATED),
        },
        HttpResponse: &auth.CheckResponse_DeniedResponse{
            DeniedResponse: &auth.DeniedHttpResponse{
                Status: &envoy_type.HttpStatus{
                    Code: envoy_type.StatusCode_Unauthorized,
                },
                Body: "Need an Authorization Header with a character bearer token using asm- as prefix!",
            },
        },
    }, nil
}

func main() {
    // create a TCP listener on port 4000
    lis, err := net.Listen("tcp", ":4000")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    log.Printf("listening on %s", lis.Addr())

    grpcServer := grpc.NewServer()
    authServer := &AuthorizationServer{}
    auth.RegisterAuthorizationServer(grpcServer, authServer)

    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("Failed to start server: %v", err)
    }

}

可以直接使用镜像: registry.cn-beijing.aliyuncs.com/istio-samples/ext-authz-grpc-service:latest

或者可以基于以下Dockerfile构建镜像,具体代码参见istio_ext_authz_filter_sample

启动外部授权服务器

  • Github项目库中下载示例部署YAML 文件。 或者复制以下YAML定义:
apiVersion: v1
kind: Service
metadata:
  name: extauth-grpc-service
spec:
  ports:
  - port: 4000
    targetPort: 4000
    protocol: TCP
    name: grpc
  selector:
    app: extauth-grpc-service
  type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: extauth-grpc-service
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: extauth-grpc-service
    spec:
      containers:
      - name: extauth
        image: registry.cn-beijing.aliyuncs.com/istio-samples/ext-authz-grpc-service:latest
        ports:
          - containerPort: 4000
  • 通过 kubectl 连接到 ASM 实例中新添加的 ACK 集群,执行如下命令:
kubectl apply -n istio-system -f extauth-sample-grpc-service.yaml
  • 将看到以下输出显示已成功部署:
service/extauth-grpc-service created
deployment.extensions/extauth-grpc-service created

等待部署的外部授权pod启动之后,接下来开始部署示例应用。

部署示例应用

  • 该示例部署使用了命名空间default,并且已启动Sidecar自动注入。
  • Github项目库中下载示例部署示例httpbin服务的YAML 文件。
  • 通过 kubectl 连接到 ASM 实例中新添加的 ACK 集群,执行如下命令:
kubectl apply -f httpbin.yaml
  • 然后部署用于测试的客户端示例应用sleep。从 Github项目库中下载示例部署示例sleep服务的YAML 文件。
  • 通过 kubectl 连接到 ASM 实例中新添加的 ACK 集群,执行如下命令:
kubectl apply -f sleep.yaml

定义EnvoyFilter

  • 在控制平面区域,选择EnvoyFilter页签,然后单击新建。
  • 在新建页面中,选择相应的命名空间。本例中选择的命名空间为 default。
  • 在文本框中,定义EnvoyFilter,可以复制粘贴EnvoyFilter定义到编辑框中。可参考如下 YAML 定义:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  # This needs adjusted to be the app name
  name: extauth-sample
spec:
  workloadSelector:
    labels:
      # This needs adjusted to be the app name
      app: httpbin
 
  # Patch the envoy configuration
  configPatches:
 
  # Adds the ext_authz HTTP filter for the ext_authz API
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        name: virtualInbound
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
    patch:
      operation: INSERT_BEFORE
      value:
        # Configure the envoy.ext_authz here:
        name: envoy.ext_authz
        config:
          grpc_service:
            # NOTE: *SHOULD* use envoy_grpc as ext_authz can use dynamic clusters and has connection pooling
            google_grpc:
              target_uri: extauth-grpc-service.istio-system:4000
              stat_prefix: ext_authz
            timeout: 0.2s
          failure_mode_allow: false
          with_request_body:
            max_request_bytes: 8192
            allow_partial_message: true
  • 单击确定,将会看到EnvoyFilter已成功创建。
    image.png

验证外部授权

  • 登录到Sleep Pod容器中执行如下命令:
export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl  http://httpbin:8000/headers'

返回如下结果:

Need an Authorization Header with a character bearer token using asm- as prefix!


可以看到示例应用程序的请求没有通过外部授权的许可,原因是请求头中并没有满足Bearer Token值以asm-开头。

  • 在请求中添加以asm-开头的Bearer Token请求头,再次执行如下命令:
export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl -H "Authorization: Bearer asm-token1" http://httpbin:8000/headers'

返回如下结果:

{
  "headers": {
    "Accept": "*/*",
    "Authorization": "Bearer asm-token1",
    "Content-Length": "0",
    "Host": "httpbin:8000",
    "User-Agent": "curl/7.64.0",
    "X-B3-Parentspanid": "dab85d9201369071",
    "X-B3-Sampled": "1",
    "X-B3-Spanid": "c29b18886e98a95f",
    "X-B3-Traceid": "66875d955ac13dfcdab85d9201369071",
    "X-Custom-Header-From-Authz": "some value"
  }
}


可以看到示例应用程序的请求通过外部授权的许可。

相关文章
|
2月前
|
Cloud Native 容器 Kubernetes
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
本文简要讨论了使用流量泳道来实现全链路流量灰度管理的场景与方案,并回顾了阿里云服务网格 ASM 提供的严格与宽松两种模式的流量泳道、以及这两种模式各自的优势与挑战。接下来介绍了一种基于 OpenTelemetry 社区提出的 baggage 透传能力实现的无侵入式的宽松模式泳道,这种类型的流量泳道同时具有对业务代码侵入性低、同时保持宽松模式的灵活特性的特点。同时,我们还介绍了新的基于权重的流量引流策略,这种策略可以基于统一的流量匹配规则,将匹配到的流量以设定好的比例分发到不同的流量泳道。
73490 16
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
|
1月前
|
人工智能 自然语言处理 安全
使用阿里云服务网格高效管理LLM流量:(一)流量路由
ASM支持通过LLMProvider和LLMRoute资源管理大型语言模型流量。LLMProvider负责注册LLM服务,LLMRoute负责设定流量规则,应用可灵活切换模型,满足不同场景需求。
|
2月前
|
负载均衡 测试技术 网络安全
阿里云服务网格ASM多集群实践(一)多集群管理概述
服务网格多集群管理网络打通和部署模式的多种最佳实践
|
1月前
|
Cloud Native 测试技术 开发者
阿里云服务网格ASM多集群实践(二):高效按需的应用多环境部署与全链路灰度发布
介绍服务网格ASM提出的一种多集群部署下的多环境部署与全链路灰度发布解决方案。
|
2月前
|
人工智能 安全 Go
使用阿里云服务网格 ASM LLMProxy 插件保障大模型用户数据安全
本文介绍如何使用ASM LLMProxy动态为LLM请求添加API_KEY、使用模式匹配以及私有大模型判别请求敏感信息并根据判别结果拒绝请求等功能,帮助用户提升LLM场景下的安全水位。
|
2月前
|
负载均衡 Kubernetes 算法
服务网格 ASM 负载均衡算法全面解析
在本文中,笔者将解析服务网格的多种负载均衡算法的实现原理和使用场景,为服务网格负载均衡算法的选择提供参考。
|
3月前
|
Kubernetes Cloud Native 容器
全景剖析阿里云容器网络数据链路(六)—— ASM Istio
本文是[全景剖析容器网络数据链路]第六部分部分,主要介绍ASM Istio模式下,数据面链路的转转发链路。
333 0
全景剖析阿里云容器网络数据链路(六)—— ASM Istio
|
3月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
179 2
|
3月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
259 0