使用Istio和FusionAuth将用户数据库和授权从应用程序中分离出来

2020-11-10 02:53:49

Kubernetes是一个非常强大的集群管理系统。有许多可插拔的技术可供选择,这是你想要的功能,这很棒,因为你有选择-但也有不利的一面,其他人已经做了你想做的事情的可能性很小。最终,随着开发人员聚集在最好的解决方案周围,将会有一些整合,但就目前而言,有很多有趣的项目可供选择(对于某些配置来说,没有太多很好的例子)。今天,我要分享一个略具挑战性的设置,希望它能帮助社区。

我使用Istio作为我的L7入口和路由控制器,它基于特使。它是一个高度可扩展的L7代理,具有出色的性能特性和相对成熟的功能集。到了在项目中实现基本/管理路线的时候,我列出了我想要实现的特性列表。在我想要的配置中:

应用程序不应重新实现基于角色的访问控制(RBAC)安全,因为每个应用程序都需要它。

用户应该能够在不创建另一个用户名/密码的情况下登录以记住,但是如果他们愿意的话,可以支持它。

用户应该能够在不需要支持的情况下自行注册、重置密码,以及管理与其帐户关联的远程身份验证(Google Keyword CIAM)。

应用程序管理员应该能够以显式或按组权限编辑用户的角色,并为非技术人员提供控制访问的可视界面。

K8S Ops应该能够更改RBAC规则保护应用程序的各个路由,而无需重新部署。

最简单的入门方法是遵循Jetstack.io上的出色演练,该演练相当详细地解释了如何使用JWT处理覆盖整个入口。我不会在这里详述所有的细节。相反,我将提供直接部署工作配置所需的确切YAML清单,并显示FusionAuth中有关如何配置应用程序以使其与这些清单正确通信的屏幕截图。

我通常会尝试两到三种替代技术,然后才会选择我喜欢的一种。虽然我从KeyCloak开始,但它感觉有点不完善,在解释如何在术语不熟悉的情况下配置它时,还有很多需要改进的地方(例如。不是安全专业人员的人)。我研究了其他几种选择,最后归结为Gluu或FusionAuth。对我来说,支持FusionAuth的主要决定因素是大量的文档和教程(带有很好的幽默意味)。开发商也做出了明显的努力,提供了官方的码头图片和Kubernetes的例子,展示了现实世界的使用情况。我对这一决定非常满意。

好的,那么让我们来谈谈这两者如何协同工作的架构。与使用Istio的任何其他流量一样,请求将按照VirtualService到服务的路由规则进入应用程序,然后到达部署的Pod。要使用Istio安全功能,此Pod需要运行Sidecar代理,否则规则不会执行任何操作。(这是不幸的,因为根据我的经验,Sidecar可能会导致某些工作负载的连接问题,所以请注意它可能会造成副作用,您可能需要为此命名空间显式创建和配置Sidecar)。要实现这一点,最简单的方法是在新的命名空间上启用自动SideCar代理注入,并在那里部署应用程序。通过声明RequestAuthentication规则,我们将Istio配置为拒绝任何没有有效签名的Json Web令牌(JWT)的流量。通过声明AuthorizationPolicy规则,我们将Istio配置为通过匹配特定的HTTP路径或用户角色等来接受或拒绝流量。这很棒,对吧?

嗯,Istio还不够成熟,不能说Open ID Connect。但它只有足够聪明,才能期待一个经过有效解码的JWT,并根据其内容进行一些简单的模式匹配。当这些规则失败时,你只会得到RBAC:作为对你请求的回应,访问被拒绝。没有重定向逻辑将浏览器发送到身份验证服务器登录页面。因此,让我们通过在Sidecar_Inbound上注入一个简单的EnvoyFilter规则来教它如何做到这一点。这使我们能够针对特定的应用程序,仅保护我们关心的路由,而不会影响其他任何内容。

几个关键细节:RequestAuthentication只接受使用RSA密钥签名的JWT,因为HMAC是对称密钥,任何能够解码它的人也可以签名。这意味着它需要知道从哪里获得公共RSA密钥,该密钥在颁发者字段中提供。假设此情况属实,Istio随后会查看任何AuthorizationPolicy规则,并根据匹配或不匹配的详细信息允许或拒绝流量。*在这种情况下,我提供了一个基本规则,允许任何经过验证的人拥有此应用程序的帐户,并进一步将/admin/路径限制为具有admin角色的帐户。如果出现任何问题,Istio只会说RBAC:访问被拒绝。要进行诊断,只需删除这些规则并尝试点击终结点,看看会弹出什么错误。如果这些规则被删除,而你仍然收到未经授权的消息,它的OAuth2-Proxy拒绝用户--检查配置和记录以了解原因。

这就是我们期盼已久的YAML。这完全描述了一种工作配置,其中VirtualService位于默认命名空间中,但其他所有内容都在身份验证中,这只是为了让它远离其他所有内容。*应用程序托管在https://auth-example.reachablegames.com.上。下面评论了如果配置不正确会导致问题的某些困难和未记录的细节--请在更改或简化之前注意。

#创建应用程序可以具有SideCar注入的命名空间apiVersion:v1Kind:Namespacemetadata:Labels:app:Auth istio-Injection:Enable Name:Auth-#此规则确保JWT被解码,并作为HTTP_payload Base64编码传递到Web服务器。apiVersion:security.istio.io/v1beta1ind:RequestAuthenticationMetadata:Name:Auth-Example Nample Namespace:Auth.apiVersion:security.istio.io/v1beta1ind:RequestAuthenticationMetadata:Name:Auth-Example Namespace:Auth.。Header ForwardOriginalToken:true#这只会将解码后的JWT作为";payload";Header outputPayloadToHeader:";payload";-#此规则验证用户是经过身份验证的用户(请求主体)和授权用户(request.auth.Claims)apiVersion:security.istio.io/v1beta1Kind:AuthorizationPolicyMetadata:Name:Auth-Example。]至:-operation:路径:[";/admin/*";]时间:-key:request.auth.Claims[r

ApiVersion:networking.istio.io/v1alpha3ind:VirtualServicemetadata:name:fusionauth labels:app:fusionauthspec:hosts:-";fusionauth.reachablegames.com";网关:-istio-gw http:-Match:-uri:Prefix:/Route:-Destination:host:Fusionauth port:Number:80-apiVersion:v1Kind:Servicemetadata:Name:Fusionauth Labels:app:FusionAuthSpec:ports:-port:80 name:http-web protocol:TCP targetPort:http-web选择器:app:fusionauth会话亲和性:无类型:ClusterIP-apiapi.。Fusionauth-db群集IP:None-#FusionauthapiVersion:app/v1ind:StatefulSetMetadata:名称:Fusionauth-db标签:app:fusionauth-db标签:serviceName:fusionauth-db副本:1选择器:matchLabels:app:fusionauth-db updateStrategy:type:RollingUpdate Template:Metadata:Annotation:sidecar.istio.io/indateStrategy:type:RollingUpdate Template:Metadata:Annotation:sidecar.istio.io/indateStrategy:RollingUpdate Template:Metadata:Annotation:sidecar.istio.io/indateStrategy。FALSE";标签:app:fusionauth-db Version:1.0.0规范:Containers:-Image:Postgres:11.9-阿尔卑斯山名称:Postgres env:-name:PGDATA值:/var/lib/PostgreSQL/data/pgdata-name:postgres_user值:pguser-name:postgres_password值:pgpass-name:postgres_DB value:Fusionauth ports:-tainerPort:5432 name。请求:CPU:";0.25";内存:";250Mi";卷装载:-名称:Fusionauth-storage装载路径:/var/lib/postgreSQL/Data Voluments:-name:Fusionauth-storage PersistentVolumeClaim:Claim Name:Fusionauth-storage VolumeClaimTemplates:-Metadata:Name:Fusionauth-storage Spec:access Modes:[";ReadWriteSpec:Access Modes:[";ReadWrite34;#更改以匹配您的存储系统资源:请求:存储:10Gi-apiVersion:app/v1ind:DeploymentMetadata:Name:Fusionauth Labels:app:FusionAuthSpec:Replicas:1 Strategy:type:rereate selector:matchLabels:app:Fusionauth Template:Metadata:Annotation:sidecar.istio.io/Inject:";False";Labels:app:Fusionauth Version:1.0.0规范。容器:-Name:Fusionauth图像:Fusionauth/Fusionauth-app:最新图像PullPolicy:Always env:-Name:Database_URL值:jdbc:postgresql://fusionauth-db:5432/fusionauth-Name:Database_Root_Username值:PG用户名:Database_Root_Password值:PG Pass-Name:Database_Username值:PG用户名:Database_Password值:PG Pass-Name:FUSIONAUTH_APP_MEMORY值:512M-Name:FUSIO。/fusionauth.reachablegames.com/-名称:搜索类型值:数据库名称:ES_JAVA_OPTS值:";-Xms256M-Xmx512M";端口:-tainerPort:9011名称:http-web livenessProbe:InitialDelaySecond:10超时秒:10周期秒:30故障阈值:5 httpGet:path:/port:http-web readinessProbe:InitialDelaySecond:10超时秒:10周期秒:30故障阈值:5 httpGet:path:/port:http-web readinessProbe:InitialDelaySecond:10 Period Second:30 ailureThreshold:5 httpGet:path:/port:http-web readinessProbe:InitialDelaySecond:10 timeureThreshold:5 httpGet:path:/port:http。卷装载:-name:fusionauth-pvc装载路径:/usr/local/fusionauth/config subPath:配置卷:-name:fusionauth-pvc sistentVolumeClaim:Claim Name:fusionauth-pvc#将其更改为与您环境中的PVC匹配。

上面的YAML部署了Postgres DB和FusionAuth部署,它们可以独立扩展。很明显,我的存储系统将与您的存储系统不同,因此请更改PersistentVolumeClaim和storageClassName与您的存储环境匹配的两个位置。*启动后,请转到托管演练以配置FusionAuth。它不会花很长时间,因此会创建你的第一个超级管理员用户。本文的其余部分是如何正确配置FusionAuth以实现以下目标的可视化演练:

此处未显示的步骤包括:创建子域、配置入口网关以使用HTTPS证书等。如果确定,请立即部署FUSIONAUTH。*kubectl Apply-f fusionauth.yaml。

FusionAuth是一个多租户系统,其中一个租户可能有多个应用程序。*FusionAuth将自身视为应用程序,并使用与管理外部应用程序相同的身份验证和授权系统来管理自身。所以不要删除你的权限,否则你会被锁在门外!

我们要做的第一件事是创建两个RSA密钥,这两个密钥将用于对JWT进行非对称签名,因此Istio将接受它们。默认的是HMAC,所以让我们来改变这一点。

接下来,让我们配置租户使用这些密钥。这使得所有应用程序都默认使用它们,这样以后添加新应用程序时需要记住的步骤就少了一步。(可以,您可以对许多不同的域、应用程序、路线等使用FusionAuth,如果您愿意,还可以在用户数据库中将它们在逻辑上分开。不要尝试

应用程序的名称纯粹是为了显示目的。在这里添加两个角色,仔细命名为user和admin。确保复选框如图所示进行配置,以便每个人在注册(首次登录)时都获得用户角色,并且管理员拥有完全权限。

在OAuth选项卡上,ClientID将为空,直到您点击保存,因此我们将返回并立即获取它。请确保您已配置指向您的应用程序的域...。我不知道您可能还需要在哪些地方配置不同的URL(如果您需要管理,请给我发个便条。

.