百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

使用 OAuth2-Proxy 和 Keycloak 为系统添加 OAuth2 身份验证

toyiye 2024-09-16 06:07 4 浏览 0 评论

背景

在平常工作,相信大家都会使用到一些常用的开源软件,像 prometheus , rabbitmq , kibanba 等。这些软件很多在权限设计这块就比较简单,或者是没有,如Prometheus 自带的查询面板,早期的 rocketmq dashboard,kibana 等,相信小伙伴有不少基于这块的安全整改,整改措施一般只是配置简单的 http basic 认证,或者 IP 白名单访问。下面介绍基于 Keycloak 和 OAuth2-Proxy 为系统添加 OAuth2 身份验证的方案。

keycloak 简单介绍

KeyCloak 是一种开源身份和访问管理解决方案,以最少的工作量为应用程序添加身份验证和保护服务。Keycloak 提供用户联合、强身份验证、用户管理、精细授权等。目前支持挺多开源软件单点登录,如 jenkins, redash, grafana 等。

OAuth2-Proxy 简单介绍

oauth2-proxy 是一个反向代理和静态文件服务器,它使用提供程序(Google、Keycloak、GitHub 等)提供身份验证,以通过电子邮件、域或组验证帐户。

方案介绍

我们可以使用 OAuth2-ProxyKeycloak 为应用程序中添加 OAuth2 身份验证,特别是那些没有身份验证的系统,下面以 Prometheus 为例,在我的一台服务器上,有 nginx , keycloak , oauth2_proxy 以及 prometheus 4 个服务,其中 keycloak, oauth2_proxy, prometheus 都是通过 nginx vhost 反向代理访问,域名如下图:

配置 Prometheus 基于 OAuth2-ProxyKeycloak 身份验证的请求过程可以参考下图:

nginx , keycloak , oauth2_proxy 以及 prometheus 4 个服务这次全部使用 docker 部署。

keycloak docker 部署

keycloak docker-compose.yml

services:
  keycloak:
    image: quay.io/keycloak/keycloak:25.0.4
    ports:
      - "8080:8080"
 #   restart: always
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ftLVBgGK9SP
      KC_HTTP_ENABLED: true
      KC_PROXY_HEADERS: xforwarded  # keycloak 访问通过 nginx 反向代理,proxy headers 支持 forwarded, xforwarded
      KC_HEALTH_ENABLED: true
      KC_HOSTNAME: keycloak.zwade.top
      #KC_HOSTNAME_STRICT: false
      KC_DB: mysql
      KC_DB_URL: jdbc:mysql://mysql:3306/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: Pp123456
    command: 
      - start 
    networks:
      - access-mysql
        
networks:
  access-mysql:
    external: true

默认情况下,服务器使用 dev-file 数据库。这是服务器将用于持久数据的默认数据库,并且仅存在用于开发用例的数据库。 dev-file 数据库不适合生产用例,必须在部署到生产之前替换。keycloak 内置支持不同的数据库,具体可以参考官档。

oauth2-proxy docker 部署

Oauth2-proxy 的配置项可以参考 oauth2-proxy 官档,每个命令行参数都可以指定为环境变量,方法是将其前缀 OAUTH2_PROXY_ ,将其大写,并将连字符 ( - ) 替换为下划线 ( _ )。如果可以多次指定参数,则环境变量应为复数(尾随 S )。注意,环境配置项的值千万不要加引号

生成强 Cookie 密钥,对应环境变量 OAUTH2_PROXY_COOKIE_SECRET

dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_' ; echo

REDIRECT_URL 需要与 keycloak 配置的 client 的 Valid redirect URIs 配置项要对应上,下面是 oauth2-proxydocker-compose.yml

services:
   server:
     image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
     ports:
       - "4180:4180"
     environment:
       - OAUTH2_PROXY_PROVIDER=keycloak-oidc
       - OAUTH2_PROXY_CLIENT_ID=prometheus
       - OAUTH2_PROXY_CLIENT_SECRET=z6rqgRPAZ3QsOIbx02Zq60llHeDGpZnAuo
       - OAUTH2_PROXY_REDIRECT_URL=https://prometheus.zwade.top/oauth2/callback
       - OAUTH2_PROXY_OIDC_ISSUER_URL=https://keycloak.zwade.top/realms/master
       - OAUTH2_PROXY_COOKIE_SECRET=ofonr_QLDW5EaKaVp09P2b46Pycn8pps7bHNpjDEUEk=
       - OAUTH2_PROXY_EMAIL_DOMAINS=*
       - OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL=true
       - OAUTH2_PROXY_CODE_CHALLENGE_METHOD=S256
       - OAUTH2_PROXY_REVERSE_PROXY=true
       - OAUTH2_PROXY_HTTP_ADDRESS=0.0.0.0:4180

Nginx 和 Prometheus docker 部署

部署过程略

Keycloak 创建新的 OIDC

Keycloak新版控制台按照以下步骤创建:
a. 在 Keycloak realm 下创建新的 OIDC client
Clients -> Create client
Client Type 选择 OpenID Connect,填写 Client ID,* 必填项,其他项也可以进行填写, Next

Client authentication 'On',
Authentication flow ,勾选 Standard flow,取消勾选 Direct access grants, Next

填写Valid redirect URIs,需要与 oauth2_proxyOAUTH2_PROXY_REDIRECT_URL 对应上,Save

b. client 配置专用的 audience mapper
Clients -> <your client's id> -> Client scopes
点击
Configure a new mapper 然后选择 Audience

Name 一般以aud-mapper-<your client's id>格式,Included Client Audience 下拉框选择你对应的 client's id,Add to ID token 'On',Add to access token 'On',其他保持默认就可以,然后 Save

更多请参考:https://oauth2-proxy.github.io/oauth2-proxy/configuration/providers/keycloak_oidc/

配置 Nginx 反向代理

创建关于 prometheus 域名 nginx vhost 配置,使用 Nginx auth_request 指令,该指令允许 Nginx 通过 oauth2-proxy 的/auth endpoint 对请求进行身份验证,该 endpoint 仅返回 202 Accepted 响应或 401 Unauthorized 响应,而不通过代理请求。

upstream prometheus {
    server localhost:9090;
    keepalive 1;
}


server {
    listen 80;
    listen 443 ssl http2;
    server_name prometheus.zwade.top;

    ssl_certificate /etc/nginx/conf.d/ssl/zwade.top/zwade.top.cer;
    ssl_certificate_key /etc/nginx/conf.d/ssl/zwade.top/zwade.top.key;

    proxy_buffer_size 32k;
    proxy_buffers 4 32k;

    location /oauth2/ {
        proxy_pass       http://127.0.0.1:4180;
        proxy_set_header Host                    $host;
        proxy_set_header X-Real-IP               $remote_addr;
        proxy_set_header X-Auth-Request-Redirect $request_uri;
        # or, if you are handling multiple domains:
        proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
    }

    location = /oauth2/auth {
        proxy_pass       http://127.0.0.1:4180;
        proxy_set_header Host             $host;
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Forwarded-Uri  $request_uri;
        # nginx auth_request includes headers but not body
        proxy_set_header Content-Length   "";
        proxy_pass_request_body           off;
    }

    location / {
        auth_request /oauth2/auth;
        error_page 401 =403 /oauth2/sign_in;

        # pass information via X-User and X-Email headers to backend,
        # requires running with --set-xauthrequest flag
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        proxy_set_header X-User  $user;
        proxy_set_header X-Email $email;

        # if you enabled --pass-access-token, this will pass the token to the backend
        auth_request_set $token  $upstream_http_x_auth_request_access_token;
        proxy_set_header X-Access-Token $token;

        # if you enabled --cookie-refresh, this is needed for it to work with auth_request
        auth_request_set $auth_cookie $upstream_http_set_cookie;
        add_header Set-Cookie $auth_cookie;

        # When using the --set-authorization-header flag, some provider's cookies can exceed the 4kb
        # limit and so the OAuth2 Proxy splits these into multiple parts.
        # Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response,
        # so if your cookies are larger than 4kb, you will need to extract additional cookies manually.
        auth_request_set $auth_cookie_name_upstream_1 $upstream_cookie_auth_cookie_name_1;

        # Extract the Cookie attributes from the first Set-Cookie header and append them
        # to the second part ($upstream_cookie_* variables only contain the raw cookie content)
        if ($auth_cookie ~* "(; .*)") {
            set $auth_cookie_name_0 $auth_cookie;
            set $auth_cookie_name_1 "auth_cookie_name_1=$auth_cookie_name_upstream_1$1";
        }

        # Send both Set-Cookie headers now if there was a second part
        if ($auth_cookie_name_upstream_1) {
            add_header Set-Cookie $auth_cookie_name_0;
            add_header Set-Cookie $auth_cookie_name_1;
        }

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass  http://prometheus/;

    }

}
  

测试验证


打开浏览器开发者模式,可以看到请求Prometheus 是带有 ouath2_proxy cookies 认证。

最后

keycloak + oauth2_proxy 真的基本上可以开箱即用,无需额外开发,我们可以使用 keycloak 做统一用户管理,当然 keycloak 还不止上面这些功能,有兴趣的朋友可以自行查看官档。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码