2020 年美国大选技术平台架构( 四 )


因此 , 我们创建了Conductor(因为拜登喜欢火车 , 就用售票员来命名)、我们的内部工具UI , 以及Turbotots(我们根据土豆来命名的众多工具之一) , 也就是我们的平台API 。
图4:Conductor和Turbotots
图4实际上是对一个复杂架构的简化图 , 但这些概略的描述足以让你了解Conductor和Turbotots做了哪些事情 。
Conductor成为我们为竞选工作人员开发的所有内部工具的统一入口 。 换句话说 , 这是所有参与竞选活动的人想要访问我们提供的服务都必须经过的地方 。 Conductor是一个ReactWeb应用 , 通过S3来部署 , 并通过CloudFront来分发 。
Turbotots是一个统一的API , 它为我们所做的一切提供了通用的身份认证和授权模型 , 与Conductor通信也是通过它 。 我们在AWSCognito上构建了Turbotots的AuthN和AuthZ部分 , 这节省了大量工作 , 并通过GSuite/GoogleWorkspace提供了简单的单点登录(SSO)功能 。 身份验证是通过解析JWT令牌来实现的 。 为了在前端管理好它们 , 我们使用了AWSAmplify的React绑定 , 它被无缝地集成到应用程序中 。
图4右侧的内容有点难以理解 , 我会尽量简化 。 正向API是一种API网关 , 包含了完整的代理资源 。 API网关可以很容易与Cognito集成 , 这帮助我们实现了API请求的安全性 。 与API网关集成的Cognito授权器也会在请求通过代理之前执行JWT验证 。 我们可以通过它清楚地知道请求在发送到后端之前已经过完整的验证了 。
在开发API网关代理资源时 , 你可以通过VPC网络负载均衡器让运行在VPC中的代码连通起来 。 这很复杂 , 但据我所知 , 它有效地在AWS内部的API网关和你的私有VPC之间创建了一个弹性网络接口 。 反过来 , NLB被附加到一个包含一组NGINX实例的自动伸缩组中 , 作为我们的统一API 。 这就是Turbotots的主要部分 , 本质上就是在VPC中运行的所有内部服务的反向代理 。 在这种模式下 , 我们不需要向公网公开任何VPC资源 。 我们可以依赖AWS内置的安全装置 , 这让我们大家都轻松多了 。
当请求到达Turbotots时,Turbotots中的轻量级Lua脚本就会提取JWT令牌的用户信息部分 , 并将该数据作为新的请求负载的一部分传递给下游服务 。 当请求到达目标服务时 , 它就可以检查用户信息 , 看看是否对该用户的请求做了验证 。
用户可以被添加到Cognito的授权组中 , 这样他们就可以在下游服务中获得不同级别的访问权限 。 最小权限原则在这里仍然适用 , 并且没有默认权限 。
Conductor和Turbotots作为一个统一的用户界面 , 为内部工具提供了与GSuite帐户的无缝SSO集成 。 在下一节 , 我们将介绍如何使用相同的架构向非内部用户公开部分API 。
Pencil和Turbotots
Pencil是一个点对点短信平台 , 从一系列简单的早期需求开始 , 发展成为一个我们为之投入了大量时间的庞大架构 。
自己构建P2P短信平台的初衷是为了节省成本 。 我知道 , 我们可以通过Twilio发送短信 , 这比任其他何一个供应商的收费都要低 。 但是 , 在一开始 , 我们并不需要供应商提供的大量功能 , 我们很容易就能构建一个简单的短信系统来满足当时的需求 。
随着项目越来越流行 , 它的规模在急剧扩张 。 Pencil被成千上万的志愿者用来接触数以百万计的选民 , 并成为我们选民外联工作流程中的一个重要组成部分 。 你收到的来自竞选志愿者的短信很可能是通过Pencil发送的 。
Pencil的外部架构看起来有点眼熟 , 我们重用了Conductor架构 , 只做了一些配置修改 , 不需要修改代码 。
图5:Pencil的架构看起来很像Conductor
Pencil的用户组件是一个通过S3部署并通过CloudFront分发的ReactWeb应用程序 。 React应用程序反过来与连接到Cognito授权器的API网关资源对话 。