3.4 保护敏感的配置信息

 在默认情况下,Spring Cloud配置服务器在应用程序配置文件中以纯文本格式存储所有属性,包括像数据库凭据这样的敏感信息。
    将敏感凭据作为纯文本保存在源代码存储库中是一种非常糟糕的做法。遗憾的是,它发生的频率比我们想象的要高得多。Spring Cloud Config可以让我们轻松加密敏感属性。Spring Cloud Config支持使用对称加密(共享密钥)和非对称加密(公钥/私钥)。
    我们将看看如何搭建Spring Cloud配置服务器以使用对称密钥的加密。要做到这一点,需要:
    (1)下载并安装加密所需的Oracle JCE jar;
    (2)创建加密密钥;
    (3)加密和解密属性;
    (4)配置微服务以在客户端使用加密。
    3.4.1 下载并安装加密所需的Oracle JCE jar
    首先,需要下载并安装Oracle的不限长度的Java加密扩展(Unlimited Strength Java Cryptography Extension,JCE)。它无法通过Maven下载,必须从Oracle公司下载 。下载包含JCE jar的zip文件后,必须执行以下操作。
    (1)切换到$JAVA_HOME/jre/lib/security文件夹。
    (2)将$JAVA_HOME/jre/lib/security目录中的local_policy.jar和US_export_policy.jar文件备份到其他位置。
    (3)解压从Oracle下载的JCE zip文件。
    (4)将local_policy.jar和US_export_policy.jar复制到$JAVA_HOME/jre/lib/security目录中。
 
(5)配置Spring Cloud Config以使用加密。
    
自动化安装Oracle JCE文件的过程
我已经完成了在笔记本电脑上安装JCE所需的手动步骤。因为我们使用Docker将所有的服务构建为Docker容器,
所以我已经在Spring Cloud Config Docker容器中编写了这些JAR文件的下载和安装的脚本。
下面的OS X shell脚本代码段展示了如何使用curl命令行工具进行自动化操作:
cd /tmp/
-H 'Cookie: oraclelicense=accept-securebackup-cookie' && unzip  jce_policy-8.zip 
rm jce_policy-8.zip 
yes |cp -v /tmp/UnlimitedJCEPolicyJDK8/­*.jar /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
我不会去讲所有的细节,但基本上我使用CURL下载了JCE zip文件(注意通过curl命令中的-H属性传递的Cookie头参数),
然后解压文件并将其复制到Docker容器中的/usr/lib/jvm/java-1.8-openjdk/jre/lib/security目录。
如果读者查看本章源代码中的src/main/docker/Dockerfile文件,就可以看到该脚本的示例。
    
3.4.2 创建加密密钥
一旦JAR文件就位,就需要设置一个对称加密密钥。对称加密密钥只不过是加密器用来加密值和解密器用来解密值的共享密钥。
使用Spring Cloud配置服务器,对称加密密钥是通过操作系统环境变量ENCRYPT_KEY传递给服务的字符串。
在本书中,需要始终将ENCRYPT_KEY环境变量设置为:
export ENCRYPT_KEY=IMSYMMETRIC
关于对称密钥,要注意以下两点。
    (1)对称密钥的长度应该是12个或更多个字符,最好是一个随机的字符集。
    (2)不要丢失对称密钥。一旦使用加密密钥加密某些东西,如果没有对称密钥就无法解密。
    
管理加密密钥
    为了撰写本书,我做了两件在生产部署中通常不会推荐的事情。
    我将加密密钥设置为一句话。因为我想保持密钥简单,以便我能记住它,并且它能很好地进行阅读。在真实的部署中,我会为部署的每个环境使用单独的加密密钥,并使用随机字符作为我的密钥。
    我直接在本书中使用的Docker文件中硬编码了ENCRYPT_KEY环境变量。我这样做是为了让读者可以下载文件并启动它们而无需设置环境变量。在真实的运行时环境中,我将引用ENCRYPT_KEY作为Docker文件中的一个操作系统环境变量。注意这一点,并且不要在Dockerfile内硬编码加密密钥。记住,Dockerfile应该处于源代码管理下。
 
3.4.3 加密和解密属性
    现在,可以开始加密在Spring Cloud Config中使用的属性了。我们将加密用于访问EagleEye数据的许可证服务Postgres数据库密码。要加密的属性spring.datasource.password当前设置的纯文本值为p0stgr@s。
    在启动Spring Cloud Config实例时,Spring Cloud Config将检测到环境变量ENCRYPT_KEY已设置,并自动将两个新端点(/encrypt和/decrypt)添加到Spring Cloud Config服务。我们将使用/encrypt端点加密p0stgr@s值。
    图3-8展示了如何使用/encrypt端点和POSTMAN加密p0stgr@s的值。请注意,无论何时调用/encrypt或/decrypt端点,都需要确保对这些端点进行POST请求。
图3-8 使用/encrypt端点可以加密值
    如果要解密这个值,可以使用/decrypt端点,在调用中传递已加密的字符串。
    现在可以使用以下语法将已加密的属性添加到GitHub或基于文件系统的许可证服务的配置文件中:
    spring.datasource.password:"{cipher}858201e10fe3c9513e1d28b33ff417a66e8c8411dcff3077c53cf53d8a1be360"
    Spring Cloud配置服务器要求所有已加密的属性前面加上{cipher}。{cipher}告诉Spring Cloud配置服务器它正在处理已加密的值。启动Spring Cloud配置服务器,并使用GET方法访问http://localhost:8888/licensingservice/default端点。
    图3-9展示了这次调用的结果。
图3-9 虽然在属性文件中,spring.datasource.password已经被加密,然而当许可证服务的配置被检索时,它将被解密。这仍然是有问题的
    我们通过对属性进行加密来让spring.datasource.password变得更安全,但仍然存在一个问题。在访问http://localhost:8888/licensingservice/default端点时,数据库密码被以纯文本形式公开了。
    在默认情况下,Spring Cloud Config将在服务器上解密所有属性,并将未加密的纯文本作为结果传回给请求属性的应用程序。但是,开发人员可以告诉Spring Cloud Config不要在服务器上进行解密,并让应用程序负责检索配置数据以解密已加密的属性。
    3.4.4 配置微服务以在客户端使用加密
    要让客户端对属性进行解密,需要做以下3件事情。
    (1)配置Spring Cloud Config不要在服务器端解密属性。
(2)在许可证服务器上设置对称密钥。
    (3)将spring-security-rsa JAR添加到许可证服务的pom.xml文件中。
    首先需要做的是在Spring Cloud Config中禁用服务器端的属性解密。这可以通过设置Spring Cloud Config的src/main/resources/application.yml文件中的spring.cloud.config.server.encrypt.enabled属性为false来完成。这就是在Spring Cloud Config服务器上需要做的所有工作。
    因为许可证服务现在负责解密已加密的属性,所以需要先在许可证服务上设置对称密钥,方法是确保ENCRYPT_KEY环境变量与Spring Cloud Config服务器使用的对称密钥相同(如IMSYMMETRIC)
    接下来,需要在许可证服务中包含spring-security-rsa JAR依赖项:
    <dependency>   
<groupId>org.springframework.security</groupId>   
<artifactId>spring-security-rsa</artifactId> 
</dependency>
    这些JAR文件包含解密从Spring Cloud Config检索的已加密的属性所需的Spring代码。有了这些更改,就可以启动Spring Cloud Config和许可证服务了。如果读者访问http://localhost:8888/licensingservice/default端点,就会发现spring.datasource.password是以加密形式返回的。图3-10展示了这一调用的输出结果。
图3-10 启用客户端解密后,敏感属性不再以未加密文本的形式从Spring Cloud Config REST调用中返回。相反,在从Spring Cloud Config加载属性时,该属性将由调用服务解密。
 
OK
 
 
 
posted @ 2019-12-02 20:50  mongotea  阅读(270)  评论(0编辑  收藏  举报