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

强转根系
• 阅读 554

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 鉴权 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
点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
TARS的服务鉴权功能|避免数据泄露
!(https://oscimg.oschina.net/oscnet/084208376c754453a44175dc09e16402.gif)在我们使用微服务架构时,经常会选择通过RPC通信框架方便地实现服务间的调用。但方便的同时也带来了一些安全隐患,任何用户都能够访问对外公开的接口,可能造成部分敏感数据的泄露,这是我们不希望
Stella981 Stella981
3年前
SpringBoot项目中使用AOP
1.概述将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签、鉴权等。Spring的声明式事务也是通过AOP技术实现的。具体的代码参照示例项目https://github.com/qihaiyan/springcamp/tree/master/springaop(https://www.oschina.net/actio
Stella981 Stella981
3年前
Spring Cloud之Feign 转发请求头(header参数)
在做接口请求时,我们经常会在header头中增加一些鉴权信息,如token或jwt,那么在通过fegin从Aserver去调用Bserver的接口时,如果Bserver的接口需要header信息,我们需要将Asever获取的header转发到B上。解决方式我们需要实现Feign提供的一个接口RequestInterc
Easter79 Easter79
3年前
SpringBoot项目中使用AOP
1.概述将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签、鉴权等。Spring的声明式事务也是通过AOP技术实现的。具体的代码参照示例项目https://github.com/qihaiyan/springcamp/tree/master/springaop(https://www.oschina.net/actio
Wesley13 Wesley13
3年前
RTSP拉流协议视频平台多点认证造成潜在威胁?如何破解?
上一篇我们讲了TSINGSEE青犀视频平台EasyNVR内登陆鉴权的优化,通过优化登陆鉴权,我们可以抵御很多分发用户的攻击。在该问题优化完成后,我们模拟不法分子的攻击对EasyNVR的安全性进行了测试,EasyNVR已经达到了一个安全性很高的级别。!203.png(https://imgblog.csdnimg.cn/img_convert/937
Stella981 Stella981
3年前
Spring Cloud微服务架构从入门到会用(五)—服务网关鉴权
上一篇文章我们集成了服务网关SpringCloudGateway,所有的服务请求都可以通过Gateway访问。那我们就可在服务网关这一层对用户的请求进行鉴权,判断是否可以访问路由的API接口。接下来我们开始增加鉴权,这里我们使用jwt1\.创建授权服务module按照第二篇文章创建一个module,起名为appauth。
Stella981 Stella981
3年前
Spring Boot Actuator监控
1、简介  springboot有四大杀器:starters、autoConfiguration、cli、actuator。actuator是springboot对应用的监控组件,可以查看应用系统的配置、资源使用等统计功能。2、actuator主要功能HTTP方法路径描述鉴权默认可以用备注GET/autoconfi
Stella981 Stella981
3年前
CDN a,b,c三种鉴权的PHP代码
A鉴权方式的代码//http://DomainName/Filename?auth\_keytimestampranduidmd5hash//sstring"URITimestampranduidPrivateKey"(URI是用户的请求对象相对地址,如/Filename)//HashValuemd5su
你想要的【微前端】都在这里了! | 京东云技术团队
某次遇到一个从0到1的大型项目,该项目涉及两个端,除了鉴权和部分业务逻辑不同外,页面UI和其余逻辑几乎一致,遇到这种项目,该如何架构?既能保证项目顺利开发完成,又能保证后期的迭代、维护、可扩展?
liam liam
1年前
从零开始的 WebSocket 鉴权实践指南
作为实时通信的利器,越来越受到开发者的青睐。然而,为了确保通信的安全性和合法性,鉴权成为不可或缺的一环。本文将深入探讨WebSocket的鉴权机制,为你呈现一揽子的解决方案,确保你的WebSocket通信得心应手。使用场景鉴权在许多场景中都显得尤为重要。例