NIFI-8094 Added support for BCFKS Keystore Type

NIFI-8094 Updated Administration Guide to include BCFKS

Signed-off-by: Nathan Gough <thenatog@gmail.com>

This closes #4729.
This commit is contained in:
exceptionfactory 2020-12-14 16:31:01 -05:00 committed by Nathan Gough
parent 82c84492ce
commit 7d76bcd520
12 changed files with 56 additions and 46 deletions

View File

@ -38,6 +38,7 @@ import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.AttributeExpression;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
@ -47,9 +48,6 @@ public class HttpNotificationService extends AbstractNotificationService {
public static final String NOTIFICATION_TYPE_KEY = "notification.type";
public static final String NOTIFICATION_SUBJECT_KEY = "notification.subject";
public static final String STORE_TYPE_JKS = "JKS";
public static final String STORE_TYPE_PKCS12 = "PKCS12";
public static final PropertyDescriptor PROP_URL = new PropertyDescriptor.Builder()
.name("URL")
.description("The URL to send the notification to.")
@ -81,8 +79,8 @@ public class HttpNotificationService extends AbstractNotificationService {
.build();
public static final PropertyDescriptor PROP_TRUSTSTORE_TYPE = new PropertyDescriptor.Builder()
.name("Truststore Type")
.description("The Type of the Truststore. Either JKS or PKCS12")
.allowableValues(STORE_TYPE_JKS, STORE_TYPE_PKCS12)
.description("The Type of the Truststore")
.allowableValues(KeystoreType.values())
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
@ -104,7 +102,7 @@ public class HttpNotificationService extends AbstractNotificationService {
public static final PropertyDescriptor PROP_KEYSTORE_TYPE = new PropertyDescriptor.Builder()
.name("Keystore Type")
.description("The Type of the Keystore")
.allowableValues(STORE_TYPE_JKS, STORE_TYPE_PKCS12)
.allowableValues(KeystoreType.values())
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();

View File

@ -20,11 +20,12 @@ import java.util.Arrays;
import java.util.stream.Collectors;
/**
* Keystore types.
* Keystore Type enumeration of supported Keystore formats
*/
public enum KeystoreType {
PKCS12("PKCS12", "A PKCS12 Keystore"),
JKS("JKS", "A Java Keystore");
BCFKS("BCFKS", "Bouncy Castle FIPS Keystore"),
PKCS12("PKCS12", "PKCS12 Keystore"),
JKS("JKS", "Java Keystore");
private final String type;
private final String description;
@ -47,7 +48,7 @@ public enum KeystoreType {
return getType();
}
public static boolean isValidKeystoreType(String type) {
public static boolean isValidKeystoreType(final String type) {
if (type == null || type.replaceAll("\\s", "").isEmpty()) {
return false;
}

View File

@ -29,6 +29,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
@ -45,23 +47,25 @@ public class KeyStoreUtils {
public static final String SUN_PROVIDER_NAME = "SUN";
private static final Map<String, String> KEY_STORE_TYPE_PROVIDERS = new HashMap<>();
static {
Security.addProvider(new BouncyCastleProvider());
KEY_STORE_TYPE_PROVIDERS.put(KeystoreType.BCFKS.getType(), BouncyCastleProvider.PROVIDER_NAME);
KEY_STORE_TYPE_PROVIDERS.put(KeystoreType.PKCS12.getType(), BouncyCastleProvider.PROVIDER_NAME);
KEY_STORE_TYPE_PROVIDERS.put(KeystoreType.JKS.getType(), SUN_PROVIDER_NAME);
}
/**
* Returns the provider that will be used for the given keyStoreType
*
* @param keyStoreType the keyStoreType
* @return the provider that will be used
* @return Key Store Provider Name or null when not found
*/
public static String getKeyStoreProvider(String keyStoreType) {
if (KeystoreType.PKCS12.toString().equalsIgnoreCase(keyStoreType)) {
return BouncyCastleProvider.PROVIDER_NAME;
} else if (KeystoreType.JKS.toString().equalsIgnoreCase(keyStoreType)) {
return SUN_PROVIDER_NAME;
}
return null;
final String storeType = StringUtils.upperCase(keyStoreType);
return KEY_STORE_TYPE_PROVIDERS.get(storeType);
}
/**
@ -103,7 +107,7 @@ public class KeyStoreUtils {
*
* @param keystorePath the file path to the keystore
* @param keystorePassword the keystore password
* @param keystoreType the keystore type ({@code JKS} or {@code PKCS12})
* @param keystoreType the keystore type
* @return the loaded keystore
* @throws TlsException if there is a problem loading the keystore
*/
@ -163,7 +167,7 @@ public class KeyStoreUtils {
* @param keystorePath the file path to the keystore
* @param keystorePassword the keystore password
* @param keyPassword the key password
* @param keystoreType the keystore type ({@code JKS} or {@code PKCS12})
* @param keystoreType the keystore type
* @return the initialized key manager factory
* @throws TlsException if there is a problem initializing or reading from the keystore
*/
@ -183,7 +187,7 @@ public class KeyStoreUtils {
*
* @param truststorePath the file path to the truststore
* @param truststorePassword the truststore password
* @param truststoreType the truststore type ({@code JKS} or {@code PKCS12})
* @param truststoreType the truststore type
* @return the loaded truststore
* @throws TlsException if there is a problem loading the truststore
*/
@ -235,7 +239,7 @@ public class KeyStoreUtils {
*
* @param truststorePath the file path to the truststore
* @param truststorePassword the truststore password
* @param truststoreType the truststore type ({@code JKS} or {@code PKCS12})
* @param truststoreType the truststore type
* @return the initialized trust manager factory
* @throws TlsException if there is a problem initializing or reading from the truststore
*/

View File

@ -59,6 +59,11 @@ public class KeyStoreUtilsTest {
DURATION_DAYS);
}
@Test
public void testBcfksKeyStoreRoundTrip() throws GeneralSecurityException, IOException {
testKeyStoreRoundTrip(() -> KeyStoreUtils.getKeyStore(KeystoreType.BCFKS.toString().toLowerCase()));
}
@Test
public void testJksKeyStoreRoundTrip() throws GeneralSecurityException, IOException {
testKeyStoreRoundTrip(() -> KeyStoreUtils.getKeyStore(KeystoreType.JKS.toString().toLowerCase()));
@ -76,6 +81,11 @@ public class KeyStoreUtilsTest {
() -> KeyStoreUtils.getKeyStore(KeystoreType.PKCS12.toString().toLowerCase()), BAD_KEY_STORE_TEST_PASSWORD_DONT_USE_THIS);
}
@Test
public void testBcfksTrustStoreRoundTrip() throws GeneralSecurityException, IOException {
testTrustStoreRoundTrip(() -> KeyStoreUtils.getKeyStore(KeystoreType.BCFKS.toString().toLowerCase()));
}
@Test
public void testJksTrustStoreRoundTrip() throws GeneralSecurityException, IOException {
testTrustStoreRoundTrip(() -> KeyStoreUtils.getTrustStore(KeystoreType.JKS.toString().toLowerCase()));

View File

@ -172,11 +172,11 @@ NiFi provides several different configuration options for security purposes. The
|==================================================================================================================================================
| Property Name | Description
|`nifi.security.keystore` | Filename of the Keystore that contains the server's private key.
|`nifi.security.keystoreType` | The type of Keystore. Must be either `PKCS12` or `JKS`. JKS is the preferred type, PKCS12 files will be loaded with BouncyCastle provider.
|`nifi.security.keystoreType` | The type of Keystore. Must be `PKCS12` or `JKS` or `BCFKS`. JKS is the preferred type, BCFKS and PKCS12 files will be loaded with BouncyCastle provider.
|`nifi.security.keystorePasswd` | The password for the Keystore.
|`nifi.security.keyPasswd` | The password for the certificate in the Keystore. If not set, the value of `nifi.security.keystorePasswd` will be used.
|`nifi.security.truststore` | Filename of the Truststore that will be used to authorize those connecting to NiFi. A secured instance with no Truststore will refuse all incoming connections.
|`nifi.security.truststoreType` | The type of the Truststore. Must be either `PKCS12` or `JKS`. JKS is the preferred type, PKCS12 files will be loaded with BouncyCastle provider.
|`nifi.security.truststoreType` | The type of the Truststore. Must be `PKCS12` or `JKS` or `BCFKS`. JKS is the preferred type, BCFKS and PKCS12 files will be loaded with BouncyCastle provider.
|`nifi.security.truststorePasswd` | The password for the Truststore.
|==================================================================================================================================================

View File

@ -70,6 +70,7 @@ import org.apache.nifi.reporting.AbstractReportingTask;
import org.apache.nifi.reporting.EventAccess;
import org.apache.nifi.reporting.ReportingContext;
import org.apache.nifi.reporting.util.provenance.ProvenanceEventConsumer;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.util.StringSelector;
@ -360,8 +361,6 @@ public class ReportLineageToAtlas extends AbstractReportingTask {
private static final String TRUSTSTORE_PASSWORD_ALIAS = "ssl.client.truststore.password";
private static final String KEYSTORE_TYPE_JKS = "JKS";
private final ServiceLoader<NamespaceResolver> namespaceResolverLoader = ServiceLoader.load(NamespaceResolver.class);
private volatile AtlasAuthN atlasAuthN;
private volatile Properties atlasProperties;
@ -698,7 +697,7 @@ public class ReportLineageToAtlas extends AbstractReportingTask {
getLogger().warn("No SSLContextService configured, the system default truststore will be used.");
} else if (!sslContextService.isTrustStoreConfigured()) {
getLogger().warn("No truststore configured on SSLContextService, the system default truststore will be used.");
} else if (!KEYSTORE_TYPE_JKS.equalsIgnoreCase(sslContextService.getTrustStoreType())) {
} else if (!KeystoreType.JKS.getType().equalsIgnoreCase(sslContextService.getTrustStoreType())) {
getLogger().warn("The configured truststore type is not supported by Atlas (not JKS), the system default truststore will be used.");
} else {
atlasProperties.put(ATLAS_PROPERTY_TRUSTSTORE_FILE, sslContextService.getTrustStoreFile());

View File

@ -23,6 +23,7 @@ import org.apache.nifi.elasticsearch.ElasticSearchClientServiceImpl
import org.apache.nifi.elasticsearch.IndexOperationRequest
import org.apache.nifi.elasticsearch.IndexOperationResponse
import org.apache.nifi.elasticsearch.SearchResponse
import org.apache.nifi.security.util.KeystoreType
import org.apache.nifi.ssl.StandardSSLContextService
import org.apache.nifi.util.TestRunner
import org.apache.nifi.util.TestRunners
@ -158,7 +159,7 @@ class ElasticSearch5ClientService_IT {
runner.addControllerService("sslContext", sslContext)
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE, "src/test/resources/truststore.jks")
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE_PASSWORD, "2DZ5i7yvbG2GA3Ld4yiAsH62QDqAjWt4ToCU0yHajwM")
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE_TYPE, StandardSSLContextService.STORE_TYPE_JKS)
runner.setProperty(sslContext, StandardSSLContextService.TRUSTSTORE_TYPE, KeystoreType.JKS.getType())
runner.setProperty(service, ElasticSearchClientService.PROP_SSL_CONTEXT_SERVICE, "sslContext")
runner.enableControllerService(sslContext)
runner.enableControllerService(service)
@ -168,7 +169,7 @@ class ElasticSearch5ClientService_IT {
runner.disableControllerService(sslContext)
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE, "src/test/resources/keystore.jks")
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE_PASSWORD, "pben4DTOUhLDI8mZiCHNX1dGEAWrpGnSYX38FTvmaeU")
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE_TYPE, StandardSSLContextService.STORE_TYPE_JKS)
runner.setProperty(sslContext, StandardSSLContextService.KEYSTORE_TYPE, KeystoreType.JKS.getType())
runner.enableControllerService(sslContext)
runner.enableControllerService(service)

View File

@ -67,12 +67,12 @@
'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
using LDAPS or START_TLS.
'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
LDAPS or START_TLS (i.e. JKS or PKCS12).
LDAPS or START_TLS such as PKCS12.
'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
LDAP using LDAPS or START_TLS.
'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
LDAPS or START_TLS (i.e. JKS or PKCS12).
LDAPS or START_TLS such as PKCS12.
'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
Possible values are REQUIRED, WANT, NONE.
'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,

View File

@ -33,12 +33,12 @@
'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
using LDAPS or START_TLS.
'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
LDAPS or START_TLS (i.e. JKS or PKCS12).
LDAPS or START_TLS such as PKCS12.
'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
LDAP using LDAPS or START_TLS.
'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
LDAPS or START_TLS (i.e. JKS or PKCS12).
LDAPS or START_TLS such as PKCS12.
'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
Possible values are REQUIRED, WANT, NONE.
'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,

View File

@ -189,10 +189,10 @@ The following properties may be used for configuring security parameters:
| Property Name | Description | Example Value |
|---------------|-------------|---------------|
| nifi.stateless.security.truststore | Filename of a Truststore to use for Site-to-Site or for interacting with NiFi Registry or Extension Clients | /etc/certs/truststore.jks |
| nifi.stateless.security.truststoreType | The type of the Truststore. JKS or PKCS12 | JKS |
| nifi.stateless.security.truststoreType | The type of the Truststore such as PKCS12 | JKS |
| nifi.stateless.security.truststorePasswd | The password of the Truststore. | do-not-use-this-password |
| nifi.stateless.security.keystore | Filename of a Keystore to use for Site-to-Site or for interacting with NiFi Registry or Extension Clients | /etc/certs/keystore.jks |
| nifi.stateless.security.keystoreType | The type of the Keystore. JKS or PKCS12 | JKS |
| nifi.stateless.security.keystoreType | The type of the Keystore such as PKCS12 | JKS |
| nifi.stateless.security.keystorePasswd | The password of the Keystore | do-not-use-this-password-either |
| nifi.stateless.security.keyPasswd | An optional password for the key in the Keystore. If not specified, the password of the Keystore itself will be used. | password |
| nifi.stateless.sensitive.props.key | The dataflow does not hold sensitive passwords, but some processors may have a need to encrypt data before storing it. This key is used to allow processors to encrypt and decrypt data. At present, the only Processor supported by the community that makes use of this feature is hte GetJMSTopic processor, which is deprecated. However, it is provided here for completeness. | Some Passphrase That's Difficult to Guess |

View File

@ -55,9 +55,6 @@ import org.apache.nifi.util.StringUtils;
+ "allows a specific set of SSL protocols to be chosen.")
public class StandardSSLContextService extends AbstractControllerService implements SSLContextService {
public static final String STORE_TYPE_JKS = "JKS";
public static final String STORE_TYPE_PKCS12 = "PKCS12";
// Shared description for other SSL context services
public static final String COMMON_TLS_PROTOCOL_DESCRIPTION = "The algorithm to use for this TLS/SSL context. \"TLS\" will instruct NiFi to allow all supported protocol versions " +
"and choose the highest available protocol for each connection. " +
@ -75,8 +72,8 @@ public class StandardSSLContextService extends AbstractControllerService impleme
.build();
public static final PropertyDescriptor TRUSTSTORE_TYPE = new PropertyDescriptor.Builder()
.name("Truststore Type")
.description("The Type of the Truststore. Either JKS or PKCS12")
.allowableValues(STORE_TYPE_JKS, STORE_TYPE_PKCS12)
.description("The Type of the Truststore")
.allowableValues(KeystoreType.values())
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
@ -98,7 +95,7 @@ public class StandardSSLContextService extends AbstractControllerService impleme
public static final PropertyDescriptor KEYSTORE_TYPE = new PropertyDescriptor.Builder()
.name("Keystore Type")
.description("The Type of the Keystore")
.allowableValues(STORE_TYPE_JKS, STORE_TYPE_PKCS12)
.allowableValues(KeystoreType.values())
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
@ -453,12 +450,12 @@ public class StandardSSLContextService extends AbstractControllerService impleme
}
/**
* Returns a list of {@link ValidationResult}s when validating an actual JKS or PKCS12 file on disk. Verifies the
* Returns a list of {@link ValidationResult}s when validating an actual truststore file on disk. Verifies the
* file permissions and existence, and attempts to open the file given the provided password.
*
* @param filename the path of the file on disk
* @param password the file password
* @param type the type (JKS or PKCS12)
* @param type the truststore type
* @return the list of validation results (empty is valid)
*/
private static List<ValidationResult> validateTruststoreFile(String filename, String password, String type) {
@ -499,13 +496,13 @@ public class StandardSSLContextService extends AbstractControllerService impleme
}
/**
* Returns a list of {@link ValidationResult}s when validating an actual JKS or PKCS12 file on disk. Verifies the
* Returns a list of {@link ValidationResult}s when validating an actual keystore file on disk. Verifies the
* file permissions and existence, and attempts to open the file given the provided (keystore or key) password.
*
* @param filename the path of the file on disk
* @param password the file password
* @param keyPassword the (optional) key-specific password
* @param type the type (JKS or PKCS12)
* @param type the keystore type
* @return the list of validation results (empty is valid)
*/
private static List<ValidationResult> validateKeystoreFile(String filename, String password, String keyPassword, String type) {

View File

@ -123,11 +123,11 @@ public enum CommandOption {
// Security related
KEYSTORE("ks", "keystore", "A keystore to use for TLS/SSL connections", true),
KEYSTORE_TYPE("kst", "keystoreType", "The type of key store being used (JKS or PKCS12)", true),
KEYSTORE_TYPE("kst", "keystoreType", "The type of key store being used such as PKCS12", true),
KEYSTORE_PASSWORD("ksp", "keystorePasswd", "The password of the keystore being used", true),
KEY_PASSWORD("kp", "keyPasswd", "The key password of the keystore being used", true),
TRUSTSTORE("ts", "truststore", "A truststore to use for TLS/SSL connections", true),
TRUSTSTORE_TYPE("tst", "truststoreType", "The type of trust store being used (JKS or PKCS12)", true),
TRUSTSTORE_TYPE("tst", "truststoreType", "The type of trust store being used such as PKCS12", true),
TRUSTSTORE_PASSWORD("tsp", "truststorePasswd", "The password of the truststore being used", true),
PROXIED_ENTITY("pe", "proxiedEntity", "The identity of an entity to proxy", true),
PROTOCOL("pro", "protocol", "The security protocol to use, such as TLSv.1.2", true),