上手实操:Amazon OpenSearch Service 支持 JSON Web Token 身份验证和授权

d2748a430f091f158aec667f74b191f3.gif

本文作者 韩旭

北京西云数据科技有限公司亚马逊云技术支持

亚马逊云科技云博主 

最近,Amazon OpenSearch 推出了一个新功能,支持 JSON Web Token (JWT) 认证和授权。

此前的授权方式

控制台登录

  1. 内部数据库:使用基本的用户名和密码进行 HTTP 验证。如果切换到其他认证方式(如 IAM 或 SAML),此验证方式将被禁用。

  2. IAM 主用户:实际上是通过 Amazon Cognito 进行验证。由于中国区没有用户池,设置为 IAM 作为主用户故无法使用。

  3. SAML 单点登录:与 SAML 身份提供商(如 Azure AD、Auth0)集成。SAML 身份验证仅能在浏览器中访问 OpenSearch Dashboard,开启 SAML 后会禁用基本的 HTTP 验证。

编程方式

对于 SDK 而言,可以通过在 HTTP 请求中携带用户名和密码,或使用 SignV4 携带 IAM 身份信息进行认证。

常见的解决方案包括

  1. 控制台和 SDK 都使用内部数据库的主用户进行基本 HTTP 验证。

  2. 控制台使用内部数据库或 SAML 凭证登录 OpenSearch Dashboard,然后在权限认证中给 IAM 身份单独授权访问索引,这样编程方式就可以使用 SignV4 的签名算法访问集群资源。

JWT 与 OIDC

JWT 验证流程

  1. 客户端请求:客户端向服务器发出登录请求,提供用户凭证(例如用户名和密码)。

  2. 服务器验证凭证:服务器验证用户凭证的有效性。

  3. 生成 JWT:如果凭证有效,服务器生成一个包含用户身份信息和其他声明的 JWT,并使用服务器的私钥签名。

  4. 返回 JWT:服务器将签名的 JWT 返回给客户端。

  5. 客户端存储 JWT:客户端收到 JWT 后,将其存储在本地存储或 cookie 中,以便在后续请求中使用。

  6. 携带 JWT 的请求:客户端在每次请求时将 JWT 包含在 HTTP 请求头中(通常是 Authorization: Bearer )。

  7. 服务器验证 JWT:服务器接收到请求后,提取并解析 JWT,验证其签名、有效期和其他声明的合法性。

  8. 处理请求:如果 JWT 验证通过,服务器处理请求并返回响应;如果验证失败,返回 401 或 403 错误。

fc2234418ab7aa0cf8852a16e76b0e0b.png

OIDC 验证流程

OpenID Connect(OIDC)是在 OAuth 2.0 协议之上构建的一个身份层,用于实现单点登录(SSO)和身份验证。以下是 OIDC 的详细验证流程:

  1. 客户端请求身份认证:客户端向身份提供者(IdP)发送身份认证请求,包含 client_id、redirect_uri、scope、response_type 和 state 参数。

  2. 用户身份验证:身份提供者显示登录界面,用户输入凭证进行身份验证。

  3. 同意授权:用户登录成功后,身份提供者可能会显示同意授权页面。

  4. 返回授权码:用户同意授权后,身份提供者重定向客户端到 redirect_uri,并附带一个授权码。

  5. 交换授权码:客户端使用授权码向身份提供者的 token 端点发送请求,以交换 access token 和 ID token。

  6. 返回 token:身份提供者验证授权码后,返回 access token 和 ID token。ID token 是一个包含用户身份信息的 JWT。

  7. 验证 ID token:客户端接收到 ID token 后,验证其签名、声明合法性和过期时间。

  8. 使用 token:客户端使用 access token 访问受保护资源,并解码 ID token 中的用户身份信息。

be6d500aaa338554a01f5981d504d0f7.png

OpenSearch 的 JWT 认证授权

2024 年 6 月 19 日 Amazon OpenSearch 在全球区上线了 JWT 认证授权功能,中国区在 2024 年 6 月 23 日上线控制台增加了 JWT 认证授权功能,启用此功能需要开启精细访问控制,并导入验证 JWT 有效性的证书。本文经后期整理。

5e343ec913510e2c2adf17bf5c10e59d.png

配置 Auth0

配置 JWT 认证授权的步骤包括在 IDP 中创建 API,并使用 API 获取 JWT。以下是使用 Auth0 生成 JWT 的示例代码:

import requests
import json


# 配置
AUTH0_DOMAIN = "<domain>.auth0.com"
CLIENT_ID = "<CLIENT_ID>"
CLIENT_SECRET = "<CLIENT_SECRET>"
AUDIENCE = "https://auth0-jwt-authorize"
GRANT_TYPE = "client_credentials"
TOKEN_URL = f"https://{AUTH0_DOMAIN}/oauth/token"
OUTPUT_FILE_PATH = 'jwt_token.json'


# 请求负载和头部
payload = {
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "audience": AUDIENCE,
    "grant_type": GRANT_TYPE
}
headers = {
    "content-type": "application/json"
}


# 发送 POST 请求获取 JWT
response = requests.post(TOKEN_URL, json=payload, headers=headers)


# 处理响应
if response.status_code == 200:
    data = response.json()
    with open(OUTPUT_FILE_PATH, 'w') as file:
        json.dump(data, file, indent=4)
    print(f"JWT 已保存到文件: {OUTPUT_FILE_PATH}")
else:
    print(f"请求失败,状态码:{response.status_code}")
    print(response.text)

左右滑动查看完整示意

我们在 Auth0 中新建一个 API,然后会帮我们生成一个 Application。后续我们会使用这个 Application 的 Client ID 和 Secret ID 以及 Domain 的信息来登录。

47ed73d9015cc63265da4fbea01d4e90.png

也就是说这三个信息确定了一个身份池,然后符合规则的用户可以通过这个身份池来换取 JWT。可以在Applications-Applications 中看到。

配置好之后,可以通过 Auth0 的 API 来拿到登录后的 JWT,以下是一个官方给的教程可以用来测试功能,当然也可以集成到 APP 中。

Auth0 也提供了示例代码供我们测试:

27794e529b7865407c119799d4163904.png

官方提供代码样例可读性不是很高,让我们用 requests 来改写一下,这个代码会把生成的 JWT 存在一个 JSON 文件里面,这样我们就能容易的复制出来。

import requests
import json


# 配置
AUTH0_DOMAIN = "<domain>.auth0.com"
CLIENT_ID = "<CLIENT_ID>"
CLIENT_SECRET = "<CLIENT_SECRET>"
AUDIENCE = "https://auth0-jwt-authorize"
GRANT_TYPE = "client_credentials"
TOKEN_URL = f"https://{AUTH0_DOMAIN}/oauth/token"
OUTPUT_FILE_PATH = 'jwt_token.json'


# 请求负载和头部
payload = {
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "audience": AUDIENCE,
    "grant_type": GRANT_TYPE
}
headers = {
    "content-type": "application/json"
}


# 发送POST请求获取JWT
response = requests.post(TOKEN_URL, json=payload, headers=headers)


# 处理响应
if response.status_code == 200:
    data = response.json()
    with open(OUTPUT_FILE_PATH, 'w') as file:
        json.dump(data, file, indent=4)
    print(f"JWT已保存到文件: {OUTPUT_FILE_PATH}")
else:
    print(f"请求失败,状态码:{response.status_code}")
    print(response.text)

左右滑动查看完整示意

我们可以看到控制台多出了一个 JWT 认证授权新功能,使用这个功能需要先开启精细访问控制,我们需要在这里需要导入验证 JWT 有效性的证书。

fb3e38cbc801da2a73d5fe3ddd8b3178.png

服务端需要填写验证 JWT 的 PEM 证书,那么我们要从 Auth0 的 API 中拿到这个信息。使用如下代码从 .well-known/jwks.json 中解析出来需要的证书,然后填写到 OpenSearch 中。

import requests
from jwcrypto import jwk
import json


# 配置
JWKS_URI = 'https://<domain>/.well-known/jwks.json'  # 替换为你的Auth0域名
OUTPUT_DIR = './pem_keys'  # 你希望保存PEM公钥的目录


# 创建输出目录
import os


if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)


# 获取JWKS
response = requests.get(JWKS_URI)
jwks = response.json()


# 处理每一个JWK
for index, jwk_key in enumerate(jwks['keys']):
    try:
        key = jwk.JWK(**jwk_key)
        pem = key.export_to_pem(private_key=False, password=None).decode('utf-8')
        kid = jwk_key['kid']


        # 将PEM格式公钥写入文件
        pem_file_path = os.path.join(OUTPUT_DIR, f'{kid}.pem')
        with open(pem_file_path, 'w') as pem_file:
            pem_file.write(pem)


        print(f'PEM格式公钥已保存到文件: {pem_file_path}')
    except Exception as e:
        print(f'处理公钥时出错: {e}')

左右滑动查看完整示意

配置好后,可以在 OpenSearch 的安全配置中看到 “View JWT details” 信息,验证 JWT 的有效性。通过标准的 JWT 流程使用 Postman 验证时,将 JWT 输入到 Bearer token 中,即可进行验证。

fe80f729bbfb1e2a71f1da4c79bc5c94.png

postman 测试 JWT

然后我们按照标准的 JWT 流程进行验证,这里使用 Postman,验证方式使用 Bear token,我们把通过应用程序模拟的 JWT 输入进去。

baea9b374fc6212ea72c9e92efa09486.png

编程方式访问 (Python)

我们也可以使用编程方式来进行访问,其实就是上加上一个 ‘Authorization’: ‘Bearer ’ 的请求头。

import requests


url = "OpenSearch URL"


payload = {}
headers = {
  'Authorization': 'Bearer <jwt token>'
}


response = requests.request("GET", url, headers=headers, data=payload)


print(response.text)

左右滑动查看完整示意

期待未来能够实现从控制台无缝跳转到 OIDC IDP,为用户提供更便捷和安全的使用体验。您可扫描下方二维码,继续阅读文中参考的一些文档。

参考文档

0bd1b4cd2a03c888d5b6a7d695a6ed55.png

参考文档 1

扫码了解更多

fbeb4e47e7e8769a3e5005c3106a96a5.png

参考文档 2

扫码了解更多

8bf5486387bb88f23037caa93f63a90e.png

参考文档 3

扫码了解更多

左右滑动查看更多

94b16261bd415f146baa6cfe40820e91.gif

星标不迷路,开发更极速!

关注后记得星标「亚马逊云开发者」

点击阅读原文查看博客,获得更详细内容

听说,点完下面4个按钮

就不会碰到bug了!

aaf3a486836ab4209f1d337346c6769d.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值