首页 > 其他分享 >Istio 实现 ext-authz 外部扩展鉴权以及对接基于 k8s 的微服务

Istio 实现 ext-authz 外部扩展鉴权以及对接基于 k8s 的微服务

时间:2023-06-01 14:02:18浏览次数:50  
标签:authz redis Istio ext go logger com 鉴权

Istio 实现 ext-authz 外部扩展鉴权以及对接基于 k8s 的微服务

可以实现基于 redistoken 鉴权以及实现 rbac 鉴权。

转载请注明来源:https://janrs.com/vrsr


Istio 的外部鉴权本质是基于 Envoy 实现的,直接看 Envoy 的代码,链接地址:点击自动跳转

Isio 官方的 Demo 代码,链接:点击自动跳转

实现

Istio 提供了基于 HTTP 方式以及 Grpc 方式的外部鉴权扩展,这里这实现了 Grpc

配置

修改 IstioConfigmap 配置。在 mesh 字段下面添加以下代码配置:

extensionProviders:
    - name: "rgrpc-dev-authz-grpc-provider"
      envoyExtAuthzGrpc:
        service: "auth.rgrpc-dev.svc.cluster.local"
        port: 50051

截图如下

Istio 实现 ext-authz 外部扩展鉴权以及对接基于 k8s 的微服务_istio

创建 Istio 鉴权 Grpc 服务

本质上,Istio 的外部鉴权是基于 Evnoy 实现,只需要实现了 EnvoyGrpc 方法后 Istio 就会自动调用。

需要实现的 Envoyexternal_auth.pb.go文件 链接:点击自动跳转

只需要实现里面的 Check 方法即可。Envoy 官方提供了 v2 以及 v3 代码的实现,这里我只实现了 v3 的接口。

写好代码后将服务做成镜像部署到 k8s

案例代码如下:

package serverV1

import (
	"encoding/json"
	authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
	typev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/redis/go-redis/v9"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"

	"authservice/config"
	"golang.org/x/net/context"
)

type Server struct {
	authv3.UnimplementedAuthorizationServer
	conf   *config.Config
	redis  *redis.Client
	repo   *Repository
	logger log.Logger
}

func NewServer(
	conf *config.Config,
	redis *redis.Client,
	repo *Repository,
	logger log.Logger,
) authv3.AuthorizationServer {
	return &Server{
		conf:   conf,
		redis:  redis,
		repo:   repo,
		logger: logger,
	}
}

var (
	UnauthorizedMsg = "没有权限"
	ForbiddenMsg    = "没有权限"
)

// Response 返回 HTTP Body 数据
type Response struct {
	Code int64    `json:"code"`
	Msg  string   `json:"msg"`
	Data struct{} `json:"data"`
}

// Check istio-grpc 外部鉴权方法
func (s *Server) Check(ctx context.Context, req *authv3.CheckRequest) (*authv3.CheckResponse, error) {
	// 以下是我的逻辑代码。可以全部删除然后自行修改
	attrs := req.GetAttributes()
	httpHeaders := attrs.GetRequest().GetHttp().GetHeaders()
	// 获取请求路径
	path, exists := httpHeaders[":path"]
	if !exists {
		_ = level.Info(s.logger).Log("msg", "获取不到 :path 字段")
		return s.Unauthorized(), nil
	}
	// 判断是否是白名单
	if s.repo.IsWhiteListApi(path) {
		return s.Allow(), nil
	}
	// 获取头部 token
	token, exists := httpHeaders["authorization"]
	duration := 7 * 24 * 60 * 60
	if !exists {
		_ = level.Info(s.logger).Log("msg", "未传递头部 authorization 字段")
		return s.Unauthorized(), nil
	}
	// 去除头部 "Bearer "字符串
	if len(token) <= 7 {
		_ = level.Info(s.logger).Log("msg", "authorization 数据格式错误。没有设置 Bearer 前缀")
		return s.Unauthorized(), nil
	}
	// 截取后面的 token 字符串
	token = token[7:]

	// 验证 token
	if err := s.repo.GetAuthentication(ctx, token, int64(duration)); err != nil {
		_ = level.Info(s.logger).Log("msg", "access token 不存在")
		return s.Unauthorized(), nil
	}
	return s.Allow(), nil
}

// Allow 通过鉴权。返回 200
func (s *Server) Allow() *authv3.CheckResponse {
	return &authv3.CheckResponse{
		Status: &status.Status{Code: int32(codes.OK)},
		HttpResponse: &authv3.CheckResponse_OkResponse{
			OkResponse: &authv3.OkHttpResponse{},
		},
	}
}

// Unauthorized Unauthorized 未授权 401
func (s *Server) Unauthorized() *authv3.CheckResponse {
	resp := &Response{
		Code: int64(typev3.StatusCode_Unauthorized),
		Msg:  UnauthorizedMsg,
		Data: struct{}{},
	}
	respJson, err := json.Marshal(resp)
	httpBody := ""
	if err == nil {
		httpBody = string(respJson)
	}
	return &authv3.CheckResponse{
		Status: &status.Status{Code: int32(codes.Unauthenticated)},
		HttpResponse: &authv3.CheckResponse_DeniedResponse{
			DeniedResponse: &authv3.DeniedHttpResponse{
				Status: &typev3.HttpStatus{Code: typev3.StatusCode_Unauthorized},
				Body:   httpBody,
			},
		},
	}
}

// Forbidden Forbidden 没有权限 403
func (s *Server) Forbidden() *authv3.CheckResponse {
	resp := &Response{
		Code: int64(typev3.StatusCode_Forbidden),
		Msg:  ForbiddenMsg,
		Data: struct{}{},
	}
	respJson, err := json.Marshal(resp)
	httpBody := ""
	if err == nil {
		httpBody = string(respJson)
	}

	return &authv3.CheckResponse{
		Status: &status.Status{Code: int32(codes.PermissionDenied)},
		HttpResponse: &authv3.CheckResponse_DeniedResponse{
			DeniedResponse: &authv3.DeniedHttpResponse{
				Status: &typev3.HttpStatus{Code: typev3.StatusCode_Forbidden},
				Body:   httpBody,
			},
		},
	}
}

创建 IstioAuthorizationPolicy

最后设置 IstioAuthorizationPolicy。设置后,所有经过 Istio 网关的请求都会自行被拦截,然后调用部署好的 Grpc 鉴权服务进行鉴权。

需要注意的是:provider 需要跟上面 IstioConfigmap 中的 extensionProviders.name 字段的值对应上才会调用到配置中的 Grpc 地址

使用的是 CUSTOM 配置,配置如下:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: rgrpc-ext-authz
  namespace: rgrpc-dev
spec:
  action: CUSTOM
  provider:
    name: rgrpc-dev-authz-grpc-provider
  rules:
    - to:
        - operation:
            hosts:
              - api.your-domain.com:31380

转载请注明来源:https://janrs.com/vrsr

标签:authz,redis,Istio,ext,go,logger,com,鉴权
From: https://blog.51cto.com/u_15436157/6393570

相关文章

  • Istio 实现 ext-authz 外部扩展鉴权以及对接基于 k8s 的微服务
    Istio实现ext-authz外部扩展鉴权以及对接基于k8s的微服务可以实现基于redis的token鉴权以及实现rbac鉴权。转载请注明来源:https://janrs.com/vrsrIstio的外部鉴权本质是基于Envoy实现的,直接看Envoy的代码,链接地址:点击自动跳转Isio官方的Demo代码,链接:点......
  • IDEA中slf4j和logback冲突,快速排除(LoggerFactory is not a Logback LoggerContext but
    pom文件中右击  ctrl+f输入点击定位 选中shift+delet,直接排除  或者手动输入排除 ......
  • ext4 extent 寻址方案
    ExtentTreeInext4,thefiletologicalblockmaphasbeenreplacedwithanextenttree.Undertheoldscheme,allocatingacontiguousrunof1,000blocksrequiresanindirectblocktomapall1,000entries;withextents,themappingisreducedtoasi......
  • 配置 Sublime Text 4 作为 R/Python IDE
    VScode太占用内存了,在作为RIDE的时候,经常后台有13个R的Front-end进程,再开启浏览器,浏览器一会就崩溃了。RStudio不是轻便IDE的第一选择。比来比去,就只有SublimeText。必须安装的SublimeText插件:SendCode、Terminus。配置SublimeText4作为RIDER已经安装并加入系统路径......
  • Build context
    Buildcontext|DockerDocumentationhttps://docs.docker.com/build/building/context/ Multiple <src> resourcesmaybespecifiedbutthepathsoffilesanddirectorieswillbeinterpretedasrelativetothesourceofthecontextofthebuild.Docker......
  • 如何使用Next.js创建全栈应用程序
    Next.js乍一看似乎令人生畏,因为有这么多新概念需要掌握。但别担心——在这个循序渐进的教程中,我将为您提供使用Next.js创建您的第一个现代全栈应用程序所需的所有基本信息。在本教程中,我将带您了解Next.js的基础知识,并指导您创建您的第一个全栈应用程序。在本教程结束时,您将......
  • next_permutation函数
    next_permutation的函数声明:#include <algorithm> boolnext_permutation(iteratorstart,iteratorend);next_permutation函数的返回值是布尔类型,在STL中还有perv_permutation()函数 #include<iostream>#include<algorithm>#include<string>usingnamespacest......
  • [4] Secret Key Extraction using Bluetooth Wireless Signal Strength Measurements
    近日在找和BLE或者RSS相关的baseline,不好找,找到了一篇2014年的文章,感觉CCFB的文章工作量其实也还好吧。 SecretKeyExtractionusingBluetoothWireless SignalStrengthMeasurements题目:通过蓝牙测试RSS来生成密钥 1、摘要和介绍其实看了题目大概就知道他在干啥了,摘......
  • app直播源代码,带下划线的TextVeiw
    app直播源代码,带下划线的TextVeiw /** *带有下划线的TextView。 */publicclassUnderlineTextViewextendsTextView{  publicUnderlineTextView(Contextcontext,AttributeSetattrs,intdefStyle){    super(context,attrs,defStyle);  }  pu......
  • extern 存储类
     extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用'extern'时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得......