通过 Keycloak 结合 OAuth2.0协议进行 Amazon API Gateway 鉴权

news2024/11/18 3:30:04

1. 简介

本文介绍了如何通过 Keycloak,并结合 Amazon API Gateway 内置的授权功能,完成对 Amazon 资源请求的鉴权过程。API Gateway 帮助开发者安全的的创建、发布、维护并管理 API 的访问。在中国区,由于Cognito 仍未上线,因此使用 Keycloak 作为 API 调用的鉴权服务,具有重要的实际意义。

亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术,观点,和项目,并将中国优秀开发者或技术推荐给全球云社区。如果你还没有关注/收藏,看到这里请一定不要匆匆划过,点这里让它成为你的技术宝库!

本文共分为四大模块:

简介:对 Keycloak、OAuth2.0以及 Amazon API Gateway Authorizer 进行了介绍;

配置说明:对环境的设定进行了详细的说明,包括 DynamoDB 的设定以及 Keycloak 环境的搭建和设置;

验证 JWT Authorizer:通过 Postman 对 API Gateway 的授权功能进行验证;

总结:对全文的总结。

1.1 关于 Keycloak

Keycloak 是一个开源并广泛应用于用户身份管理与授权的解决方案。Keycloak 支持多种协议和标准,包括 OpenID Connect,OAuth2.0和SAML2.0。同时 Keycloak 可以集成与已有的 LDAP 或者 Active Directory 服务集成,用于单点登录。基于 OAuth2.0,Keycloak 还可以通过 JWT Token 完成对 API 的鉴权,本文基于此场景,结合 Keycloak 通过 Amazon Gateway 的 Authorizer 完成请求的鉴权。

1.2 关于OAuth2.0

OAuth2.0全称为 Open Authorization 2.0,为用于鉴权的协议。通过 OAuth 协议,可以授权第三方应用请求用户的资源,而不需要资源的拥有者直接向第三方提供任何验证凭据信息。 OAuth2.0 鉴权流程

image.png

1.3 关于 Amazon API Gateway Authorizer

在本文中,我们以 HTTP API 为例,利用 HTTP API 已内置的授权功能进行 API 请求的鉴权。如果使用 REST API,则需要通过结合 Lambda 进行 JWT Token 的校验,可参照此说明文档进行配置。

2. 配置说明

image.png

在本设计中,用户通过调用 API Gateway 中定义好的 API ,访问 Amazon 上的数据库资源。我们通过定义2个路由,并集成 Lambda 函数,完成对 DynamoDB 数据的读/写。

  • GET /items:不需要进行鉴权,可以直接通过 API Gateway 获取DynamoDB 数据。
  • POST /items:需要进行鉴权,通过 API Gateway 校验请求 Token,验证成功后,向 DynamoDB 写入数据。
2.2 预置条件
  • 创建一个 DynamoDB Table,DemoTable。
  • 在 Amazon API Gateway 创建 HTTP API,并与 Lambda 进行集成。

DynomoDB 设置

image.png

  • 分区键:pk
  • 排序键:sk
  • 其他保留默认配置

API Gateway 设置

创建 API Gateway,为 API Gateway 创建2条路由,并关联 Lambd 函数,列表如下:

image.png

Lambda 函数样例

  • GetItemsLambda
import boto3
import os
import json
import botocore
 
def lambda_handler(event, context):
    try:
        client = boto3.resource("dynamodb")
        table_name = os.environ.get('DDB_TABLE')
        table = client.Table(table_name)
        scanning_result = table.scan()
 
        return {
            'statusCode': 200,
            'body': json.dumps(scanning_result),
            'headers': {
                    'Content-Type': 'application/json'
                },
            'isBase64Encoded': 'false'
        }
    except botocore.exceptions.ClientError as e:
        print(e)

  • GetItemsLambdaRole Policy:
"Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "dynamodb:DescribeTable",
                "dynamodb:Query",
                "dynamodb:Scan"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:123456789012:table/DemoTable"
            ],
            "Effect": "Allow"
        }
    ]
}

  • CreateItemsLambda:
import json
import datetime
import boto3
import os
import botocore
import uuid
 
def lambda_handler(event, context):
    try:
        client = boto3.client('dynamodb')
        table_name = os.environ.get('DDB_TABLE')
        req_body = json.loads(event["body"])
        req_user = event["requestContext"]["authorizer"]["jwt"]["claims"]["email"]
        ct = datetime.datetime.now()
        client.put_item(
            TableName = table_name,
            Item = {
                'pk': {'S':req_user},
                'sk': {'S':'item#' + str(uuid.uuid4())},
                'title': {'S':req_body["title"]},
                'timeCreated': {'S': ct.isoformat()}
                 
            }
                )
                 
        return {
            'statusCode': 200,
            'body': json.dumps('New Item Created')
        }
    except botocore.exceptions.ClientError as e:
        print(e)

  • CreateItemsLambdaRole Policy:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:GetRecords",
                "dynamodb:GetShardIterator",
                "dynamodb:Query",
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:ConditionCheckItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem"
            ],
            "Resource": [
                " arn:aws:dynamodb:us-east-1:123456789012:table/DemoTable "
            ],
            "Effect": "Allow"
        }
    ]
}

2.3 Keycloak 的设定

2.3.1 Keycloak 的安装

关于 Keycloak 的安装,请参照 blog:使用 SAML 和 Keycloak 建立 Amazon SSO 登陆 Console

2.3.2 Keycloak realm 的建立

Realm 可以理解为域,用于管理用户、用户凭据、角色和用户组。通常我们需要在 realm 里创建 client ,不同的应用客户端应在 realm 中配置不同的 client 。当进行鉴权时,请求资源的应用客户端会向鉴权服务器请求 Auth Code ,正如上文中 OAuth2.0鉴权流程 第2步所示。为了完成 Keycloak realm 的建立,我们可以:

  1. 登陆 keycloak admin console,点击 “Administration Console” 并登陆;

image.png

  1. 创建一个 realm,并进入到 realm 中;

image.png

2.3.3 Keycloak Client 的建立

  1. 在 realm 中点击 “Configure-> Clients-> Create”;

image.png

  1. 按照下面的说明输入相关信息;注意选择 Standard Flow Enabled,这将会使 client 的鉴权按照0的 “Authorization Code Flow” 完成,即 OAuth2.0鉴权流程所示。

注意,如没有特别的需求,尽量避免使用 “Implicit Flow” 即关闭 “Implicit Flow Enabled” 。这种方式没有授权码这个中间步骤,所以称为(授权码)”隐藏式”(implicit)。这将会把 Token 直接传给前端,是很不安全的,因此,只能用于一些安全要求不高的场景。

image.png

  1. 在 “Credentials tab” 中,选择 Client Id and Secret,此时会生成一串随机字符串作为Secret。在上文中 OAuth2.0鉴权流程 第6步中交换 Token 的过程中,Secret 将作为 client_secret 的值,在应用客户端的 POST Body 中被发送到 Keycloak Client 中,以确保向 Client 交换的 Token 颁布给了正确的应用客户端。

2.3.4 Keycloak User 的建立

  1. 创建测试用的 User,点击左侧 Manage-> Users-> Add user”;

image.png

  1. 输入 User 信息;

image.png

  1. 设定密码,输入密码,并输入 Password Confirmation,点击 Reset Password 以完成设置。

image.png

2.4 API Gateway Authorizer 的设定
  1. 进入到上文创建的 API Gateway 中,由于我们的目的是在创建 item 时,需要进行 API 鉴权,因此只在 POST /items 的路由上附加授权方即可:

image.png

  1. 输入相关信息;

image.png

  • 身份来源:通常情况下,在请求资源服务器时,会将 JWT Token 写入到请求头中的 Authorization 字段,因此可以保留默认。
  • 发布者 URL:针对 Keycloak 为https://{Keycloak_URL}/auth/realms/{realm}/
  • 受众:关联的受众,此处输入 account

3. 验证 JWT Authorizer

3.1 请求 Auth Code
  1. 根据 OAuth2.0鉴权流程,当用户请求资源时,应用客户端将会向鉴权服务器发送 GET 请求,以请求 Auth Code;
GET https://{Keycloak_URL}/auth/realms/Keycloaksso/protocol/openid-connect/auth?response_type=code&client_id=Keycloak

  1. 在此过程中,鉴权服务器将会返回 Keycloak 的登陆界面,要求用户输入其用户名密码,在此处,我们输入 Keycloak User 的建立章节中创建的 User 的用户名和密码。

image.png

  1. 输入正确的用户名和密码后,Keycloak 将会通过 Query String 返回 Auth Code,如下图所示;

image.png

3.2 交换 JWT Token
  1. 接下来,我们通过 Postman 模仿应用客户端,模拟通过 POST Auth Code 换取 JWT Token 的过程;

image.png

  • client_id: Keycloak的client ID,为 Keycloak Client 的建立 章节中创建;
  • grant_type: 0的鉴权模式,我们通过 authorization code 模式鉴权,这也是最常见的模式;
  • client_secret: 用于 Client 应用客户端的验证;
  • code:Auth Code,由鉴权服务器返回,用于交换 Token。
  1. 将 Postman 的请求用 curl 实现:
curl --location --request POST 'https://{Keycloak_URL}/auth/realms/Keycloaksso/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: AUTH_SESSION_ID=a0b56dbf-19b0-4d16-b254-c25248834c01.Keycloak-5b7448f8cf-v5wg6; AUTH_SESSION_ID_LEGACY=a0b56dbf-19b0-4d16-b254-c25248834c01.Keycloak-5b7448f8cf-v5wg6; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyYjQ0M2Q2ZS00MzNiLTQwYTQtYjdlMi03MDk2Mjg1YTJkYmMifQ.eyJjaWQiOiJrZXljbG9hayIsInB0eSI6Im9wZW5pZC1jb25uZWN0IiwicnVyaSI6IioiLCJhY3QiOiJBVVRIRU5USUNBVEUiLCJub3RlcyI6eyJpc3MiOiJodHRwczovL2F1dGguY2lhdGVzdC50b3AvYXV0aC9yZWFsbXMva2V5Y2xvYWtzc28iLCJyZXNwb25zZV90eXBlIjoiY29kZSJ9fQ.5T6tBz-j7vbfzvhHBpPnQ2ebRqYC69gNF-EMlWmsA8Q' \
--data-urlencode 'client_id=Keycloak' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_secret=bba58d29-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
--data-urlencode 'code=74926370-xxxx-xxxx-xxxx-xxxxxxxxxxxx.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Response:

    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDExOTksImlhdCI6MT….m91pmRMmSnA0D37qF4_...",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDI2OTksImlhdCI6MT….OaDarszhAnyd3NKZTiZ…",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "session_state": "aa8b66e0-xxxx-xxxx-xxxx-6ff28b1213d5",
    "scope": "profile email"
}

3.3 向 API Gateway 请求创建资源
  1. 通过 Postman 模仿应用客户端,模拟创建 item 的过程;

image.png

  • Authorization:将2中返回的 access_token 粘贴在 Authorization header 中,格式为:Bearer {access_token}
  1. 将 Postman 的请求用 curl 实现:
curl --location --request POST 'https://80iiueir8b.execute-api.us-east-1.amazonaws.com/items' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDExOTksImlhdCI6MT….m91pmRMmSnA0D37qF4_...\
--header 'Content-Type: application/json' \
--data-raw '{"title":"nike high heel"}'

Response:

"New Item Created"

  1. 通过浏览器 GET /item 查看 item 是否写入成功:

image.png

4. 总结

由于当前 Cognito 在中国区仍不可用,Keycloak 可以作为一个替代方案,完成用户的单点登录和 API 的鉴权。本 blog 提供了如何结合 API Gateway 的 HTTP API,利用 Keycloak 和 JWT 进行 API 鉴权的演示。通过这种方式,应用客户端在请求 Amazon 资源时,需要通过 Keycloak 服务器进行校验,并换取有效的 JWT Token,以获得访问资源的权限。

如有兴趣了解本文提到的更多技术,请参照:

OAuth2.0 Grant Type

Json Web Token

使用 SAML 和 Keycloak 建立 Amazon SSO 登录 Console

How to secure API Gateway HTTP endpoints with JWT authorizer

本篇作者

李潇翌 亚马逊云科技专业服务团队安全顾问,负责云安全合规、云安全解决方案等的咨询设计及落地实施,致力于为客户上云提供安全最佳实践,并解决客户上云中碰到的安全需求。

文章来源:https://dev.amazoncloud.cn/column/article/630b4bf9269604139cb5e9ed?sc_medium=regulartraffic&sc_campaign=crossplatform&sc_channel=CSDN

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/972275.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows 不能ping通虚拟机问题

先查看windows网卡 查看虚拟机种 对应VMnet8种的 nat (我用的是这种连接方式)设置 问题是不在同一个网段,修改windows VMnet8网卡的配置 保证网关、网段是一样的 现在ping问题解决,也能windows远程连接虚拟机

vue3请求成功后实现类似打字效果输出

要在 Vue 3 中实现请求成功后的类似打字效果输出,您可以使用 ​axios​ 或其他适合您的方法来发起异步请求。在请求成功后,您可以将返回的文本存储在响应式对象中,并使用一段时间间隔逐个字符地将文本输出到界面上。下面是一个示例代码&#…

【python爬虫】14.Scrapy框架讲解

文章目录 前言Scrapy是什么Scrapy的结构Scrapy的工作原理 Scrapy的用法明确目标与分析过程代码实现——创建项目代码实现——编辑爬虫代码实现——定义数据代码实操——设置代码实操——运行 复习 前言 前两关,我们学习了能提升爬虫速度的进阶知识——协程&#xf…

二进制搭建kubernetes(K8S)

二进制搭建kubernetes(K8S) 一、常见的K8S部署方式1.Minikube2.Kubeadmin3.二进制安装部署 二、二进制搭建K8S(单台master)1.部署架构规划2.系统初始化配置3.部署 docker引擎4.部署 etcd 集群4.部署 Master 组件5.部署 Worker Node 组件6.部署网络组件 三…

DevOps管理软件生命周期

整体的软件开发流程 PLAN:开发团队根据客户的目标制定开发计划 CODE:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。GIT,SVN BUILD:编码完成后,需要将代码构建并且运行。MAVEN TEST:成功构建…

软件测试/测试开发丨Selenium Web自动化多浏览器处理

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27185 一、多浏览器测试介绍 1.1、多浏览器测试背景 用户使用的浏览器(firefox,chrome,IE 等)web 应用应该能在任何浏览器上正常的工作,这样…

配置本地maven

安装maven安装包 修改环境变量 vim ~/.bash_profile export JMETER_HOME/Users/yyyyjinying/apache-jmeter-5.4.1 export GOROOT/usr/local/go export GOPATH/Users/yyyyjinying/demo-file/git/backend/go export GROOVY_HOME/Users/yyyyjinying/sortware/groovy-4.0.14 exp…

2023-9-4 筛法求欧拉函数

题目链接&#xff1a;筛法求欧拉函数 #include <iostream> #include <algorithm>using namespace std;typedef long long LL;const int N 1000010;int primes[N], cnt; int phi[N]; bool st[N];LL get_eulers(int n) {phi[1] 1; for(int i 2; i < n; i){if(!…

Mybatis的关系关联配置

前言 MyBatis是一个流行的Java持久化框架&#xff0c;它提供了一种简单而强大的方式来映射Java对象和关系数据库之间的数据。在MyBatis中&#xff0c;关系关联配置是一种用于定义对象之间关系的方式&#xff0c;它允许我们在查询数据库时同时获取相关联的对象。 在MyBatis中&…

数学建模--非整数规划求解的Python实现

目录 1.算法流程简介 2.算法核心代码 3.算法效果展示 1.算法流程简介 #非线性规划模型求解: #我们采用通用的minimize函数来求解 #minimize(f,x,method,bounds,contrains) #f是待求函数 #x是代求的自变量 #method是求解方法 #bounds是取值范围边界 #contrains是约束条件 &q…

vscode 上传项目到gitlab

第一步初始化项目 如果没有创建过分支&#xff08;创建分支这里不记录&#xff09;&#xff0c;默认是master分支&#xff1a; ①将所需要的上传的文件添加到暂存区&#xff0c;如图&#xff1a; ②填写一下注释信息&#xff0c;将暂存区的文件上传到本地分支&#xff08;没有创…

vue仿企微文档给页面加水印(水印内容可自定义,超简单)

1.在src下得到utils里新建一个文件watermark.js /** 水印添加方法 */let setWatermark (str1, str2) > {let id 1.23452384164.123412415if (document.getElementById(id) ! null) {document.body.removeChild(document.getElementById(id))}let can document.createE…

vue使用jsencrypt实现rsa前端加密

实现 RSA 加密 介绍 vue 完成 rsa 加密传输&#xff0c;jsencrypt 实现参数的前端加密 1 安装 jsencrypt npm install jsencrypt2 编写 jsencrypt.js 在 utils 文件夹中新建 jsencrypt.js 文件&#xff0c;内容如下&#xff1a;注意点&#xff1a;一般公钥都是后端生成好的&a…

thinkphp6 入门(4)--数据库操作 增删改查

一、设计数据库表 比如我新建了一个数据库表&#xff0c;名为test 二、配置数据库连接信息 本地测试 直接在.env中修改&#xff0c;不用去config/database.php中修改 正式环境 三、增删改查 引入Db库 use think\facade\Db; 假设新增的控制器路径为 app\test\control…

【深度学习】基于卷积神经网络的铁路信号灯识别方法

基于卷积神经网络的铁路信号灯识别方法 摘 要&#xff1a;1 引言2 卷积神经网络模型2.1 卷积神经网络结构2.2.1 卷积层2.2.2 池化层2.2.3 全连接层 3 卷积神经网络算法实现3.1 数据集制作3.2 卷积神经网络的训练过程3.2.1 前向传播过程 4 实验5 结语 摘 要&#xff1a; 目前中…

ctfhub ssrf(3关)

文章目录 内网访问伪协议读取文件扫描端口 内网访问 根据该题目&#xff0c;是让我们访问127.0.0.1/falg.php&#xff0c;访问给出的链接后用bp抓包&#xff0c;修改URL&#xff0c;发送后得到flag&#xff1a; 伪协议读取文件 这题的让我们用伪协议&#xff0c;而网站的目录…

【算法】树上倍增 LCA

文章目录 相关链接模板题目1483. 树节点的第 K 个祖先最近公共祖先LCA的求法 练习题目2836. 在传球游戏中最大化函数值2846. 边权重均等查询 扩展题目 相关链接 把相关链接放在最前面是因为&#xff0c;周赛遇到了几次&#xff0c;不会做。这才想起来学一下这个算法。 【力扣…

快讯 | ALVA 荣获首届“格物杯”联通物联网应用创新大赛复赛一等奖!

8 月 7 日&#xff0c;“物聚龙江 智联百业”物联网创新发展合作交流暨首届“格物杯”联通物联网应用创新大赛企业赛道复赛 (赛区四)在哈尔滨举办。 ALVA Systems 凭借智能远程协助平台—— ALVA Rainbow 在近 50 家企业中脱颖而出&#xff0c;荣获首届“格物杯”联通物联网应…

Docker的数据管理(持久化存储)

文章目录 一、概述二、数据卷三、数据卷容器四、端口映射五、容器互联&#xff08;使用centos镜像&#xff09;总结 一、概述 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&a…

Hadoop的概述与安装

Hadoop的概述与安装 一、Hadoop内部的三个核心组件1、HDFS&#xff1a;分布式文件存储系统2、YARN&#xff1a;分布式资源调度系统3、MapReduce&#xff1a;分布式离线计算框架4、Hadoop Common&#xff08;了解即可&#xff09; 二、Hadoop技术诞生的一个生态圈数据采集存储数…