本文介绍了如何通过 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 的授权功能进行验证;
总结:对全文的总结。
Keycloak 是一个开源并广泛应用于用户身份管理与授权的解决方案。Keycloak 支持多种协议和标准,包括 OpenID Connect,OAuth2.0和SAML2.0。同时 Keycloak 可以集成与已有的 LDAP 或者 Active Directory 服务集成,用于单点登录。基于 OAuth2.0,Keycloak 还可以通过 JWT Token 完成对 API 的鉴权,本文基于此场景,结合 Keycloak 通过 Amazon Gateway 的 Authorizer 完成请求的鉴权。
OAuth2.0全称为 Open Authorization 2.0,为用于鉴权的协议。通过 OAuth 协议,可以授权第三方应用请求用户的资源,而不需要资源的拥有者直接向第三方提供任何验证凭据信息。 OAuth2.0 鉴权流程
1.3 关于 Amazon API Gateway Authorizer
在本文中,我们以 HTTP API 为例,利用 HTTP API 已内置的授权功能进行 API 请求的鉴权。如果使用 REST API,则需要通过结合 Lambda 进行 JWT Token 的校验,可参照此说明文档进行配置。
在本设计中,用户通过调用 API Gateway 中定义好的 API ,访问 Amazon 上的数据库资源。我们通过定义2个路由,并集成 Lambda 函数,完成对 DynamoDB 数据的读/写。
DynomoDB 设置
API Gateway 设置
创建 API Gateway,为 API Gateway 创建2条路由,并关联 Lambd 函数,列表如下:
Lambda 函数样例
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)
"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"
}
]
}
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)
{
"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.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 的建立,我们可以:
2.3.3 Keycloak Client 的建立
注意,如没有特别的需求,尽量避免使用 “Implicit Flow” 即关闭 “Implicit Flow Enabled” 。这种方式没有授权码这个中间步骤,所以称为(授权码)”隐藏式”(implicit)。这将会把 Token 直接传给前端,是很不安全的,因此,只能用于一些安全要求不高的场景。
2.3.4 Keycloak User 的建立
GET https://{Keycloak_URL}/auth/realms/Keycloaksso/protocol/openid-connect/auth?response_type=code&client_id=Keycloak
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"
}
access_token
粘贴在 Authorization header 中,格式为:Bearer {access_token}
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"
由于当前 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