This is an automated email from the ASF dual-hosted git repository.
dajac pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 1c02a764eca KAFKA-12703; Allow unencrypted private keys when using PEM
files (#11916)
1c02a764eca is described below
commit 1c02a764eca19d2606259a4efa58f6cfdfc8e70a
Author: Dejan Maric <[email protected]>
AuthorDate: Mon May 16 09:25:05 2022 +0200
KAFKA-12703; Allow unencrypted private keys when using PEM files (#11916)
Reviewers: David Jacot <[email protected]>
---
.../org/apache/kafka/common/config/SslConfigs.java | 2 +-
.../common/security/ssl/DefaultSslEngineFactory.java | 2 --
.../kafka/common/network/SslTransportLayerTest.java | 18 ++++--------------
.../security/ssl/DefaultSslEngineFactoryTest.java | 11 ++++++++---
docs/security.html | 2 +-
5 files changed, 14 insertions(+), 21 deletions(-)
diff --git
a/clients/src/main/java/org/apache/kafka/common/config/SslConfigs.java
b/clients/src/main/java/org/apache/kafka/common/config/SslConfigs.java
index 5061ed5cfca..62343a23b57 100644
--- a/clients/src/main/java/org/apache/kafka/common/config/SslConfigs.java
+++ b/clients/src/main/java/org/apache/kafka/common/config/SslConfigs.java
@@ -96,7 +96,7 @@ public class SslConfigs {
public static final String SSL_KEY_PASSWORD_CONFIG = "ssl.key.password";
public static final String SSL_KEY_PASSWORD_DOC = "The password of the
private key in the key store file or "
- + "the PEM key specified in `ssl.keystore.key'. This is required for
clients only if two-way authentication is configured.";
+ + "the PEM key specified in `ssl.keystore.key'.";
public static final String SSL_TRUSTSTORE_TYPE_CONFIG =
"ssl.truststore.type";
public static final String SSL_TRUSTSTORE_TYPE_DOC = "The file format of
the trust store file.";
diff --git
a/clients/src/main/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactory.java
b/clients/src/main/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactory.java
index a46626e7d79..ac16c21bfc8 100644
---
a/clients/src/main/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactory.java
+++
b/clients/src/main/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactory.java
@@ -287,8 +287,6 @@ public final class DefaultSslEngineFactory implements
SslEngineFactory {
} else if (PEM_TYPE.equals(type) && path != null) {
if (password != null)
throw new InvalidConfigurationException("SSL key store
password cannot be specified with PEM format, only key password may be
specified");
- else if (keyPassword == null)
- throw new InvalidConfigurationException("SSL PEM key store is
specified, but key password is not specified.");
else
return new FileBasedPemStore(path, keyPassword, true);
} else if (path == null && password != null) {
diff --git
a/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
b/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
index 5b0d4172d8c..d78e5f44b27 100644
---
a/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
+++
b/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
@@ -490,9 +490,7 @@ public class SslTransportLayerTest {
}
/**
- * Test with PEM key store files without key password for client key
store. We don't allow this
- * with PEM files since unprotected private key on disk is not safe. We do
allow with inline
- * PEM config since key config can be encrypted or externalized similar to
other password configs.
+ * Test with PEM key store files without key password for client key store.
*/
@ParameterizedTest
@ArgumentsSource(SslTransportLayerArgumentsProvider.class)
@@ -502,27 +500,19 @@ public class SslTransportLayerTest {
TestSslUtils.convertToPem(args.sslClientConfigs, !useInlinePem, false);
args.sslServerConfigs.put(BrokerSecurityConfigs.SSL_CLIENT_AUTH_CONFIG,
"required");
server = createEchoServer(args, SecurityProtocol.SSL);
- if (useInlinePem)
- verifySslConfigs(args);
- else
- assertThrows(KafkaException.class, () ->
createSelector(args.sslClientConfigs));
+ verifySslConfigs(args);
}
/**
* Test with PEM key store files without key password for server key
store.We don't allow this
- * with PEM files since unprotected private key on disk is not safe. We do
allow with inline
- * PEM config since key config can be encrypted or externalized similar to
other password configs.
+ * with PEM files since unprotected private key on disk is not safe.
*/
@ParameterizedTest
@ArgumentsSource(SslTransportLayerArgumentsProvider.class)
public void testPemFilesWithoutServerKeyPassword(Args args) throws
Exception {
TestSslUtils.convertToPem(args.sslServerConfigs, !args.useInlinePem,
false);
TestSslUtils.convertToPem(args.sslClientConfigs, !args.useInlinePem,
true);
-
- if (args.useInlinePem)
- verifySslConfigs(args);
- else
- assertThrows(KafkaException.class, () -> createEchoServer(args,
SecurityProtocol.SSL));
+ verifySslConfigs(args);
}
/**
diff --git
a/clients/src/test/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactoryTest.java
b/clients/src/test/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactoryTest.java
index 0e494cc529d..fc3726ac59a 100644
---
a/clients/src/test/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactoryTest.java
+++
b/clients/src/test/java/org/apache/kafka/common/security/ssl/DefaultSslEngineFactoryTest.java
@@ -18,7 +18,6 @@ package org.apache.kafka.common.security.ssl;
import org.apache.kafka.common.config.SslConfigs;
import org.apache.kafka.common.config.types.Password;
-import org.apache.kafka.common.errors.InvalidConfigurationException;
import org.apache.kafka.test.TestUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -33,7 +32,6 @@ import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
public class DefaultSslEngineFactoryTest {
@@ -291,7 +289,14 @@ public class DefaultSslEngineFactoryTest {
configs.put(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG,
pemFilePath(pemAsConfigValue(KEY, CERTCHAIN).value()));
configs.put(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG,
DefaultSslEngineFactory.PEM_TYPE);
- assertThrows(InvalidConfigurationException.class, () ->
factory.configure(configs));
+ configs.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, null);
+ factory.configure(configs);
+
+ KeyStore keyStore = factory.keystore();
+ List<String> aliases = Collections.list(keyStore.aliases());
+ assertEquals(Collections.singletonList("kafka"), aliases);
+ assertNotNull(keyStore.getCertificate("kafka"), "Certificate not
loaded");
+ assertNotNull(keyStore.getKey("kafka", null), "Private key not
loaded");
}
@Test
diff --git a/docs/security.html b/docs/security.html
index 846ce5f20bc..21ec72cec50 100644
--- a/docs/security.html
+++ b/docs/security.html
@@ -271,7 +271,7 @@ keyUsage = digitalSignature,
keyEncipherment</code></pre>
<p>Store password configs <code>ssl.keystore.password</code> and
<code>ssl.truststore.password</code> are not used for PEM.
If private key is encrypted using a password, the key password
must be provided in <code>ssl.key.password</code>. Private keys may be provided
- in unencrypted form without a password when PEM is specified
directly in the config value. In production deployments, configs should be
encrypted or
+ in unencrypted form without a password. In production deployments,
configs should be encrypted or
externalized using password protection feature in Kafka in this
case. Note that the default SSL engine factory has limited capabilities for
decryption
of encrypted private keys when external tools like OpenSSL are
used for encryption. Third party libraries like BouncyCastle may be integrated
witn a
custom <code>SslEngineFactory</code> to support a wider range of
encrypted private keys.</p>