加密与解密
要使用加密和解密功能,您需要在 JVM 中安装全强度的 JCE(默认情况下不包含)。您可以从 Oracle 下载“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files”,并按照安装说明进行操作(基本上,您需要将 JRE lib/security 目录中的两个策略文件替换为您下载的文件)。
如果远程属性源包含加密内容(以 {cipher}
开头的值),它们会在通过 HTTP 发送到客户端之前被解密。这种设置的主要优势在于,属性值在“静态”时(例如,在 git 仓库中)不需要以明文形式存在。如果某个值无法解密,它将被从属性源中移除,并添加一个额外的属性,该属性具有相同的键,但前缀为 invalid
,值为“不适用”(通常为 <n/a>
)。这主要是为了防止将密文用作密码并意外泄露。
如果你为配置客户端应用程序设置了远程配置仓库,它可能会包含一个类似于以下的 application.yml
文件:
spring:
datasource:
username: dbuser
password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'
application.properties
文件中的加密值不能使用引号包裹。否则,该值将无法解密。以下示例展示了有效的值:
spring.datasource.username: dbuser
spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ
你可以安全地将这个纯文本推送到共享的 git 仓库,而秘密密码仍然受到保护。
服务器还暴露了 /encrypt
和 /decrypt
端点(假设这些端点是安全的,并且只有经过授权的代理才能访问)。如果你编辑一个远程配置文件,你可以通过向 /encrypt
端点发送 POST 请求来使用配置服务器加密值,如下例所示:
$ curl localhost:8888/encrypt -s -d mysecret
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
如果你使用 curl 进行测试,请使用 --data-urlencode
(而不是 -d
),并在要加密的值前加上 =
(curl 要求这样做),或者显式设置 Content-Type: text/plain
,以确保 curl 在存在特殊字符(特别是 '+')时正确编码数据。
确保不要在加密值中包含任何 curl 命令的统计信息,这就是为什么示例中使用 -s
选项来静默它们的原因。将值输出到文件可以帮助避免这个问题。
逆操作也可以通过 /decrypt
实现(前提是服务器配置了对称密钥或完整的密钥对),如下例所示:
$ curl localhost:8888/decrypt -s -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
将加密值添加 {cipher}
前缀后,再放入 YAML 或 properties 文件中,并在提交并推送到远程(可能不安全的)存储之前。
/encrypt
和 /decrypt
端点也都接受形式为 /*/{application}/{profiles}
的路径,当客户端调用主环境资源时,这些路径可用于按应用程序(名称)和按配置文件控制加密。
要以这种细粒度的方式控制加密,您还必须提供一个 @Bean
类型的 TextEncryptorLocator
,该 TextEncryptorLocator
会根据名称和配置文件创建不同的加密器。默认提供的加密器不会这样做(所有加密使用相同的密钥)。
安装了 Spring Cloud CLI 扩展的 spring
命令行客户端也可以用于加密和解密,如下例所示:
$ spring encrypt mysecret --key foo
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret
要在文件中使用密钥(例如用于加密的 RSA 公钥),请在密钥值前加上 @
并提供文件路径,如下例所示:
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
--key
参数是必需的(尽管它带有 --
前缀)。