greyp9 commented on a change in pull request #5110: URL: https://github.com/apache/nifi/pull/5110#discussion_r644226669
########## File path: nifi-commons/nifi-security-kms/src/main/java/org/apache/nifi/security/kms/reader/StandardFileBasedKeyReader.java ########## @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms.reader; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +/** + * Standard File Based Key Reader reads Secret Keys from Properties files encrypted using AES-GCM with Tag Size of 128 + */ +public class StandardFileBasedKeyReader implements FileBasedKeyReader { + protected static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + protected static final int IV_LENGTH = 16; + + protected static final int TAG_SIZE = 128; Review comment: // size in bits suggest clarifying comments to specify the units ########## File path: nifi-commons/nifi-security-kms/src/test/java/org/apache/nifi/security/kms/util/SecretKeyUtils.java ########## @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms.util; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Base64; +import java.util.Map; +import java.util.Properties; + +public class SecretKeyUtils { + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); Review comment: It might better if the lifetime of this is less than the lifetime of the process. ########## File path: nifi-commons/nifi-security-kms/src/main/java/org/apache/nifi/security/kms/reader/StandardFileBasedKeyReader.java ########## @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms.reader; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +/** + * Standard File Based Key Reader reads Secret Keys from Properties files encrypted using AES-GCM with Tag Size of 128 + */ +public class StandardFileBasedKeyReader implements FileBasedKeyReader { + protected static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + protected static final int IV_LENGTH = 16; Review comment: // length in bytes ########## File path: nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/kms/CryptoUtils.java ########## @@ -445,7 +331,7 @@ public static boolean constantTimeEquals(byte[] a, byte[] b) { */ private static byte[] convertCharsToBytes(char[] chars) { CharBuffer charBuffer = CharBuffer.wrap(chars); - ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer); + ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer); Review comment: +1 ########## File path: nifi-commons/nifi-security-kms/src/main/java/org/apache/nifi/security/kms/KeyProviderFactory.java ########## @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms; + +import org.apache.commons.codec.DecoderException; +import org.apache.nifi.security.kms.configuration.FileBasedKeyProviderConfiguration; +import org.apache.nifi.security.kms.configuration.KeyProviderConfiguration; +import org.apache.nifi.security.kms.configuration.KeyStoreKeyProviderConfiguration; +import org.apache.nifi.security.kms.configuration.StaticKeyProviderConfiguration; +import org.apache.commons.codec.binary.Hex; +import org.apache.nifi.security.kms.reader.KeyReaderException; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.util.HashMap; +import java.util.Map; + +/** + * Key Provider Factory + */ +public class KeyProviderFactory { + private static final String SECRET_KEY_ALGORITHM = "AES"; Review comment: This declaration is duplicated in several places in the code. Should we consider consolidating these? Is "nifi-security-kms" module close enough to the base that this might be the place? ########## File path: nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/util/KeyStoreUtilsTest.java ########## @@ -115,11 +142,30 @@ private void assertKeyEntryStoredLoaded(final KeyStore sourceKeyStore, final Key assertEquals(String.format("[%s] Public Key not matched", sourceKeyStore.getType()), keyPair.getPublic(), entryCertificateChain[0].getPublicKey()); } + private void assertSecretKeyStoredLoaded(final KeyStore sourceKeyStore, final KeyStore destinationKeyStore) throws GeneralSecurityException, IOException { + sourceKeyStore.load(null, null); + final KeyStore.ProtectionParameter protection = getProtectionParameter(sourceKeyStore.getType()); + sourceKeyStore.setEntry(ALIAS, new KeyStore.SecretKeyEntry(secretKey), protection); + + final KeyStore copiedKeyStore = copyKeyStore(sourceKeyStore, destinationKeyStore); + final KeyStore.Entry entry = copiedKeyStore.getEntry(ALIAS, protection); + assertTrue(String.format("[%s] Secret Key entry not found", sourceKeyStore.getType()), entry instanceof KeyStore.SecretKeyEntry); + } + private KeyStore copyKeyStore(final KeyStore sourceKeyStore, final KeyStore destinationKeyStore) throws GeneralSecurityException, IOException { final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); sourceKeyStore.store(byteArrayOutputStream, STORE_PASSWORD); destinationKeyStore.load(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), STORE_PASSWORD); return destinationKeyStore; } + + private KeyStore.ProtectionParameter getProtectionParameter(final String keyStoreType) { + if (KeystoreType.PKCS12.getType().equals(keyStoreType)) { + // Select Key Protection Algorithm for PKCS12 to avoid unsupported algorithm on Java 1.8.0.292 Review comment: helpful comment ########## File path: nifi-commons/nifi-security-kms/src/test/java/org/apache/nifi/security/kms/FileBasedKeyProviderTest.java ########## @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms; + +import org.apache.nifi.security.kms.util.SecretKeyUtils; +import org.junit.Test; + +import javax.crypto.SecretKey; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class FileBasedKeyProviderTest { + private static final String KEYS_EXTENSION = ".keys"; + + private static final String KEY_ID = UUID.randomUUID().toString(); + + @Test + public void testGetKey() throws GeneralSecurityException, IOException { + final SecretKey rootKey = SecretKeyUtils.getSecretKey(); + final SecretKey secretKey = SecretKeyUtils.getSecretKey(); + final Path secretKeysPath = getSecretKeysPath(rootKey, Collections.singletonMap(KEY_ID, secretKey)); + final FileBasedKeyProvider provider = new FileBasedKeyProvider(secretKeysPath, rootKey); + + final SecretKey secretKeyFound = provider.getKey(KEY_ID); + assertEquals(secretKey, secretKeyFound); + assertTrue(provider.keyExists(KEY_ID)); + assertFalse(provider.getAvailableKeyIds().isEmpty()); + } + + private Path getSecretKeysPath(final SecretKey rootKey, final Map<String, SecretKey> secretKeys) throws IOException, GeneralSecurityException { + final Path path = Files.createTempFile(FileBasedKeyProviderTest.class.getSimpleName(), KEYS_EXTENSION); + path.toFile().deleteOnExit(); + + final Properties properties = SecretKeyUtils.getEncryptedSecretKeys(rootKey, secretKeys); + try (final OutputStream outputStream = new FileOutputStream(path.toFile())) { Review comment: Interesting that the base64 trailer bytes are escaped. But I guess that makes sense. ``` #Wed Jun 02 14:20:23 EDT 2021 fdf3bc86-c2ed-43d4-b9af-853cb0b6745a = STakjx+cvYMcCrfYgog2hHAgj5e44t1DHfyAzqImW7UI7svXUI1LbUsorsZdqhtR/pkOSgFK/MGXyAi79B3LFw\=\= ``` ########## File path: nifi-docs/src/main/asciidoc/administration-guide.adoc ########## @@ -2829,8 +2829,9 @@ NOTE: Unlike the encrypted content and provenance repositories, the repository i |==== |*Property*|*Description* -|`nifi.flowfile.repository.encryption.key.provider.implementation`|This is the fully-qualified class name of the **key provider**. A key provider is the datastore interface for accessing the encryption key to protect the content claims. There are currently two implementations -- `StaticKeyProvider` which reads a key directly from _nifi.properties_, and `FileBasedKeyProvider` which reads *n* many keys from an encrypted file. The interface is extensible, and HSM-backed or other providers are expected in the future. +|`nifi.flowfile.repository.encryption.key.provider.implementation`|This is the fully-qualified class name of the **key provider**. A key provider is the datastore interface for accessing the encryption key to protect the content claims. There are currently three implementations: `StaticKeyProvider` which reads a key directly from _nifi.properties_, `FileBasedKeyProvider` which reads keys from an encrypted file, and `KeyStoreKeyProvider` which reads keys from an encrypted keystore. Review comment: `KeyStoreKeyProvider` which reads keys from a standard, password-protected `java.security.Keystore`. ########## File path: nifi-commons/nifi-security-kms/src/test/java/org/apache/nifi/security/kms/util/SecretKeyUtils.java ########## @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms.util; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Base64; +import java.util.Map; +import java.util.Properties; + +public class SecretKeyUtils { + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + private static final Base64.Encoder ENCODER = Base64.getEncoder(); + + private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + private static final String KEY_ALGORITHM = "AES"; + + private static final int KEY_LENGTH = 32; + + private static final int IV_LENGTH = 16; + + private static final int TAG_LENGTH = 128; + + /** + * Get Encrypted Secret Keys as Properties + * + * @param rootKey Root Key used to encrypt Secret Keys + * @param secretKeys Map of Key Identifier to Secret Key + * @return Properties containing encrypted Secret Keys + * @throws GeneralSecurityException Thrown on getEncryptedSecretKey() + */ + public static Properties getEncryptedSecretKeys(final SecretKey rootKey, final Map<String, SecretKey> secretKeys) throws GeneralSecurityException { + final Properties properties = new Properties(); + for (final Map.Entry<String, SecretKey> secretKeyEntry : secretKeys.entrySet()) { + final SecretKey secretKey = secretKeyEntry.getValue(); + final String encryptedSecretKey = getEncryptedSecretKey(rootKey, secretKey); + properties.setProperty(secretKeyEntry.getKey(), encryptedSecretKey); + } + return properties; + } + + /** + * Get Random AES Secret Key + * + * @return Secret Key + */ + public static SecretKey getSecretKey() { + final byte[] encodedKey = new byte[KEY_LENGTH]; + SECURE_RANDOM.nextBytes(encodedKey); + return new SecretKeySpec(encodedKey, KEY_ALGORITHM); + } + + /** + * Get Encrypted Secret Key using AES-GCM with Base64 encoded string prefixed with initialization vector + * + * @param rootKey Root Key used to encrypt Secret Key + * @param secretKey Secret Key to be encrypted + * @return Base64 encoded and encrypted Secret Key + * @throws GeneralSecurityException Thrown when unable to encrypt Secret Key + */ + private static String getEncryptedSecretKey(final SecretKey rootKey, final SecretKey secretKey) throws GeneralSecurityException { + final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + + final byte[] initializationVector = new byte[IV_LENGTH]; + SECURE_RANDOM.nextBytes(initializationVector); + cipher.init(Cipher.ENCRYPT_MODE, rootKey, new GCMParameterSpec(TAG_LENGTH, initializationVector)); + final byte[] encryptedSecretKey = cipher.doFinal(secretKey.getEncoded()); + + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + outputStream.write(initializationVector); + outputStream.write(encryptedSecretKey); + } catch (final IOException e) { + throw new UncheckedIOException(e); Review comment: Would this be better as a GeneralSecurityException? ########## File path: nifi-commons/nifi-security-kms/src/main/java/org/apache/nifi/security/kms/reader/StandardFileBasedKeyReader.java ########## @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.security.kms.reader; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +/** + * Standard File Based Key Reader reads Secret Keys from Properties files encrypted using AES-GCM with Tag Size of 128 + */ +public class StandardFileBasedKeyReader implements FileBasedKeyReader { + protected static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + protected static final int IV_LENGTH = 16; + + protected static final int TAG_SIZE = 128; + + private static final Base64.Decoder DECODER = Base64.getDecoder(); + + private static final String SECRET_KEY_ALGORITHM = "AES"; + + /** + * Read Secret Keys using provided Root Secret Key + * + * @param path File Path contains a properties file with Key Identifier and Base64-encoded encrypted values + * @param rootKey Root Secret Key + * @return Map of Key Identifier to decrypted Secret Key + */ + @Override + public Map<String, SecretKey> readSecretKeys(final Path path, final SecretKey rootKey) { + Objects.requireNonNull(path, "Path required"); + Objects.requireNonNull(rootKey, "Root Key required"); + final Map<String, SecretKey> secretKeys = new HashMap<>(); + + final Properties properties = getProperties(path); + for (final String keyId : properties.stringPropertyNames()) { + final String encodedProperty = properties.getProperty(keyId); + final SecretKey secretKey = readSecretKey(keyId, encodedProperty, rootKey); + secretKeys.put(keyId, secretKey); + } + return secretKeys; + } + + private Properties getProperties(final Path path) { + final Properties properties = new Properties(); + try (final FileInputStream inputStream = new FileInputStream(path.toFile())) { + properties.load(inputStream); + } catch (final IOException e) { + throw new KeyReaderException(String.format("Reading Secret Keys Failed [%s]", path), e); + } + return properties; + } + + private SecretKey readSecretKey(final String keyId, final String encodedProperty, final SecretKey rootKey) { Review comment: Do you have any plan for a means of writing secret keys in this format? ########## File path: nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/KeyStoreUtils.java ########## @@ -143,6 +169,27 @@ public static KeyStore loadKeyStore(String keystorePath, char[] keystorePassword } } + /** + * Load {@link KeyStore} containing Secret Key entries using configured Security Provider + * + * @param keystorePath File path to KeyStore + * @param keystorePassword Password for loading KeyStore + * @param keystoreTypeName Keystore Type Name + * @return KeyStore loaded using specified configuration + * @throws TlsException Thrown when unable to load KeyStore or unsupported Keystore Type + */ + public static KeyStore loadSecretKeyStore(final String keystorePath, final char[] keystorePassword, final String keystoreTypeName) throws TlsException { + try { + final KeyStore keyStore = getSecretKeyStore(keystoreTypeName); + try (final InputStream keyStoreStream = new FileInputStream(keystorePath)) { + keyStore.load(keyStoreStream, keystorePassword); + } + return keyStore; + } catch (final GeneralSecurityException|IOException e) { + throw new TlsException(String.format("Loading Secret Keystore [%s] Type [%s] Failed", keystorePath, keystoreTypeName), e); Review comment: How about KeyStoreException? ########## File path: nifi-docs/src/main/asciidoc/user-guide.adoc ########## @@ -3001,6 +3029,34 @@ key5=c6FzfnKm7UR7xqI2NFpZ+fEKBfSU7+1NvRw+XWQ9U39MONWqk5gvoyOCdFR1kUgeg46jrN5dGXk Each line defines a key ID and then the Base64-encoded cipher text of a 16 byte IV and wrapped AES-128, AES-192, or AES-256 key depending on the JCE policies available. The individual keys are wrapped by AES/GCM encryption using the **root key** defined by `nifi.bootstrap.sensitive.key` in _conf/bootstrap.conf_. +==== KeyStoreKeyProvider +The `KeyStoreKeyProvider` implementation reads from an encrypted keystore using the configured password to load AES Secret Key entries. Review comment: ... reads from an encrypted `java.security.KeyStore` using ... ########## File path: nifi-docs/src/main/asciidoc/user-guide.adoc ########## @@ -2922,6 +2922,34 @@ key5=c6FzfnKm7UR7xqI2NFpZ+fEKBfSU7+1NvRw+XWQ9U39MONWqk5gvoyOCdFR1kUgeg46jrN5dGXk Each line defines a key ID and then the Base64-encoded cipher text of a 16 byte IV and wrapped AES-128, AES-192, or AES-256 key depending on the JCE policies available. The individual keys are wrapped by AES/GCM encryption using the **root key** defined by `nifi.bootstrap.sensitive.key` in _conf/bootstrap.conf_. +===== KeyStoreKeyProvider +The `KeyStoreKeyProvider` implementation reads from an encrypted keystore using the configured password to load AES Secret Key entries. + +The provider supports the following Keystore Types: + +* BCFKS +* PKCS12 + +The keystore filename extension must be either `.p12` indicating PKCS12 or `.bcfks` indicating BCFKS. + +The `keytool` command can be used to generate an AES-256 Secret Key stored in a PKCS12 file for repository encryption: + +... +keytool -genseckey -alias primary-key -keyalg AES -keysize 256 -keystore repository.p12 -storetype PKCS12 Review comment: great idea to provide a command template ########## File path: nifi-docs/src/main/asciidoc/administration-guide.adoc ########## @@ -2829,8 +2829,9 @@ NOTE: Unlike the encrypted content and provenance repositories, the repository i |==== |*Property*|*Description* -|`nifi.flowfile.repository.encryption.key.provider.implementation`|This is the fully-qualified class name of the **key provider**. A key provider is the datastore interface for accessing the encryption key to protect the content claims. There are currently two implementations -- `StaticKeyProvider` which reads a key directly from _nifi.properties_, and `FileBasedKeyProvider` which reads *n* many keys from an encrypted file. The interface is extensible, and HSM-backed or other providers are expected in the future. +|`nifi.flowfile.repository.encryption.key.provider.implementation`|This is the fully-qualified class name of the **key provider**. A key provider is the datastore interface for accessing the encryption key to protect the content claims. There are currently three implementations: `StaticKeyProvider` which reads a key directly from _nifi.properties_, `FileBasedKeyProvider` which reads keys from an encrypted file, and `KeyStoreKeyProvider` which reads keys from an encrypted keystore. Review comment: Also propagate below. ########## File path: nifi-docs/src/main/asciidoc/user-guide.adoc ########## @@ -2922,6 +2922,34 @@ key5=c6FzfnKm7UR7xqI2NFpZ+fEKBfSU7+1NvRw+XWQ9U39MONWqk5gvoyOCdFR1kUgeg46jrN5dGXk Each line defines a key ID and then the Base64-encoded cipher text of a 16 byte IV and wrapped AES-128, AES-192, or AES-256 key depending on the JCE policies available. The individual keys are wrapped by AES/GCM encryption using the **root key** defined by `nifi.bootstrap.sensitive.key` in _conf/bootstrap.conf_. +===== KeyStoreKeyProvider +The `KeyStoreKeyProvider` implementation reads from an encrypted keystore using the configured password to load AES Secret Key entries. + +The provider supports the following Keystore Types: + +* BCFKS +* PKCS12 Review comment: We are discouraging use of JKS? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org