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

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

截图如下

[图片上传失败...(image-793224-1685598147167)]

创建 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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容