Kubernetes Authentication Sidecars:微服务架构的启示
Kubernetes Authentication Sidecars:微服务架构的启示
作为软件工程师,我们花费太多时间设置身份验证和调试与身份验证相关的问题。我们都陷入了一个兔子洞,我们的身份验证方法没有达到我们的预期,我们失去了几天(和头发)摸不着头脑!
随着微服务采用的增长,我们需要实现身份验证的服务越来越多。在任何组织中,现在都有数百种不同的方式来处理身份验证,并且使用了许多不同的库。
随着时间的推移,我们学会了将一些跨领域的问题,例如 SSL 终止和 IP 授权转移到负载均衡器、API 网关和反向代理。最近,Istio 和 Linkerd 等服务网格出现了,通过使用与我们的服务在同一个 Kubernetes pod 中运行的 sidecar 容器,帮助我们解决了一些更接近应用程序运行位置的问题。
Sidecar 方法也可用于卸载身份验证,以便我们的自定义应用程序无需担心它。本文展示了如何将 ASP.NET YARP 用作反向代理来验证下游应用程序的请求,但是,任何技术都可以用于下游应用程序,只要它使用 HTTP。
此处讨论的反向代理思想并非特定于 .NET,并且可以使用大多数 Web 技术来实现。
身份验证代理的完整代码可以在我的 GitHub 上找到 这里 .
认证的历史
因此,在我们研究使用 sidecar 解决身份验证问题之前,让我们先看看身份验证是如何演变的。
Cookie 身份验证
一段时间以来,Cookie 一直被用于对前端应用程序进行身份验证,但传统上它们有一些缺点:
- CSRF 攻击 — CSRF 攻击是一种强制用户发出带有附加 cookie 的意外请求的攻击。
- 会话 cookie — cookie 通常是有状态的并与特定的服务器绑定,因此很难加载和平衡我们的应用
智威汤逊认证
随之而来的是 JSON Web Tokens,它通过提供自我验证的无状态令牌帮助我们解决了 cookie 的一些缺点。可以对 JWT 进行解码以检索用户的声明,并使用公钥在任何服务器上进行验证。
由于这些原因,近年来,JWT 一直被发起人推为身份验证的圣杯……不幸的是,我们的故事并没有就此结束!使用 JWT 有一些人们经常忽略或不理解的关键缺点(有一篇很棒的文章解释 这里 如果您想了解更多):
- 撤销 — 无法撤销 JWT。即使 JWT 被泄露,它仍然有效直到过期,从而导致严重的安全漏洞。
- XSS 攻击——JWT 通常存储在浏览器的 localStorage 中,使其容易受到跨站点脚本攻击。当攻击者在您的网站上运行恶意 JavaScript 以提取 JWT 并将其发送到其他地方时,就会发生 XSS。
网络安全救援!
幸运的是,随着时间的推移,许多与 cookie 和 JWT 相关的问题都已通过安全功能得到解决:
- 'SameSite' cookie 策略 — 现在可以在 cookie 上定义 cookie 策略,以限制它们在不同站点中的使用。如果
严格的
或者松懈
使用,则限制跨站点使用。 - 'HttpOnly' cookie — 现在可以将 Cookie 标记为 HttpOnly,这可以防止客户端脚本访问它们以阻止 XSS 攻击。
- 数据保护密钥 — 用于加密 cookie 的密钥现在可以安全地集中存储,以便分布式计算可以与 cookie 一起使用。
- CORS 和 CSP — 现在可以在浏览器中实施 CORS 和内容安全策略,以防止 CSRF 和 XSS 攻击。
JWT 已死;饼干万岁!
好的,您可以对这个标题持怀疑态度... JWT 仍然是验证用户身份的绝妙方法,但重要的是要意识到风险 - 确保使用短期到期并尽可能限制服务器端请求.
饼干怪兽——图片来源:facebook.com
除了它们的安全优势外,cookie 通常使我们的应用程序更加简单,因为我们不需要自定义代码来将它们附加到请求或挑战访问我们网站的未经身份验证的用户。
最近,人们开始将他们的 JWT 安全地存储在 HttpOnly cookie 中,以获得两全其美的效果。
自我认证方法
我们需要实施的所有这些不同的选项和网络安全策略听起来很复杂,不是吗?嗯,你是对的。身份验证有点像雷区,而不是您想弄错的东西!
然而,知道这一点,我们的团队和服务通常会自行执行所有身份验证逻辑。当使用这种方法时,当我们创建一个新项目时,我们必须解决的第一件事就是身份验证。
使用 JWT 进行自我认证的典型流程如下所示:
自我认证方法
通常 JWT 用于对用户进行身份验证,这意味着我们的应用程序必须解决两个不同的问题:
- 必须在前端编写代码以检索访问令牌并将它们附加到请求中
- 令牌必须在服务器端验证以验证用户
有许多身份验证 SDK 可以提供帮助,团队通常使用自己的库来扩展这些 SDK。我们最终采用了这种方法,因为我们所有的开发人员都必须很好地理解这个问题,并且正在使用大量不同的方法和库。
Sidecar 身份验证方法
为了减轻自我身份验证方法的这些缺点,可以使用边车容器代理对我们服务的请求,并在请求到达我们的代码之前执行身份验证。
Sidecar 模式是一种解耦模式,其中服务的支持功能由附加到主服务的 Sidecar 容器提供。 Sidecar 位于同一个 Kubernetes Pod 中,并与其关联的服务共享相同的生命周期,与服务一起创建和终止。
身份验证可以通过 sidecar 代理以多种不同方式处理,但以下是我使用的方法:
Sidecar 身份验证方法
- OpenId Connect with Authorization Code Flow 用于挑战未认证用户,认证后保存会话cookie
- 这
访问令牌
和刷新令牌
存储在 cookie 中。这允许任何 sidecar 实例使用 cookie 来刷新访问令牌
并将其发送给下游应用程序,以便他们可以在需要时使用它 - 共享相同的数据保护密钥,以便 cookie 可用于不同的组件和实例,例如负载平衡服务或其他微服务
- 用户的身份通过 headers 传递给下游服务
- ASP.NET YARP(Yet Another Reverse Proxy)用于代理实现。实施见下一节
- Cookie 或 JWT 可用于对请求进行身份验证。如果将承载令牌传递到请求中,它将用于身份验证。否则,将使用 cookie
Sidecar 身份验证的好处
实现身份验证代理相当复杂,但这种方法的美妙之处在于它只需要处理一次。还有一些其他的好处:
- 开发可以由具有该领域专家的平台团队处理
- 可支持刷新令牌等复杂逻辑并支持多种身份验证方法和身份提供者
- 更容易迁移到新的协议和方法
- 应用程序团队根本不需要身份验证代码。由于默认使用 cookie,它们将自动被我们的网站使用
- 通过标头传递的身份使测试更容易,我们可以在没有代理的情况下运行或创建模拟代理进行测试
转发的声明和标头
选择标头来传递标识信息,因此下游应用程序不需要额外的配置。 JWT 可用于声明,但下游应用程序需要了解颁发机构以及如何验证 JWT。
目前,人们使用这种方法传递身份的方式还有很多。希望随着时间的推移,随着越来越多的人采用这种技术,该行业将与一些推荐的最佳实践保持一致,无论是什么。
这 访问令牌
通过 Authorization 标头传递给下游请求,以便下游应用程序可以使用它为用户发出额外的请求。这 访问令牌
无论是使用 Cookie 还是 JWT 来对用户进行身份验证,都会向下游传递。这是可能的,因为 访问令牌
存储在 cookie 中。
ASP.NET YARP 实现
如果 .NET 不是您选择的武器,您可以跳过本节。无论您使用 .NET 还是其他语言进行身份验证 sidecar,本文的其余部分都适用。
YARP(又一个反向代理)是一个库,可帮助创建高性能、生产就绪和高度可定制的反向代理服务器。 YARP 是使用 ASP.NET 的基础结构在 .NET 上构建的。 YARP 的主要区别在于它的设计目的是通过 .NET 代码轻松定制和调整,以匹配每个部署场景的特定需求。
使用 YARP,我们可以使用普通的 ASP.NET HTTP 请求管道并在请求被 YARP 转发到我们的下游服务之前实现 cookie 和/或 JWT 身份验证。
身份验证代理的完整代码可以在我的 GitHub 上找到 这里 .
大部分配置 YARP 网关的代码可以在 程序.cs
对于网关项目。
让我们分解 程序.cs
看看发生了什么:
验证
默认情况下,用户使用 OpenId Connect 进行质询,并使用 cookie 进行身份验证。 JWT Bearer 身份验证也作为身份验证方案添加。这 CustomAuthenticationSchemeProvider
用于选择适当的身份验证方案。稍后,我们将看到它是如何工作的。
授权码流用作流。每次经过身份验证的请求通过管道时, 访问令牌
检查过期,并使用 a 刷新令牌 刷新令牌
如有必要。
认证方案检测
一个习俗 AuthenticationSchemeProvider
用于检测对用户进行身份验证的方案。如果传递包含承载令牌的授权标头,则将使用 JWT。否则,将使用 cookie。
授权
正常的 ASP.NET 授权管道也可以在反向代理上使用。默认情况下需要经过身份验证的用户,并创建一个额外的管理策略,允许为特定下游端点配置管理员列表。
YARP 配置
YARP 通过标准 .NET 配置添加和配置。这里使用 JSON 文件来配置代理。稍后,我们将看到如何在部署到 Kubernetes 时对其进行自定义。
YARP 可以开箱即用地对转发的请求执行许多不同的转换。一个习俗 ClaimHeaderAppender
添加了转换以提取声明并将它们作为标头转发到下游服务。
如果在原始请求中找到用于转发声明的标头名称,则转换将删除它们以阻止攻击者欺骗用户的身份。
Kubernetes 部署
现在我们有了身份验证代理,我们可以将其部署为 API 网关或 Sidecar 容器。
在这里,我们将其部署为 Kubernetes pod 中的 sidecar 容器,以便对流入 pod 的所有流量进行身份验证。
示例应用程序架构
我的 GitHub 存储库有一个使用身份验证代理作为 sidecar 的示例应用程序。该应用程序包含一个 Blazor WebAssembly 单页应用程序和一个 ASP.NET Core API。
Nginx 入口控制器终止 SSL 并将流量路由到 Web 和 API pod。入口使用基于路径的路由,使用请求路径前缀将流量路由到适当的服务。流量通过 Kubernetes 服务提供给 Pod 端口 80
.
身份验证 sidecar 容器和服务容器使用 端口 8081 和 8080
, 以便可以使用具有受限权限的用户来运行容器 ( 用户 1000
)。
示例应用程序架构
Kubernetes 清单
每个 pod 部署使用两个容器。下图展示了 API 部署:
这 api
容器运行 ASP.NET API 和 网关
容器运行身份验证代理。默认情况下,所有经过身份验证的流量都将由网关转发到 http://localhost:8080
在吊舱上。
API 服务通过网关 sidecar 将流量路由到 pod 端口 8081
.如果不通过网关并经过身份验证,就不可能向 pod 发出请求。
默认情况下,所有流量都必须经过身份验证,但是可以通过使用 ConfigMap 添加配置文件来覆盖 YARP 配置。
这 配置映射
用于 API sidecar 网关执行以下操作:
- 使用匿名策略允许未经身份验证的流量到 API 运行状况端点
- 限制访问
/api/admin/*
仅路由到管理员([[email protected]](/cdn-cgi/l/email-protection)
这里)使用管理策略 - 对需要经过身份验证的用户的所有其他流量使用默认策略
现在 Kubernetes 已经成为大规模部署应用程序的实际方式,很可能会有更多的人开始采用边车模式来解决常见的横切关注点。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明