亚马逊AWS官方博客
当 DR 灾备遇到 KMS
中国区的KMS服务已经发布,为加密的需求提供了便利的解决方案。但是注意到为了满足安全的要求,KMS的CMK是不允许出区域的,在这种情况下,已经加密的资料,如何能够在另外的区域使用?采用了KMS加密的方案,如何实施灾备呢?
一般来说,各种应用场景可以归类为服务器端加密和客户端加密两种实现方式,针对着两种不同的实现方式,本文都提供了相应的解决方案建议。
【应用场景和对应方案】
1. 场景一、服务器端加密的DR方案
服务器端加密主要是指KMS与托管服务集成的应用场景。这样的场景下的DR方案,代码无感,无需研发人员修改代码。
1.1信封加密的基本原理
为了实现对DR的支持,需要借助信封加密的方法。先回顾信封加密的原理。
在信封加密中,首先需要创建在KMS中创建一个CMK(Customer Master Key);其次,在创建数据库或者EBS卷的时候,选择使用刚才创建的CMK加密。实际上,系统服务在后台创建了一个data encryption key(DEK)真正用于加密的数据。这个DEK则需要使用之前指定的CMK进行加密保护。加密后的DEK则会跟相应的业务(RDS/EBS)保存在一起。
信封加密之加密过程
服务器根据客户选择的CMK,生成一个DEK,利用DEK加密数据,然后用CMK加密DEK,将加密的DEK和数据密文放在一个信封里。
信封加密之解密过程
从信封中取出加密的DEK,通过CMK解密后得到明文的DEK,使用DEK对数据密文进行解密,得到明文数据。
信封加密在DR方案中应用示意
而在DR场景中,数据密文和DEK明文在两个不同的区域间是保存不变的,这样就保证了复制到两个区域的数据是被同一个DEK加密的,就能使用同一个DEK进行解密。关键在于在主区域中的DEK,是用主区域的CMK进行加密保护;而在数据跨区域复制过程中,DEK会用主区域的CMK解密后,将明文的DEK使用备份区域的CMK进行加密保护。这样,借助信封加密的方法,避免了对海量的源数据进行解密和重新加密的过程,高效实现加密数据的跨区域备份。
1.2 KMS加密的EBS卷,跨区域复制方法
在数据解密的过程中,以EBS解密为例。当EC2需要读取加密的EBS卷,保存在EBS上的加密的DEK,会通过接口,发送到KMS服务,通过相应的CMK,对DEK进行解密,在这个过程中,传输的是DEK,CMK始终保存在KMS服务中,降低泄漏风险。通过接口返回明文的DEK(当然,传输通道是加密的),EC2就可以使用该明文的DEK,对EBS进行解密,读取相应的数据。该过程对EC2上的应用程序是透明无感的,应用的代码不需要做任何修改。
关于如何将已有的RDS数据库转换为加密的数据库,请参见
那么在DR场景下,如何完成对加密的EBS卷的夸区域复制呢?
在信封加密中,用户数据实际上是被DEK加密的,而加密的DEK会跟EBS卷保存在一起。因此,当我们需要将加密的EBS卷做垮区域的复制,以便支持DR的场景,需要解决的问题就是如何在新的区域能够将DEK解密,得到明文DEK,就可以对数据解密了。
命令行的方式如下
以下代码示例将数据库快照从北京区域复制到宁夏区域并重新加密。在宁夏区域中运行命令。注意kms-key-id这个是目标区域宁夏的
1.3 KMS加密的RDS数据库,创建跨区域只读副本
对于使用了KMS加密的RDS数据库,可以按照以下步骤创建垮区域的只读副本
首先源区域创建使用KMS加密的数据库。
然后在控制台选定该数据库实例,针对该数据库创建只读副本操作;
对于目标区域 Destination region,选择要复制的目的区域,比如ZHY;
切换到目标区域的KMS页面,记录目标区域使用的自建的CMK或者AWS managed keys的ARN
在Encryption 选项下面,篮框部分粘贴目标区域的CMK的ARN
这两个步骤是最关键的,通过这样的方式,创建出来的目标区域的数据库只读副本,对DEK加密的CMK就会被替换为目标区域的CMK。在这个过程中数据库的数据没有收到任何改变,加密的数据不变,使用的DEK也没有发生变化。
2. 场景二、客户端加密:使用KMS的encryption SDK的应用场景,涉及代码修改
有一些场景下,客户需要使用客户端方式对数据进行加密,这样的方式下,如何实现DR方案呢?
在AWS中,提供了ENCRYPTION SDK,可以支持多个CMK,每个Provider对应了一个或多个CMK。如下图所示,假设我们需要在BJS北京区域和ZHY宁夏区域都能够使用同一个DEK对数据加解密。
我们可以通过SDK的 KmsMasterKeyProvider 方法,通过传入的CMK的ARN,可以构造一个 KmsMasterKeyProvider。我们可以分别通过BJS区域的CMK-bjs以及ZHY区域的CMK-zhy各自构造出一个KmsMasterKeyProvider。将这两个KmsMasterKeyProvider作为参数调用MultipleProviderFactory.buildMultiProvider 方法,就可以构建出一个包含多个CMK的Provider。
接下来,我们就可以使用这个Provider对同一个DEK进行加密,就可以得到两个加密的DEK,分别是Encryted Data Keybjs 和 Encrypted Date Keyzhy. 这两个被加密的datakey,在分别使用北京区域和宁夏区域对应的CMK解密之后,得到的明文的datakey是一样的。这就是加密场景在跨区域DR的应用的基础了。在这个过程中,DEK是不可见的,实际上,调用encryptData(provider, plaintext, context),在方法内部会使用DEK对plaintext做加密。
备注:context:所有 AWS KMS 加密操作都接受加密上下文,它是一组包含有关数据的额外上下文信息的 可选键–值对。以加密方式绑定到密文,需要 相同的加密上下文 来解密(或解密和重新加密)数据。
在北京区域解密过程。被解密的数据,通过调用 AwsCrypto().decryptData 的方法,只需要传入provider和密文就可以了。在decyptData方法内部,如下图所示,自动判断应该使用BJS的CMK,对DEK解密后,使用DEK的明文,就可以用于对密文进行解密了。
在宁夏区域解密过程也是类似的。SDK自动判断应该使用ZHY的CMK,对DEK解密后,使用DEK的明文,用于对密文进行解密。
参考代码如下。此外,AWS提供了一个完整的LAB,建议通过这个LAB来熟悉SDK不同的使用场景。
http://busy-engineers-guide.reinvent-workshop.com/index.html
以java为例,需要指定依赖的encryption sdk的版本:
需要构造包含多个CMK的provider,例如
其中的getKeyProvider的方法如下:
执行数据加密的时候,就可以调用这个provider,这个provider会使用之前初始化的多个CMK对数据的DEK进行加密。
执行数据解密的时候,调用这个Provider即可,注:解密的时候,可以用多个CMK,也可以用当前区域的单个CMK初始化Provider。后者代码执行效率更高。
3. 场景三,客户端加密场景扩展,需要固定DEK支持密文对比
某些场景下,加密数据不会解密使用,而是用密文做对比,比如用户的密码,数据库存放的就是密文。用户在客户端输入的密码,在加密之后传输,通过密文与密文的对比来判断密码是否一致。这样的情况下,都不会涉及解密过程,但是要求不管任何时间对同样的明文,加密的密文保持不变。这样就要求DEK必须固定不变。在场景二介绍的Encryption SDK中,为了提高安全等级,DEK是调用的时候临时生成的,每次调用,生成的DEK是不一样的。因此场景二的解决方案不能直接用于场景三。调整如下
为了保证DEK不变,需要将DEK从封装的方法中剥离出来,Client端自己管理DEK。具体如下
DEK的生成和管理
首先,调用Encryption SDK 中的generateDataKey 方法,生成一个DEK
其次,对该DEK进行加密保护,在加密的时候,为了保证该DEK能够在DR场景下使用,也需要使用场景二中介绍的包含多个区域的CMK的Provider,对DEK进行加密保护,这样,我们就可以在不同的区域都可以将加密的DEK进行解密了。
经过加密的DEK,就可以保存在数据库中备用了。当然,还可以放一份在S3上作为冷备保存,借助S3高达11个9的持久性,更为放心。因为DEK已经加密了,所以也不担心安全的风险。
数据加解密环节
从数据库中取出加密的DEK,调用场景二中的解密方法decryptData(),得到明文的DEK,这时候就可以使用该DEK对数据进行加解密了。由于encryption SDK 中包含的方法都有自己的DEK,因此建议使用成熟的库支持AES加密的SDK,对数据做加密和解密。比如java中的Cipher库 javax.crypto.Cipher;
4. 总结
无论是使用客户端加密还是服务器端加密的方式,AWS都提供了对应的DR(多区域)的方案。但是从具体的操作方式来看,服务器端的加密,更加简单方便,无需修改代码;而客户端的方式,是需要在代码层面进行调整的。因此我们建议优先使用服务器端加密的方式,在服务器端加密不能满足的场景下,再考虑客户端加密的方式。