如何在 Spring Kafka 配置中设置 ssl 文件的位置?

问题描述 投票:0回答:3

我正在尝试在 Spring 客户端和 Kafka 之间建立 ssl(mTLS) 连接。 我得到了两个文件:

  -app.keystore;
  -client.truststore.

当我用

/usr/bin/keytool -list -rfc -keystore app.keystore |grep "Keystore type"
检查文件时, 我发现类型是PKCS12。

我手动配置Kafka,因此我有一个具有Kafka属性的配置类。在配置中,我将属性“ssl.keystore.type”和“ssl.truststore.typ”设置为“PKCS12”。

文件位置在 application.properties 中设置,并使用 @Value 注释粘贴到配置中(请参阅下面的配置代码):

kafka.trust-store-location=classpath:ssl/client.truststore
kafka.key-store-location=classpath:ssl/app.keystore

物理文件放置在文件夹中: maven_module_name/src/main/resources/ssl/client.truststore maven_module_name/src/main/resources/ssl/app.keystore

当我启动应用程序时,出现错误:

Caused by: org.apache.kafka.common.KafkaException: Failed to load SSL keystore classpath:ssl/app.keystore of type PKCS12
Caused by: java.nio.file.NoSuchFileException: classpath:ssl/app.keystore

这是我的配置类:

@Configuration
public class KafkaProducerConfiguration {

...

    @Value("${kafka.key-store-location}")
    private String keyStoreLocation;

    @Value("${kafka.truststore-location}")
    private String trustStoreLocation;

    @Bean
    public Map<String, Object> producerConfigs() {
        Map<String, Object> props = new HashMap<>();
        ...
        ...
        props.put("security.protocol", "SSL");
        props.put("ssl.key.password", "password");
        props.put("ssl.keystore.location", keyStoreLocation);
        props.put("ssl.keystore.password", "password");
        props.put("ssl.keystore.type", "PKCS12");
        props.put("ssl.truststore.location", trustStoreLocation);
        props.put("ssl.truststore.password", "password");
        props.put("ssl.truststore.type", "PKCS12");
        return props;
    }

    @Bean
    public <T> ProducerFactory<Long, T> someProducerFactory() {
        return new DefaultKafkaProducerFactory<>(producerConfigs());
    }

    @Bean
    public <T> KafkaTemplate<Long, T> someKafkaTemplate() {
        ...
        return template;
    }


}

我还尝试按照此答案中的建议使用资源界面:

    @Value("${kafka.key-store-location}")
    private Resource keyStoreLocation;

    @Value("${kafka.trust-store-location}")
    private Resource trustStoreLocation;

当我尝试以这种方式获取绝对路径时:

props.put("ssl.keystore.location", keyStoreLocation.getFile().getAbsolutePath());

应用程序抛出异常:

java.io.FileNotFoundException: class path resource [ssl/app.keystore] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/BOOT-INF/classes!/ssl/app.keystore

请向我建议如何解决该问题。 谢谢。

java spring ssl apache-kafka spring-kafka
3个回答
1
投票

看起来这是 Kafka 客户端中的一个“已知问题”。 它无法从类路径加载文件,只能从文件系统加载文件。因此,当您构建应用程序时,src/main/resources 下的所有内容都会打包在 jar 文件中,并且不能直接从磁盘读取。

Spring Boot 提出了一个

解决方法

,如下: FileCopyUtils.copy(new ClassPathResource("client.ks").getInputStream(), new FileOutputStream("/tmp/client.ks"));

您的配置文件可以如下所示:

ssl.keystore.location=/tmp/client.ks



0
投票

请遵循以下一般步骤:

    通过创建一个实现接口中定义的方法的新类来实现 KeyStoreProvider 接口。
  • 使用 CredHub 客户端库或 API 连接到您的 CredHub 实例并检索 KeyStoreProvider 方法请求的密钥的值。
  • 将 CredHub 值映射到适当的 KeyStore 数据类型并从 KeyStoreProvider 方法返回它们。
  • 通过设置 security.provider.classes 属性将 Spring Boot Kafka 客户端配置为使用自定义 KeyStoreProvider。
  • 这里有一些示例代码,演示了如何实现自定义 KeyStoreProvider 从 CredHub 检索值并配置 Spring Boot Kafka 客户端来使用它:

import org.apache.kafka.common.config.AbstractConfig; import org.apache.kafka.common.config.ConfigException; import org.springframework.credhub.core.CredHubProperties; import org.springframework.credhub.core.CredHubTemplate; import org.springframework.credhub.support.CredentialDetails; import org.springframework.credhub.support.CredentialName; import org.springframework.security.crypto.keygen.StringKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import java.security.KeyStore; import java.util.HashMap; import java.util.Map; public class CredHubKeyStoreProvider implements KeyStoreProvider { private final CredHubTemplate credHubTemplate; private final StringKeyGenerator keyGenerator = KeyGenerators.string(); private final Map<String, String> keyNameMapping; public CredHubKeyStoreProvider(CredHubProperties credHubProperties, Map<String, String> keyNameMapping) { this.credHubTemplate = new CredHubTemplate(credHubProperties); this.keyNameMapping = keyNameMapping; } @Override public KeyStore getKeyStore() throws Exception { KeyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(null, null); for (Map.Entry<String, String> entry : keyNameMapping.entrySet()) { String alias = entry.getKey(); String credHubName = entry.getValue(); CredentialDetails<?> credentialDetails = credHubTemplate.getByName(new CredentialName(credHubName)); if (credentialDetails != null) { Object credentialValue = credentialDetails.getValue(); if (credentialValue instanceof byte[]) { keyStore.setKeyEntry(alias, new javax.crypto.spec.SecretKeySpec((byte[]) credentialValue, "AES"), null, null); } else if (credentialValue instanceof String) { keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(new javax.crypto.spec.SecretKeySpec(((String) credentialValue).getBytes(), "AES")), null); } } } return keyStore; } @Override public BytesKeyGenerator getBytesKeyGenerator() { return keyGenerator; } @Override public StringKeyGenerator getStringKeyGenerator() { return keyGenerator; } }

要将 Spring Boot Kafka 客户端配置为使用自定义 KeyStoreProvider,您可以在应用程序的配置中设置 security.provider.classes 属性,如下所示:

spring.kafka.security.provider.classes=com.example.CredHubKeyStoreProvider

在此示例中,com.example.CredHubKeyStoreProvider 是自定义 KeyStoreProvider 实现的完全限定名称。

不幸的是,

ssl.keystore.location

需要设置为可读文件,即使我们的KeyStore实现不使用它,因此我们将其设置为/dev/null,并将

ssl.keystore.password
设置为忽略。
请注意,您可能还需要在应用程序配置中配置与 SSL 和安全相关的其他属性,具体取决于您的 Kafka 集群。


0
投票

FileCopyUtils.copy(new ClassPathResource("truststore.jks").getInputStream(), new FileOutputStream("truststore.jks"));

在应用程序 yml 中我添加了以下配置。

trust-store-location: file:truststore.jks

JFYI,我没有为 Kafka 创建任何配置。这一切都是由 Spring boot 自己完成的。

另外,让我添加导入内容,以免访客感到困惑。

import java.io.FileOutputStream; import org.springframework.core.io.ClassPathResource; import org.springframework.util.FileCopyUtils;

© www.soinside.com 2019 - 2024. All rights reserved.