在OpenShift环境中部署Java密钥库的好方法是什么?

24
我们有一个Java Web应用程序,它原本是部署在常规服务器上的,现在需要迁移到OpenShift环境中(以Docker容器形式部署)。目前,该应用程序消耗一组Java密钥库(.jks文件)以获取与第三方Web接口通信所需的客户端证书。每个接口都有一个密钥库。
这些jks文件手动部署在生产机器上,并在第三方证书需要更新时偶尔进行更新。我们的应用程序具有指向密钥库文件路径的设置,启动时会从中读取证书,然后使用它们与第三方系统通信。
现在当我们迁移到OpenShift环境时,我们有一个Docker镜像用于所有环境(开发,测试和生产),并且所有配置都作为环境变量提供。但是我们无法将jks文件作为环境变量提供,它们需要挂载到Docker容器的文件系统中。
由于这些证书是机密的,我们不想将其嵌入到镜像中。我扫描了OpenShift文档以寻找解决方法,基本上找到了两个选项:使用Secrets或安装持久卷索赔(PVC)。
对我们来说,Secrets似乎行不通,因为它们基本上只是可挂载为文件或作为环境变量传递的键值对。它们还有大小限制。使用PVC在理论上是可行的,但我们需要一些方法将JKS文件放入该卷中。一个简单的方法是只需启动一个Shell容器,挂载PVC并使用OpenShift命令行工具手动将文件复制到其中,但我希望有一种不那么手动的解决方案。
您是否遇到过相似的问题,需要将文件放入容器中?
4个回答

38

原来我误解了密钥的工作方式,它们确实是可以挂载为文件的键值对。然而,该值可以是任何base64编码的二进制数据,将被映射为文件内容。因此,解决方案是首先将JKS文件的内容编码为base64:

cat keystore.jks| base64

然后你可以把这个放到你的秘密定义中:

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: my-namespace
data:
  keystore.jks: "<base 64 from previous command here>"

最后,您可以通过在部署配置中引用它来将其挂载到docker容器中:

apiVersion: v1
kind: DeploymentConfig
spec:
  ...
  template:
    spec:
      ...
      container:
       - name: "my-container"
         ...
         volumeMounts:
            - name: secrets
              mountPath: /mnt/secrets
              readOnly: true

     volumes:
        - name: secrets
          secret:
            secretName: "my-secret"
            items:
              - key: keystore.jks
                path: keystore.jks

这将挂载名为secrets的秘密卷到/mnt/secrets,并将名称为keystore.jks的入口作为文件keystore.jks/mnt/secrets下可用。

我不确定这是否是一个真正好的做法,但它至少在这里起作用。


那么你会如何使用这个密钥库?通过重新转换为JKS格式或其他格式吗? - Haseb Ansari
3
密钥库将被挂载到容器中的一个文件夹中。例如,在上面的示例中,它被挂载到/mnt/secrets/keystore.jks。从那里,您可以使用标准的密钥库API加载它(例如,KeyStore ks = KeyStore.getInstance("JKS"); InputStream readStream = new FileInputStream("/mnt/secrets/keystore.jks"); ks.load(readStream, keystorePasswordCharArray);)。 - Jan Thomä
1
可以将一个秘密链接到服务帐户,以便将内容作为文件注入到容器中。请参见此处-https://docs.openshift.com/container-platform/3.11/dev_guide/service_accounts.html#managing-allowed-secrets 但是,文档没有明确说明秘密被挂载的路径。有什么想法吗? - cogitoergosum
3
您也可以使用kubectl create secret generic my-secret --from-file=keystore.jks=/path/to/file/keystore.jks直接从文件创建。 - TecHunter

10

你可以像Jan Thomä所说的那样添加并安装秘钥,但是使用oc命令行工具会更容易:

您可以按照Jan Thomä所述的方式添加和挂载秘密,但是使用oc命令行工具更容易:

./oc create secret generic crnews-keystore --from-file=keystore.jks=$HOME/git/crnews-service/src/main/resources/keystore.jks --from-file=truststore.jks=$HOME/git/crnews-service/src/main/resources/truststore.jks --type=opaque

然后可以通过UI添加:应用程序->部署->->"添加配置文件",您可以选择要在哪里安装秘密。

请注意,名称=值对(例如truststore.jks=)将像filename=base64decoded-Content一样使用。


4

我的生成的Base64代码有多行,我一直收到同样的错误。

窍门是,在base64中使用-w0参数,这样整个编码就在1行中!

base64 -w0 ssl_keystore.jks > test

上述操作将创建一个名为test的文件,其中包含一行Base64编码,可像这样复制粘贴到密钥中:
apiVersion: v1
kind: Secret
metadata:
  name: staging-ssl-keystore-jks
  namespace: staging-space
type: Opaque
data:
  keystore.jsk: your-base64-in-one-line

我按照上面的指示将多行输出括起来,结果运行良好。 - matthenry87

0
在@Frischling和@Jan-Thomä所说的基础上,并且同意Frischling的方式更简单,也照顾了信任证书密钥库。在将密钥库添加为秘密后,在应用程序->部署->[您的部署名称]下,单击环境链接并添加以下系统属性:
名称:JAVA_OPTS_APPEND 和
值:-Djavax.net.ssl.keyStorePassword=changeme -Djavax.net.ssl.keyStore=/mnt/keystores/your_cert_key_store.jks -Djavax.net.ssl.trustStorePassword=changeme -Djavax.net.ssl.trustStore=/mnt/keystores/your_ca_key_store.jks

这将有效地将密钥库文件路径、密码追加到应用程序使用的Java选项中,例如JBoss/WildFly或Tomcat。

2
值得注意的是,这个解决方案可能会导致将密码以未加密的形式记录在控制台上。 - SubZr0
使用配置映射和系统属性注入可能更好,对吧?虽然如果他们登录到 shell 中仍然可以看到它们,所以也许配置映射不是很好,但唯一的其他选择是在应用程序中硬编码它们,对吧? - JGlass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接