category
在本文的第一部分中,我们将Key斗篷安装到我们的Kubernetes集群中,并对其进行配置,使其可以从Internet访问。现在我们需要使用它。
Keycloak solution
强制身份验证
在本文中,我们将使用上一篇文章中使用的测试服务作为我们的微服务。目前应该可以通过APISIX的APISIX API网关访问该服务<CUSTOM DOMAIN>/worlds,因为这就是我们配置NGINX入口网关和APISIX的方式。
我们在本文中要做的是保护此服务的安全,以便您必须登录并验证自己,然后才能访问它。
此强制执行是在APISIX数据层内完成的,要求我们配置APISIX以检查经过身份验证的用户。
流
这将是流程:
- 用户尝试在没有有效令牌的情况下访问服务,并收到302重定向以登录
- 用户进入Keycloft并登录并接收加密cookie形式的令牌
- 用户现在再次访问该服务,这次使用令牌
- APISIX验证令牌是否有效
- APISIX提供对服务的访问
从API网关返回401
在针对API网关开发API的过程中,我很早就意识到了对302HTTP重定向状态的依赖。许多API网关被设计为在用户尚未登录的情况下返回302,从而将用户重定向到登录页面。
这突出了用户正在使用浏览器访问API并且浏览器能够理解302并重定向到登录的广泛假设。
但是,如果我们的客户端不是浏览器,而是系统呢?如果用户界面的设计者想在重定向发生之前做些什么呢?
虽然浏览器很容易理解302响应,但它可能不适合API的使用。在这些情况下,如果没有认证,则需要返回401以表明请求没有附加认证,如果用户被认证但未被授权,则返回403。
很高兴看到APISIX实际上有一个在两者之间切换的配置选项。在本文中,我们将使用302响应,就像使用浏览器一样,但您可以切换标志以获得401响应。
我是否已通过身份验证?
为了保护服务,我们需要检查用户是否已登录。我们将使用开放ID连接(OIDC)协议来实现这一点。你可以在我的另一篇文章中阅读有关OIDC的内容。
使用此协议(特别是隐式Fow 【Implicit Fow】),我们将只允许拥有有效JSON Web令牌(JWT——发音为“jot”)的用户访问服务。我们将使用Keycloak创建APISIX将验证的有效JWT。
要做到这一点,我们需要使用我们的用户信息来设置Keycloak,但稍后会有更多信息。
这是一个非常简单的用例,但为构建单一登录和基于角色的访问控制(RBAC)提供了基础。
APISIX检查身份验证
我们将首先配置APISIX来检查用户是否已通过身份验证,并在用户未通过身份验证时重定向到登录屏幕。
APISIX支持插件的概念,可以处理所有相关的请求。在这种情况下,我们将使用openid-connect插件。
这个插件需要四条我们还没有的信息:
- 存在此服务的领域
- 向Keycloft注册的客户端ID
- 与该客户端ID关联的密钥
- Kong可以从Keycloak加载所需配置的URL
配置Keycloak
APISIX需要作为Keycloak客户端安全访问Keycloak。这是通过在Keycloak中创建客户端配置来完成的。
使用本文第一部分中的管理员用户名和密码使用Key斗篷管理UI,登录到管理控制台。
多租户技术
多租户是指应用程序的单个实例(或集群)支持多个客户。每个客户都被称为租户。
在多租户应用程序中,每个租户都认为自己是该应用程序的唯一客户。他们既看不到也无法访问其他租户、他们的帐户或数据。
多租户应用程序
在某些情况下,租户可以在其租赁中创建多个用户,如下所示:
一个租赁中有多个用户
存在更复杂的结构,现有用户可以被邀请进入另一个租赁,因此可能存在于多个租赁中。我们不会在本文中讨论这个案例。
创造Realm
Keycloak支持多租户。这意味着Keycloak的单个实例可以支持多个租户,并且,如上所示,每个租户可以有多个用户。
Keycloak在提到租赁时使用了“Realm ”一词。
在我们开始配置任何东西之前,我们需要为我们的服务创建一个Realm。
登录到管理UI,单击主领域下拉菜单,然后单击创建领域。
创建Realm
在出现的屏幕中,您只需要给Realm一个名称。让我们称之为“我们的Realm ”。确保Realm已启用,然后单击“创建”。
现在应该向您问候:
钥匙斗篷欢迎页面进入新境界
现在我们可以访问我们的新Realm,是时候开始配置它了。我们现在不会使用任何特定于OAuth的功能,而是专注于OIDC。
对于那些善于观察的人来说,是的,OIDC是建立在OAuth之上的,但Key斗篷将仅身份验证的应用程序配置为OIDC应用程序,而将需要授权的应用程序则配置为OAuth应用程序。
创建客户端
现在我们有了一个境界,我们需要在这个境界中创建一个客户端。Key斗篷客户端是将使用Key斗篷作为其OIDC提供程序(或IdP)的应用程序或服务。在我们的案例中,APISIX和我们的微服务都是Key斗篷的潜在客户,但在这个解决方案中,我们只将APISIX连接到Key斗篷,因此只需要一个客户。
在主菜单上,确保选择了“我们的世界王国”,然后单击“客户端”。
为了简洁起见,我不会向您展示如何做到这一点的所有屏幕截图,而是会告诉您整个过程。这也将使我能够帮助您了解我们正在做什么,而不是专注于我们是如何做的。
您将看到Key斗篷自动注册一组客户端,用于其自身的内部目的。我们可以忽略这些。
我们将通过点击创建客户端来创建我们自己的客户端。现在输入以下信息:
- 客户端类型【Client type】——OpenID Connect…这允许APISIX使用Keycapture作为基于OAuth的用户身份验证(OIDC)流的一部分。
- 客户端ID【Client ID】-apisix…这个命令告诉Keycapture如何识别这个客户端。它可以是任何东西。在这种情况下,我们只是将其命名为与我们的APISIX API网关相同
- 名字【Name】——apisix……对于我们的客户来说,这是一个很好的、可读的名字。
描述是可选的。
单击“下一步”。
现在有三种选择:
- 客户端身份验证【Client authentication】——打开……通过打开此选项,我们表示我们的客户端(APISIX)能够安全地保存其身份验证机密。
- 授权【Authorization】--关闭。。这意味着我们不会授权客户使用细粒度访问控制(即:我们只使用OIDC功能)。
- 身份验证流【Authentication flow】——仅限标准流和隐式流…我们将使用隐式流。
单击“下一步”。
在此页面上,我们配置了有关URL使用方式的约束:
- Root URL--
https://apisix.<CUSTOM DOMAIN>
… 设置它很有用,因为这意味着你不必一直键入根URL,并且可以将其他所有内容都保留为相对路径。 - Home URL --/worlds…这是“如果有疑问,请返回主页”URL。每当OAuth流失败、用户最终出现在不该出现的位置或注销后,都会使用它。
- Valid redirect URIs -/*…当应用程序请求时,这个列表告诉Keycapture它可以重定向到哪里。它旨在防止恶意行为者在您不知情的情况下插入自己的重定向。如果Key斗篷重定向到其他地方,它将拒绝该请求。
- Valid post logout redirect URIs -/*…与重定向URI一样,此列表告诉Keycapture在用户注销后可以重定向到哪里。
- Web origins -+…这告诉跨来源资源共享(CORS)客户可能来自哪里。输入+表示来自任何重定向URI位置。
单击“保存”。
保存后,您现在可以获得更多的配置选项!
由于这不是一个钥匙斗篷教程,我们将做足够的事情来让我们开始。
单击凭据选项卡。找到客户端机密,然后单击眼睛以揭示机密。你以后需要这个秘密。
著名的API
还有一条信息,我们需要从Keycapture,众所周知的API URL。
是客户端需要从IdP获得的大量信息,包括API端点、用于签署JWT的证书等。这些信息可通过称为.已知端点的标准端点获得。
要查找此端点的地址,请转到主菜单上的Realm settings选项。在“常规”选项卡上,滚动到底部以找到“端点”部分。
单击OpenID端点配置。出现的页面的URL就是您需要的URL。
您可以浏览页面以查看客户端可用的信息类型。
所以现在你应该有:
- The client ID (
apisix
) - The client secret
- The
.well-known
URL
配置APISIX
有了所需的信息,我们现在可以安装APISIX的OIDC插件。我们在每一条我们想要保护的路线上都这样做。如果您遵循了我的APISIX安装文章,您将获得以下文件,我们将用粗体标记的行对其进行扩展(用您自己的值替换<>字段):
apisix-hw-route.yml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: hellow-world-route
namespace: default
spec:
http:
- name: hello-world
match:
hosts:
- apisix.requillion-solutions.cloud
paths:
- /*
backends:
- serviceName: hello-world-1-svc
servicePort: 80
weight: 70
- serviceName: hello-world-2-svc
servicePort: 80
weight: 30
plugins:
- name: proxy-rewrite
enable: true
config:
uri: "/"
- name: openid-connect
enable: true
config:
client_id: apisix
client_secret: <CLIENT SECRET>
discovery: http://my-kc-service.kc:8080/realms/Our%20World/.well-known/openid-configuration
scope: openid profile
bearer_only: false
realm: Our World
introspection_endpoint_auth_method: client_secret_post
redirect_uri: /redirect_url
您可以看到,我们只在文件的底部添加了openid连接插件。然后,我们启用并配置如下:
- client_id…这被设置为我们在设置Key斗篷客户端时使用的客户端id,apisix
- client_secret…这是为我们生成的客户端机密密钥斗篷
- 发现…这是我们较早发现的众所周知的端点,但您会注意到我们正在使用主机的内部DNS名称,而不是外部名称
- scope…这定义了我们所要求的范围,在这种情况下,我们必须包括openid才能使用OIDC,并添加了概要文件以获取有关用户的更多信息(即:用户名)
- bear_only…这是一个标志,当为false时,当用户未经身份验证时,返回302重定向到登录(true返回401)
- 领域…我们正在使用的领域(我们的世界)
- 内省endpoint_auth_method…定义APISIX将如何从Key斗篷中检索访问令牌(使用前面定义的客户端机密的POST)
- redirect_url…用户在经过身份验证后(即:登录后)将返回的位置——必须由Key斗篷客户端配置允许
当您的OIDC或OAuth配置出现问题时,很可能是重定向url的定义。在我们的案例中,我们重定向到https://apisix.<CUSTOM DOMAIN>/redirect_url,由于我们定义路由(/*)的方式,它将只提供我们的hello-word测试服务。由于我们现在已通过身份验证,它将按预期提供服务。
现在,我们将更改应用于现有路线(如果是新路线,则创建一个新路线):
kubectl apply -f apisix-hw-route.yml
最终配置
还有一个配置更改必须进行。当返回加密的令牌时,NGINX代理模块在传递数据之前会耗尽容纳数据的空间。这可能导致NGINX网关返回500状态。
为了防止这种情况发生,我们需要修改代理设置。以root用户身份登录到gw服务器,然后通过添加粗体行来修改以下文件:
/etc/nginx/proxy_params
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_busy_buffers_size 32k;
proxy_buffers 4 32k;
proxy_buffer_size 16k;
使用以下内容测试配置并重新加载新设置:
nginx -t
systemctl restart nginx
测试配置
现在我们已经配置了Key斗篷和APISIX,现在我们可以测试设置了。
在浏览器中输入以下内容:
apisix.<CUSTOM DOMAIN>/worlds
而不是看Hello World 1!!响应,您现在将直接进入Keycloft登录屏幕。你无法通过这一点,因为你没有登录。你唯一的登录名是管理员用户,但他们属于主领域,无法登录我们的世界领域。
要解决此问题,请登录Key斗篷管理UI并转到我们的世界王国。从左侧的主菜单中选择“用户”。
- 单击“添加用户”
- 添加用户名(例如:Bob)
- 单击电子邮件验证,使其打开(即:无需验证,因为我们尚未设置传出电子邮件)
- 单击“创建”
此时,您将看到更多选项。选择凭据选项卡。
- 单击“设置密码”
- 输入密码并确认
- 取消选中临时(除非您希望用户在登录后被迫更改它)
- 单击“保存”
现在,刷新您的https://apisix.<CUSTOM DOMAIN>/worlds页面并使用您刚刚创建的用户登录。
登录后,您将看到Hello World 1!!(如果您正在使用我的测试服务)。如果你刷新,你将不会被要求登录。如果你刷新足够的次数,你将看到Hello World 2!!10次中有3次响应。
祝贺您,您已经使用APISIX和Keycloft获得了对服务的访问权限。如果你保护任何其他服务,你现在会意识到,如果它们在同一领域,你可以在所有服务中使用单一登录(SSO)。
那么发生了什么
在这个解决方案中,我们使用的是隐式流。当应用程序无法存储机密时,将使用此流。浏览器就是这样一个应用程序,这就是我们使用隐式流的原因。
流程如下:
Request: /worlds
Response: redirect (302) to /auth ? scope=xxx & state=xxx & client_id=xxx & response_type=xxx & redirect_uri
Request: .../auth ? (params)
Response: login page
Request: .../authenticate ? (params)
Response: redirect to (redirect_url) ? (params)
Request: (redirect_url) ? (params)
Response: redirect to /worlds setting session cookie
Request: /worlds with session cookie
Response: Hellow world response
第一个请求导致重定向,因为没有cookie。
重定向到Key斗篷/auth包含一些参数,这些参数定义了访问服务所需的身份验证,包括身份验证后要遵循的重定向URL。
/auth端点在/authenticate处返回一个登录页面。登录的结果是重定向回重定向URL。该重定向被APISIX拦截,并导致APISIX根据重定向中的参数从Keycloft获取令牌。
然后对令牌进行加密,并将其作为原始域的cookie添加回响应中。响应是重定向到原始/世界URL。
在重定向之后,浏览器现在发送会话cookie。这将由APISIX进行验证,然后将请求直接传递给服务。
如果您再次调用/worlds,会话cookie将被传递,您将立即收到响应。
如果您转到/注销,APISIX会截获请求,并使用会话cookie将您重定向到Keycloft上的/注销。在确认您要注销后,它会清除会话cookie并将您发送回/worlds。
由于此URL受到保护,您将立即返回登录页面!
总结
在这篇文章中,我们…
- 研究了使用OIDC保护我们服务的方法
- 讨论了从API网关返回302或401之间的区别
- 创建了一个密钥斗篷领域创建并配置了APISIX作为密钥斗篷客户端
- 从Keycloft获得我们需要的信息
- 修改了APISIX路由以保护我们的测试服务
- 更新了NGINX配置
- 已测试配置
- 看看发生了什么
如果你发现这篇文章感兴趣,请给我一个掌声,因为这有助于我确定人们认为什么是有用的,以及我未来应该写什么文章。如果您有任何建议,请在评论部分添加。
- 登录 发表评论
- 31 次浏览
最新内容
- 2 hours ago
- 23 hours 57 minutes ago
- 1 week 2 days ago
- 1 week 2 days ago
- 1 week 2 days ago
- 1 week 2 days ago
- 1 week 2 days ago
- 2 weeks 1 day ago
- 2 weeks 2 days ago
- 2 weeks 5 days ago