我们需要无密码访问数据库! 在企业级应用中我们可以看到众多身份管理体系, AWS 身份授权管理(IAM)、企业身份管理、应用身份管理体系等等。每个企业都试图去创建一个统一的身份认证平台,希望借此能够解决企业内的身份认证问题难题。
然而如此众多的身份认证体系中,居然没有一个很优雅的办法解决应用在连接数据库过程中的密码管理问题! 这个问题在微服务的场景下会凸显出来,想想海量服务对应海量持久化方案吧。本着 Cloud Native 服务要无状态的原则,我们这次就来设计一个“安全信息管理 as a services ”。通过这个服务,应用在不知晓数据库的用户名、密码甚至数据库地址的前提下,完成对数据库服务的发现,并授权连接。 同样的架构除了用来进行数据库密码的管理外,也有很多与密码管理相关的场景,比如用来保存密钥等关键认证信息。
安全高效密码管理服务 我们先来回顾一下传统架构中大家是如何来做身份认证的:
· 我们会将身份认证分为基础设施类的认证与应用程序类的认证两种主要形式,AD/LDAP 多被用在基础设施类身份认证上。 · AWS 平台上提供 IAM 服务,实现基础设施类的认证。值得一提的是,如果大家用 RDS Mysql/Aurora Mysql 数据库,IAM 已经提供了对数据库连接的授权管理。具体可以参照:https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html · 在应用类的认证中,有很多单点登录的方案,也可以与 AD 集成,或者通过 oauth 等其他方式与第三方认证服务集成。 然而,还有一些服务会采用提供用户名、密码访问的方式,并没有与企业的统一身份认证进行集成 。 为何在这个领域 已有的技术手段为何并没有被广泛采用? · 首先集成成本高,企业内部数据库系统可能有成百上千套,每套系统需单独与 AD 集成。 · 即便做了集成管理,在授权时仍然要采用用户名密码或密钥的方式,使用过程依然不安全。 · 因此目前主流方式是通过配置文件在本地加密保存,再在 Runtime 中由程序解密,过程非常复杂。 存在即合理,企业采用上述方式完成安全信息的保存成为了一种最佳实践。
那么,在 AWS 上 如何解决和满足这部分需求呢?
如果可以实现一套安全信息管理服务,无论哪一层的开发者都无需再保存密码;同时这些访问请求仍然通过合理的授权与认证,并提供审计日志;抽象的服务本身使得定期更换数据库密码这样的安全策略得以执行。这样,就可以用很小的成本解决企业中大量存在的安全隐患。 在此插播一个演示 我们数据库创建程序片段如下: #!/usr/bin/python import mysql.connector from mysql.connector import errorcode from secureDB import secureconnection DB_NAME = ‘mydbtest’ cnx = secureconnection() cursor = cnx.cursor() def create_database(cursor): try: cursor.execute( 'CREATE DATABASE {} DEFAULT CHARACTER SET 'utf8''.format(DB_NAME)) except mysql.connector.Error as err: print('Failed creating database: {}'.format(err)) exit(1)
try: cnx.database = DB_NAME except mysql.connector.Error as err: if err.errno == errorcode.ER_BAD_DB_ERROR: create_database(cursor) cnx.database = DB_NAME else: print(err) exit(1)
for name, ddl in TABLES.items(): try: print('Creating table {}: '.format(name), end='') cursor.execute(ddl) except mysql.connector.Error as err: if err.errno == errorcode.ER_TABLE_EXISTS_ERROR: print('already exists.') else: print(err.msg) else: print('OK') cursor.close() cnx.close() 我们提供的 sdk(secureDB.py)如下: #!/usr/bin/python import … from aws_requests_auth.aws_auth import AWSRequestsAuth
def secureconnection(): client = boto3.client('sts')
response = client.assume_role( RoleArn='arn:aws:iam::277052429340:role/sts_616532859444', RoleSessionName='test', DurationSeconds=1000 ) auth = AWSRequestsAuth(aws_access_key = response['Credentials']['AccessKeyId'], aws_secret_access_key = response['Credentials']['SecretAccessKey'], aws_token = response['Credentials']['SessionToken'], aws_host = 'j0kym28ch1.execute-api.ap-northeast-1.', aws_region = 'ap-northeast-1', aws_service = 'execute-api') response = requests.get('https://j0kym28ch1.execute-api.ap-northeast-1./Prod/secret/, auth=auth) username = response.json()['Item']['username'] dbname = response.json()['Item']['dbname'] password = response.json()['Item']['secret'] return mysql.connector.connect(user=username, password=password, host=dbname) 当然我们这里必须要做一些授权工作:需要给执行这段程序的 Amazon EC2 指定一个 Role,简单来讲,这个 Role 将授权 SDK 获取数据库用户名密码。 我们可以看到在客户端或者 sdk 都没有记录用户名、密码、数据库地址的情况下,客户端程序仍然可以获得数据库连接,成功创建表结构。 如果我们取消 Role,客户端程序则无法执行成功。 熟悉 AWS 的同学就知道,IAM 确实可以实现无密码的授权,但是 IAM 并不能获取服务内部的权限,例如这里的数据库内部的用户名、密码、数据库地址。那我们如何做到将服务内部的权限与 IAM 权限体系进行整合呢? 参考架构设计蓝图 理论上安全服务的后台架构很少讨论,因为里面会透露很多部署与编码的方式,有可能会暴露安全隐患;但我们这个服务采用了无服务器架构设计,这个设计本身暴露在外的都是 AWS 提供的托管服务,这些服务的安全性 AWS 会提供保障;而我们这里不会讨论后端代码。 我们前面演示的后台服务完全采用了无服务器的方式: Amazon API Gateway 进行客户接入与授权 AWS Lambda 调度运行环境 Amazon DynamoDB 提供加密存储 Amazon CloudWatch 提供 Metric 和日志收集 托管的 Amazon ES 服务提供日志分析与展现 Amazon IAM 模块提供用户认证与授权 服务本身的设计也已经考虑了多租户、多服务、多用户等授权场景。 篇幅所限,我们仅描述一下服务里涉及到的一个流程。这个流程中会涉及到客户的 AWS 账户(A)与安全服务的 AWS 账户(B),通过这个流程,客户应用将完成授权到链接的过程。 在客户账户 A 中 1 需要访问数据库的软件 APP,通过 SDK 发起数据库连接 2 SDK 通过 IAM STS 服务从安全服务账户 B 中获取 User Role 对应的 token 3 SDK 将 Token 与查询信息组合后,对 API Gateway 进行加密访问 安全服务账户 B 中 4 收到 SDK 提交的查询请求,Amazon API Gateway 首先验证 Token 所对应的 User Role 是否有相关权限 5 Amazon API Gateway 检查无误后,会调用 Lambda 请求;AWS Lamdba 会从 Amazon API Gateway 获取访问的 User Role ,然后在 Amazon DynamoDB 表中找到 User Role 对应的用户名、密码、服务等信息,通过 Amazon API Gateway 并返回给 SDK 。 在客户账户 A 中 6 SDK 拿到所需信息,与数据库服务创建连接,并返回给用户代码 APP 客户需要进行合理的授权行为,即通过 Role 的方式对 SDK 进行授权。同时授权或非法访问日志均会被 Amazon IAM 与 Amazon API Gateway 记录并汇总到 Amazon CloudWatch 与 Amazon ES 中,除了审计外,还可以定义事件流,侦测非法访问的地址并进行屏蔽。 作为安全方案,无服务器架构有几个突出的安全相关的优势: · 对外只暴露受控的 API。 · 运行环境是 Session 独占且是及时销毁。 · 在持久层 Amazon DynamoDB 也属于无服务器架构;从存储数据本身的安全性,到服务的访问控制,再到服务本身的设计,Amazon DynamoDB 都采取了大量的安全机制。 · 无服务器架构设计里面会使用很多 AWS 提供的托管服务,上面已经介绍过 AWS 会对这些服务本身的安全性和可用性提供保障。
除了这些明显的优势外,我们在这里采用 SaaS 服务的模式。把安全服务放在一个单独 AWS 账户中,通过对这个账户采用最严格的审计和控制来提高服务的安全性。
无服务器的架构同时还可以提供良好线性的扩展能力,无论小型企业还是大型企业,甚至可以用来提供安全类的 SaaS 服务。 为了验证我们这个方案的可扩展性,这里进行了一个简单的压力测试。测试持续了 15 分钟,压力保持在 800TPS。这个过程中 0 异常,并且 99% 的端到端相应时间均小于 1 秒,服务内部的延迟在几十毫秒。无服务器架构的服务扩展性非常出色。 任何一个 SaaS 服务都不能脱离成本考量,安全密码服务的使用性质决定了服务很有可能会长时间保持静默,而在维护窗口被集中调用。采用无服务器架构可以消灭 Idle 的成本,也可以消灭扩展的等待窗口。无论存储和计算都是按访问量计费,如果未来考虑做成 SaaS 服务,这样的特性也非常利于多租户账单的生成。
另外容易被忽视的成本来自研发投资。大量服务的采用,我们只需要对服务进行简单的配置;AWS 还提供了 Serverless Application Repository,可以在里面找到很多编程范式。剩下只需关注于业务逻辑相关的代码,AWS Lambda 保证了我们可以选择自己擅长的编程语言。上面的这个演示仅用了几个小时时间采用 Node.js 与 Python 实现;而且从 protyping 到 production 我们只需要细致打磨这个概念原型,不需要进行复杂的扩展性、可靠性、安全性方面的代码重构与优化,这些都可以交给无服务器架构来解决。 合作伙伴产品推荐 一般文章讲到最后,总是要安利一款产品,然而我们这次要安利不止一款产品。
在 AWS 这个丰富的技术生态下,几乎所有需求都会有小伙伴提供相关服务,我们看到的这个需求当然也不例外。
· AWS Secrets Manager,这是 AWS 的新服务。可帮助您保护访问您的应用程序、服务和 IT 资源所需的私密信息。该服务使您能够轻松地跨整个生命周期轮换、管理和检索数据库凭证、API 密钥和其他密钥。用户和应用程序通过调用 Secrets Manager API 来检索密钥,无需对纯文本的敏感信息进行硬编码。AWS Secrets Manager 通过适用于 Amazon RDS for MySQL、PostgreSQL 和 Amazon Aurora 的内置集成实现密钥轮换。此外,该服务还可以扩展到其他类型的密钥,包括 API 密钥和 OAuth 令牌。此外,AWS Secrets Manager 使您可以利用细粒度的权限控制对私密信息的访问,并集中审计 AWS Cloud、第三方服务和本地资源的私密信息轮换。如果您使用的区域已经有 AWS Secret Manager 服务,那么我们强烈建议您尝试一下这个由 AWS 提供安全保障的安全服务。 · AWS 高级技术合作伙伴 Hashicorp 也推出了一款产品 Vault Enterprise,不但可以解决安全信息管理的问题,同时还提供了非常多的高级功能,包括 Encryption as services、HSM 集成、KMS 集成、MFA、服务容灾等等。 本文中的演示将被贡献给 AWS 创新中心。 AWS 创新中心旨在通过科技创新的演示,向客户集中展示 AWS 丰富的工具、服务和解决方案资源。借助多媒体、高科技的手段模拟现实环境,为客户带来全新的 AWS 云计算体验,帮助客户深入了解如何实现IT转型及业务模式的创新,并取得成功。 目前 AWS 创新中心北京/上海/成都分中心均已开放。很多有创意的演示,例如:面部识别、合理规划配置云实例、数据湖、数据库迁移工具等。您可以联系与您对接的 AWS 业务代表来参观创新中心,期待您的光临。 |
|