oathkeeper的安装与使用

 

一、Oathkeeper简介

    ORY Oathkeeper是一个认证与访问代理,用于作为反向代理或者访问权限决策点。

    当作为反向代理时,客户端、oathkeeper以及内网服务之间的通信流程如图1所示。

 

                                                                       图1   作为反向代理时的通信流程

    当作为权限决策点时,客户端、API网关、Oathkeeper以及内网服务之间的通信流程如下如下。

    

                                                                        图2   当作为访问决策点时的通信流程

       当Oathkeeper接收到HTTP请求后,会首先对HTTP请求进行认证以及鉴权,如果全都通过,才会将HTTP请求转发到服务端。

      

                                                                     图3  Oathkeeper主要运行流程

       由上图可知,Oathkeeper主要完成对HTTP请求的认证、鉴权的任务。然而,在不与第三方认证、鉴权服务通信的前提下, oathkeeper的只有有限的认证、鉴权能力,详细如下:

       

oathkeeper不需要第三方时的认证、鉴权能力范围
能力范围
认证鉴权更改

1.noop(全部认证通过)

2.unauthorized(全部拒绝认证)

3.Annymous(不带Authorization头部的请求可以认证通过,如果数据的访问者没有定义,则被设置为“匿名”)

 

1.allow(权限认证时全部通过)

2.deny(权限认证时全部失败)

尚不清楚应用场景

        因此,如果想要提供更全面、更完善的安全机制,只能在系统中继续搭建其他服务。在这个博客中,oathkeeper会和go-oauth2相配合,搭建安全防护系统,保护内网的一个nginx服务器。

 

二、 Oathkeeper的安装

       详见Oathkeeper安装,由于网络原因,有些依赖包可能无法下载,可以通过设置代理或者手动下载完成,注意的是手动下载时需要将数据包安装到GOPATH下的指定路径。

 

三、  系统构建

   3.1   基于go-oauth2完成系统认证、授权代码

        核心代码如下:

        

        /*
             Step1:创建admin,zhanglei两个用户,并存储在内存数据库中
        */
        clientStore := store.NewClientStore()
        root_id, root_secret := "admin", "admin_haha"
        root_index := root_id
        root_client_info := models.Client{ID: root_id, Secret: root_secret, Domain: "http://ip_of_web:80/"}
        clientStore.Set(root_index, &root_client_info)

        user_id,user_secret := "zhanglei", "zhanglei_haha"
        user_index := user_id
        user_info := models.Client{ID: user_id, Secret:  user_secret, Domain: "http://ip_of_web:80/"}
        clientStore.Set(user_index, &user_info)
        manager.MapClientStorage(clientStore)
    /*
          搭建登录服务,用来给用户生成short live token(2h内有效)
    */
    http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
                //need:grant_typ(password),client_id,password
                if r.Method == "POST" {
                        /*
                             当客户端POST的client存在且与password对应时,则认证服务器产生一个token.
                             否则,返回失败
                        */
                        err := srv.HandleTokenRequest(w, r)
                        if err != nil {
                                http.Error(w, err.Error(), http.StatusInternalServerError)
                                return
                        }
                        return
                }
                outputHTML(w, r, "static/login.html")
        })
http.HandleFunc("/vaild_token", func(w http.ResponseWriter, r *http.Request) {
                //need:grant_typ(password),client_id,password
                /*
                      提供HTTP的认证服务
                */
                log.Println("receive a vaild token request !\n")
                ctx := r.Context()
                r.ParseForm()
                access_token := r.Form.Get("token")
                log.Println("access token:", access_token)
                if access_token == "" {
                        http.Error(w, "The request don't have any access token", http.StatusBadRequest)
                        return
                }
                /*
                     查看该token是否被认证过,如果没有,则返回错误
                */
                ti, err := srv.Manager.LoadAccessToken(ctx, access_token)
                if err != nil {
                        http.Error(w, "Found token error", http.StatusForbidden)
                        return
                }
                response_map := make(map[string]interface{})
                /*
                    active = true表示认证成功
                    active、username将会被放入鉴权信息的头部
                */
                response_map["active"] = true
                response_map["username"] = ti.GetUserID()
                response_json, err := json.Marshal(response_map)
                _ = err
                response_string := string(response_json)
                io.WriteString(w, response_string)
        })
http.HandleFunc("/access_engery", func(w http.ResponseWriter, r *http.Request) {
                /*
                   从HTTP头部信息中得到用户信息
                */
                clientID, require_resource, require_action, err := get_client_info(r)
                if err != nil {
                        http.Error(w, err.Error(), http.StatusBadRequest)
                        return
                }
                /*
                  如果有相应权限,则需要返回给oathkeeper 200状态码
                */
                if clientID == "admin" && require_resource == "web_server" && require_action == "read" {
                        io.WriteString(w, clientID+" is accessible to "+require_resource)
                } else {
                        http.Error(w, clientID+" is not accessible to "+require_resource, http.StatusBadRequest)
                }
                return
        })

   3.2  Oathkeeper配置

        oathkeeper的配置如下:

[
  {
    "id": "allow-anonymous-with-header-mutator",
    "version": "v0.36.0-beta.4",
    "upstream": {
      "url": "http://ip_of_webserver:80/"
    },
    "match": {
      "url": "<https|http>://ip_of_oathkeeper:4455/",
      "methods": [
        "GET"
      ]
    },
    "authenticators": [
      {
        "handler": "oauth2_introspection"
      }
    ],
    "authorizer": {
      "handler": "remote",
      "config": {
           "headers": {
               "clientID": "{{ print .Extra.username }}",
               "require_resource": "web_server",
               "action": "read"
           }
      }
    },
    "mutators": [
      {
        "handler": "noop"
      }
    ]
  },
  {
    "id": "user_login",
    "version": "v0.36.0-beta.4",
    "upstream": {
      "url": "http://ip_of_go_oath2:9096"
    },
    "match": {
      "url": "<https|http>://ip_of_oathkeeper:4455/login",
      "methods": [
        "GET","POST"
      ]
    },
    "authenticators": [
      {
        "handler": "noop"
      }
    ],
    "authorizer": {
      "handler": "allow"
    },
    "mutators": [
      {
        "handler": "noop"
      }
    ]
  }
]

       

serve:
  proxy:
    port: 4455 # run the proxy at port 4455
  api:
    port: 4456 # run the api at port 4456

access_rules:
  repositories:
    - file:///home/zhanglei/go_project/src/github.com/ory/oathkeeper/demo/rules.json

authenticators:
  noop:
     enabled: true
  unauthorized:
     enabled: true
  oauth2_introspection:
     enabled: true
     config:
        introspection_url: http://ip_of_go_oath2:9096/vaild_token

mutators:
  noop:
     enabled: true 

authorizers:
  allow:
     enabled: true
  remote:
     enabled: true
     config:
        remote: http://ip_of_go_oath2:9096/access_engery

    这个配置的意思是,通过配置访问authenticators.oauth2_introspection.config.introspection_url对用户进行认证,然后通过访问

authorizers.remote.config.remote来进行远程鉴权。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值