diff --git a/libs/common/src/main/java/org/opensearch/common/crypto/CryptoHandler.java b/libs/common/src/main/java/org/opensearch/common/crypto/CryptoHandler.java index f8fd983543117..37322310c7287 100644 --- a/libs/common/src/main/java/org/opensearch/common/crypto/CryptoHandler.java +++ b/libs/common/src/main/java/org/opensearch/common/crypto/CryptoHandler.java @@ -11,6 +11,7 @@ import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.common.io.InputStreamContainer; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; @@ -22,7 +23,7 @@ * U - Parsed Encryption Metadata / CryptoContext */ @ExperimentalApi -public interface CryptoHandler { +public interface CryptoHandler extends Closeable { /** * To initialise or create a new crypto metadata to be used in encryption. This is needed to set the context before diff --git a/libs/encryption-sdk/licenses/aws-encryption-sdk-java-2.4.0.jar.sha1 b/libs/encryption-sdk/licenses/aws-encryption-sdk-java-2.4.0.jar.sha1 deleted file mode 100644 index 504b4a423a975..0000000000000 --- a/libs/encryption-sdk/licenses/aws-encryption-sdk-java-2.4.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -98943eda1dc05bb01f4f5405e115b08dc541afbf \ No newline at end of file diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManager.java b/libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManager.java deleted file mode 100644 index 8e1fc8570d552..0000000000000 --- a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.encryption; - -import org.opensearch.common.crypto.CryptoHandler; -import org.opensearch.common.util.concurrent.RefCounted; - -/** - * Crypto plugin interface used for encryption and decryption. - */ -public interface CryptoManager extends RefCounted { - - /** - * @return key provider type - */ - String type(); - - /** - * @return key provider name - */ - String name(); - - /** - * @return Crypto provider for encrypting or decrypting raw content. - */ - CryptoHandler getCryptoProvider(); -} diff --git a/libs/encryption-sdk/build.gradle b/modules/crypto/build.gradle similarity index 81% rename from libs/encryption-sdk/build.gradle rename to modules/crypto/build.gradle index c87394f8d9cb9..279e4b0b675c1 100644 --- a/libs/encryption-sdk/build.gradle +++ b/modules/crypto/build.gradle @@ -15,12 +15,17 @@ thirdPartyAudit.enabled = false forbiddenApisTest.ignoreFailures = true testingConventions.enabled = false +opensearchplugin { + description 'Crypto module plugin for providing encryption and decryption support.' + classname 'org.opensearch.encryption.CryptoModulePlugin' +} + dependencies { // Common crypto classes api project(':libs:opensearch-common') - // Encryption - implementation "com.amazonaws:aws-encryption-sdk-java:2.4.0" + implementation "com.amazonaws:aws-encryption-sdk-java:1.7.0" + implementation "org.bouncycastle:bcprov-jdk15to18:${versions.bouncycastle}" implementation "org.apache.commons:commons-lang3:${versions.commonslang}" //Tests diff --git a/modules/crypto/licenses/aws-encryption-sdk-java-1.7.0.jar.sha1 b/modules/crypto/licenses/aws-encryption-sdk-java-1.7.0.jar.sha1 new file mode 100644 index 0000000000000..e0bb769bbf849 --- /dev/null +++ b/modules/crypto/licenses/aws-encryption-sdk-java-1.7.0.jar.sha1 @@ -0,0 +1 @@ +51704a672e65456d37f444c5992c079feff31218 \ No newline at end of file diff --git a/libs/encryption-sdk/licenses/aws-encryption-sdk-java-LICENSE.txt b/modules/crypto/licenses/aws-encryption-sdk-java-LICENSE.txt similarity index 100% rename from libs/encryption-sdk/licenses/aws-encryption-sdk-java-LICENSE.txt rename to modules/crypto/licenses/aws-encryption-sdk-java-LICENSE.txt diff --git a/libs/encryption-sdk/licenses/aws-encryption-sdk-java-NOTICE.txt b/modules/crypto/licenses/aws-encryption-sdk-java-NOTICE.txt similarity index 100% rename from libs/encryption-sdk/licenses/aws-encryption-sdk-java-NOTICE.txt rename to modules/crypto/licenses/aws-encryption-sdk-java-NOTICE.txt diff --git a/modules/crypto/licenses/bcprov-jdk15to18-1.75.jar.sha1 b/modules/crypto/licenses/bcprov-jdk15to18-1.75.jar.sha1 new file mode 100644 index 0000000000000..9911bb75f9209 --- /dev/null +++ b/modules/crypto/licenses/bcprov-jdk15to18-1.75.jar.sha1 @@ -0,0 +1 @@ +df22e1b6a9f6b218913f5b68dd16641344397fe0 \ No newline at end of file diff --git a/modules/crypto/licenses/bcprov-jdk15to18-LICENSE.txt b/modules/crypto/licenses/bcprov-jdk15to18-LICENSE.txt new file mode 100644 index 0000000000000..9f27bafe96885 --- /dev/null +++ b/modules/crypto/licenses/bcprov-jdk15to18-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc. + (http://www.bouncycastle.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/modules/crypto/licenses/bcprov-jdk15to18-NOTICE.txt b/modules/crypto/licenses/bcprov-jdk15to18-NOTICE.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/libs/encryption-sdk/licenses/commons-lang3-3.13.0.jar.sha1 b/modules/crypto/licenses/commons-lang3-3.13.0.jar.sha1 similarity index 100% rename from libs/encryption-sdk/licenses/commons-lang3-3.13.0.jar.sha1 rename to modules/crypto/licenses/commons-lang3-3.13.0.jar.sha1 diff --git a/libs/encryption-sdk/licenses/commons-lang3-LICENSE.txt b/modules/crypto/licenses/commons-lang3-LICENSE.txt similarity index 100% rename from libs/encryption-sdk/licenses/commons-lang3-LICENSE.txt rename to modules/crypto/licenses/commons-lang3-LICENSE.txt diff --git a/libs/encryption-sdk/licenses/commons-lang3-NOTICE.txt b/modules/crypto/licenses/commons-lang3-NOTICE.txt similarity index 100% rename from libs/encryption-sdk/licenses/commons-lang3-NOTICE.txt rename to modules/crypto/licenses/commons-lang3-NOTICE.txt diff --git a/libs/encryption-sdk/src/forbidden/crypto-signatures.txt b/modules/crypto/src/forbidden/crypto-signatures.txt similarity index 100% rename from libs/encryption-sdk/src/forbidden/crypto-signatures.txt rename to modules/crypto/src/forbidden/crypto-signatures.txt diff --git a/libs/encryption-sdk/src/forbidden/crypto-test-signatures.txt b/modules/crypto/src/forbidden/crypto-test-signatures.txt similarity index 100% rename from libs/encryption-sdk/src/forbidden/crypto-test-signatures.txt rename to modules/crypto/src/forbidden/crypto-test-signatures.txt diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManagerFactory.java b/modules/crypto/src/main/java/org/opensearch/encryption/CryptoModulePlugin.java similarity index 60% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManagerFactory.java rename to modules/crypto/src/main/java/org/opensearch/encryption/CryptoModulePlugin.java index e1dc9291ed1a6..36c278b16d08a 100644 --- a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/CryptoManagerFactory.java +++ b/modules/crypto/src/main/java/org/opensearch/encryption/CryptoModulePlugin.java @@ -11,8 +11,9 @@ import org.opensearch.common.crypto.CryptoHandler; import org.opensearch.common.crypto.MasterKeyProvider; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.AbstractRefCounted; import org.opensearch.encryption.keyprovider.CryptoMasterKey; +import org.opensearch.plugins.CryptoPlugin; +import org.opensearch.plugins.Plugin; import java.security.SecureRandom; import java.util.concurrent.TimeUnit; @@ -21,23 +22,16 @@ import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager; import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache; -public class CryptoManagerFactory { +public class CryptoModulePlugin extends Plugin implements CryptoPlugin { - private final int dataKeyCacheSize; - private final String algorithm; + private final int dataKeyCacheSize = 500; + private final String algorithm = "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY"; // - Cache TTL and Jitter is used to decide the Crypto Cache TTL. // - Random number between: (TTL Jitter, TTL - Jitter) - private final long dataKeyCacheTTL; + private final long dataKeyCacheTTL = TimeValue.timeValueDays(2).getMillis(); private static final long dataKeyCacheJitter = TimeUnit.MINUTES.toMillis(30); // - 30 minutes - public CryptoManagerFactory(String algorithm, TimeValue keyRefreshInterval, int keyCacheSize) { - this.dataKeyCacheSize = keyCacheSize; - validateAndGetAlgorithmId(algorithm); - this.algorithm = algorithm; - dataKeyCacheTTL = keyRefreshInterval.getMillis(); - } - private String validateAndGetAlgorithmId(String algorithm) { // Supporting only 256 bit algorithm switch (algorithm) { @@ -50,7 +44,7 @@ private String validateAndGetAlgorithmId(String algorithm) { } } - public CryptoManager getOrCreateCryptoManager( + public CryptoHandler getOrCreateCryptoHandler( MasterKeyProvider keyProvider, String keyProviderName, String keyProviderType, @@ -61,12 +55,11 @@ private String validateAndGetAlgorithmId(String algorithm) { keyProviderName, validateAndGetAlgorithmId(algorithm) ); - CryptoHandler cryptoHandler = createCryptoProvider(algorithm, materialsManager, keyProvider); - return createCryptoManager(cryptoHandler, keyProviderType, keyProviderName, onClose); + return createCryptoProvider(algorithm, materialsManager, keyProvider); } // package private for tests - CryptoHandler createCryptoProvider( + CryptoHandler createCryptoProvider( String algorithm, CachingCryptoMaterialsManager materialsManager, MasterKeyProvider masterKeyProvider @@ -88,40 +81,4 @@ CachingCryptoMaterialsManager createMaterialsManager(MasterKeyProvider masterKey .withMaxAge(masterKeyCacheTTL, TimeUnit.MILLISECONDS) .build(); } - - // package private for tests - CryptoManager createCryptoManager( - CryptoHandler cryptoHandler, - String keyProviderType, - String keyProviderName, - Runnable onClose - ) { - return new CryptoManagerImpl(keyProviderName, keyProviderType) { - @Override - protected void closeInternal() { - onClose.run(); - } - - @Override - public String type() { - return keyProviderType; - } - - @Override - public String name() { - return keyProviderName; - } - - @Override - public CryptoHandler getCryptoProvider() { - return cryptoHandler; - } - }; - } - - private static abstract class CryptoManagerImpl extends AbstractRefCounted implements CryptoManager { - public CryptoManagerImpl(String keyProviderName, String keyProviderType) { - super(keyProviderName + "-" + keyProviderType); - } - } } diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java b/modules/crypto/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java similarity index 98% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java rename to modules/crypto/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java index d6b23ed08c6b0..136ef50afbddc 100644 --- a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java +++ b/modules/crypto/src/main/java/org/opensearch/encryption/NoOpCryptoHandler.java @@ -125,4 +125,8 @@ public DecryptedRangedStreamProvider createDecryptingStreamOfRange( return new DecryptedRangedStreamProvider(range, (encryptedStream) -> encryptedStream); } + @Override + public void close() { + // Nothing to close. + } } diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/TrimmingStream.java b/modules/crypto/src/main/java/org/opensearch/encryption/TrimmingStream.java similarity index 100% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/TrimmingStream.java rename to modules/crypto/src/main/java/org/opensearch/encryption/TrimmingStream.java diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/keyprovider/CryptoMasterKey.java b/modules/crypto/src/main/java/org/opensearch/encryption/keyprovider/CryptoMasterKey.java similarity index 100% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/keyprovider/CryptoMasterKey.java rename to modules/crypto/src/main/java/org/opensearch/encryption/keyprovider/CryptoMasterKey.java diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/keyprovider/package-info.java b/modules/crypto/src/main/java/org/opensearch/encryption/keyprovider/package-info.java similarity index 100% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/keyprovider/package-info.java rename to modules/crypto/src/main/java/org/opensearch/encryption/keyprovider/package-info.java diff --git a/libs/encryption-sdk/src/main/java/org/opensearch/encryption/package-info.java b/modules/crypto/src/main/java/org/opensearch/encryption/package-info.java similarity index 100% rename from libs/encryption-sdk/src/main/java/org/opensearch/encryption/package-info.java rename to modules/crypto/src/main/java/org/opensearch/encryption/package-info.java diff --git a/libs/encryption-sdk/src/test/java/org/opensearch/encryption/CryptoManagerFactoryTests.java b/modules/crypto/src/test/java/org/opensearch/encryption/CryptoModulePluginTests.java similarity index 58% rename from libs/encryption-sdk/src/test/java/org/opensearch/encryption/CryptoManagerFactoryTests.java rename to modules/crypto/src/test/java/org/opensearch/encryption/CryptoModulePluginTests.java index fb5c477232bc4..e1e45393a3676 100644 --- a/libs/encryption-sdk/src/test/java/org/opensearch/encryption/CryptoManagerFactoryTests.java +++ b/modules/crypto/src/test/java/org/opensearch/encryption/CryptoModulePluginTests.java @@ -10,9 +10,7 @@ import org.opensearch.common.crypto.CryptoHandler; import org.opensearch.common.crypto.MasterKeyProvider; -import org.opensearch.common.unit.TimeValue; import org.opensearch.test.OpenSearchTestCase; -import org.junit.Before; import java.util.Collections; @@ -21,31 +19,22 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class CryptoManagerFactoryTests extends OpenSearchTestCase { +public class CryptoModulePluginTests extends OpenSearchTestCase { - private CryptoManagerFactory cryptoManagerFactory; + private final CryptoModulePlugin cryptoModulePlugin = new CryptoModulePlugin(); - @Before - public void setup() { - cryptoManagerFactory = new CryptoManagerFactory( - "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384", - TimeValue.timeValueDays(2), - 10 - ); - } - - public void testGetOrCreateCryptoManager() { + public void testGetOrCreateCryptoHandler() { MasterKeyProvider mockKeyProvider = mock(MasterKeyProvider.class); when(mockKeyProvider.getEncryptionContext()).thenReturn(Collections.emptyMap()); - CryptoManager cryptoManager = cryptoManagerFactory.getOrCreateCryptoManager( + CryptoHandler cryptoHandler = cryptoModulePlugin.getOrCreateCryptoHandler( mockKeyProvider, "keyProviderName", "keyProviderType", () -> {} ); - assertNotNull(cryptoManager); + assertNotNull(cryptoHandler); } public void testCreateCryptoProvider() { @@ -53,7 +42,7 @@ public void testCreateCryptoProvider() { MasterKeyProvider mockKeyProvider = mock(MasterKeyProvider.class); when(mockKeyProvider.getEncryptionContext()).thenReturn(Collections.emptyMap()); - CryptoHandler cryptoHandler = cryptoManagerFactory.createCryptoProvider( + CryptoHandler cryptoHandler = cryptoModulePlugin.createCryptoProvider( "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384", mockMaterialsManager, mockKeyProvider @@ -66,7 +55,7 @@ public void testCreateMaterialsManager() { MasterKeyProvider mockKeyProvider = mock(MasterKeyProvider.class); when(mockKeyProvider.getEncryptionContext()).thenReturn(Collections.emptyMap()); - CachingCryptoMaterialsManager materialsManager = cryptoManagerFactory.createMaterialsManager( + CachingCryptoMaterialsManager materialsManager = cryptoModulePlugin.createMaterialsManager( mockKeyProvider, "keyProviderName", "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384" @@ -74,19 +63,4 @@ public void testCreateMaterialsManager() { assertNotNull(materialsManager); } - - public void testCreateCryptoManager() { - CryptoHandler mockCryptoHandler = mock(CryptoHandler.class); - CryptoManager cryptoManager = cryptoManagerFactory.createCryptoManager( - mockCryptoHandler, - "keyProviderName", - "keyProviderType", - null - ); - assertNotNull(cryptoManager); - } - - public void testUnsupportedAlgorithm() { - expectThrows(IllegalArgumentException.class, () -> new CryptoManagerFactory("Unsupported_algo", TimeValue.timeValueDays(2), 10)); - } } diff --git a/libs/encryption-sdk/src/test/java/org/opensearch/encryption/MockKeyProvider.java b/modules/crypto/src/test/java/org/opensearch/encryption/MockKeyProvider.java similarity index 100% rename from libs/encryption-sdk/src/test/java/org/opensearch/encryption/MockKeyProvider.java rename to modules/crypto/src/test/java/org/opensearch/encryption/MockKeyProvider.java diff --git a/libs/encryption-sdk/src/test/java/org/opensearch/encryption/NoOpCryptoHandlerTests.java b/modules/crypto/src/test/java/org/opensearch/encryption/NoOpCryptoHandlerTests.java similarity index 100% rename from libs/encryption-sdk/src/test/java/org/opensearch/encryption/NoOpCryptoHandlerTests.java rename to modules/crypto/src/test/java/org/opensearch/encryption/NoOpCryptoHandlerTests.java diff --git a/libs/encryption-sdk/src/test/java/org/opensearch/encryption/TrimmingStreamTests.java b/modules/crypto/src/test/java/org/opensearch/encryption/TrimmingStreamTests.java similarity index 100% rename from libs/encryption-sdk/src/test/java/org/opensearch/encryption/TrimmingStreamTests.java rename to modules/crypto/src/test/java/org/opensearch/encryption/TrimmingStreamTests.java diff --git a/libs/encryption-sdk/src/test/resources/encrypted_key b/modules/crypto/src/test/resources/encrypted_key similarity index 100% rename from libs/encryption-sdk/src/test/resources/encrypted_key rename to modules/crypto/src/test/resources/encrypted_key diff --git a/libs/encryption-sdk/src/test/resources/raw_content_for_crypto_test b/modules/crypto/src/test/resources/raw_content_for_crypto_test similarity index 100% rename from libs/encryption-sdk/src/test/resources/raw_content_for_crypto_test rename to modules/crypto/src/test/resources/raw_content_for_crypto_test diff --git a/libs/encryption-sdk/src/test/resources/raw_key b/modules/crypto/src/test/resources/raw_key similarity index 100% rename from libs/encryption-sdk/src/test/resources/raw_key rename to modules/crypto/src/test/resources/raw_key diff --git a/plugins/crypto-kms/build.gradle b/plugins/crypto-kms/build.gradle index fa76118a43d92..139444babd958 100644 --- a/plugins/crypto-kms/build.gradle +++ b/plugins/crypto-kms/build.gradle @@ -26,8 +26,6 @@ ext { } dependencies { - api project(':libs:opensearch-encryption-sdk') - api "software.amazon.awssdk:sdk-core:${versions.aws}" api "software.amazon.awssdk:aws-core:${versions.aws}" api "software.amazon.awssdk:utils:${versions.aws}" @@ -56,6 +54,10 @@ dependencies { api "org.reactivestreams:reactive-streams:${versions.reactivestreams}" } +testClusters.all { + module ':modules:crypto' +} + tasks.named("dependencyLicenses").configure { mapping from: /jackson-.*/, to: 'jackson' mapping from: /jaxb-.*/, to: 'jaxb' diff --git a/server/build.gradle b/server/build.gradle index af56032897ee1..f6db3d53a0dcc 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -106,7 +106,6 @@ dependencies { api project(':libs:opensearch-x-content') api project(":libs:opensearch-geo") api project(":libs:opensearch-telemetry") - api project(":libs:opensearch-encryption-sdk") compileOnly project(':libs:opensearch-plugin-classloader') diff --git a/server/src/main/java/org/opensearch/common/blobstore/EncryptedBlobStore.java b/server/src/main/java/org/opensearch/common/blobstore/EncryptedBlobStore.java index 5365b5a9d8bdf..4d2d69e473438 100644 --- a/server/src/main/java/org/opensearch/common/blobstore/EncryptedBlobStore.java +++ b/server/src/main/java/org/opensearch/common/blobstore/EncryptedBlobStore.java @@ -9,9 +9,9 @@ package org.opensearch.common.blobstore; import org.opensearch.cluster.metadata.CryptoMetadata; -import org.opensearch.crypto.CryptoManagerRegistry; +import org.opensearch.common.crypto.CryptoHandler; +import org.opensearch.crypto.CryptoHandlerRegistry; import org.opensearch.crypto.CryptoRegistryException; -import org.opensearch.encryption.CryptoManager; import java.io.IOException; import java.util.Map; @@ -25,7 +25,7 @@ public class EncryptedBlobStore implements BlobStore { private final BlobStore blobStore; - private final CryptoManager cryptoManager; + private final CryptoHandler cryptoHandler; /** * Constructs an EncryptedBlobStore that wraps the provided BlobStore with encryption capabilities based on the @@ -36,17 +36,16 @@ public class EncryptedBlobStore implements BlobStore { * @throws CryptoRegistryException If the CryptoManager is not found during encrypted BlobStore creation. */ public EncryptedBlobStore(BlobStore blobStore, CryptoMetadata cryptoMetadata) { - CryptoManagerRegistry cryptoManagerRegistry = CryptoManagerRegistry.getInstance(); - assert cryptoManagerRegistry != null : "CryptoManagerRegistry is not initialized"; - this.cryptoManager = cryptoManagerRegistry.fetchCryptoManager(cryptoMetadata); - if (cryptoManager == null) { + CryptoHandlerRegistry cryptoHandlerRegistry = CryptoHandlerRegistry.getInstance(); + assert cryptoHandlerRegistry != null : "CryptoManagerRegistry is not initialized"; + this.cryptoHandler = cryptoHandlerRegistry.fetchCryptoHandler(cryptoMetadata); + if (cryptoHandler == null) { throw new CryptoRegistryException( cryptoMetadata.keyProviderName(), cryptoMetadata.keyProviderType(), "Crypto manager not found during encrypted blob store creation." ); } - this.cryptoManager.incRef(); this.blobStore = blobStore; } @@ -61,12 +60,9 @@ public EncryptedBlobStore(BlobStore blobStore, CryptoMetadata cryptoMetadata) { public BlobContainer blobContainer(BlobPath path) { BlobContainer blobContainer = blobStore.blobContainer(path); if (blobContainer instanceof AsyncMultiStreamBlobContainer) { - return new AsyncMultiStreamEncryptedBlobContainer<>( - (AsyncMultiStreamBlobContainer) blobContainer, - cryptoManager.getCryptoProvider() - ); + return new AsyncMultiStreamEncryptedBlobContainer<>((AsyncMultiStreamBlobContainer) blobContainer, cryptoHandler); } - return new EncryptedBlobContainer<>(blobContainer, cryptoManager.getCryptoProvider()); + return new EncryptedBlobContainer<>(blobContainer, cryptoHandler); } /** @@ -87,7 +83,7 @@ public Map stats() { */ @Override public void close() throws IOException { - cryptoManager.decRef(); + cryptoHandler.close(); blobStore.close(); } diff --git a/server/src/main/java/org/opensearch/crypto/CryptoManagerRegistry.java b/server/src/main/java/org/opensearch/crypto/CryptoHandlerRegistry.java similarity index 60% rename from server/src/main/java/org/opensearch/crypto/CryptoManagerRegistry.java rename to server/src/main/java/org/opensearch/crypto/CryptoHandlerRegistry.java index c6a8b56a8d8c8..9eaadbe67ca02 100644 --- a/server/src/main/java/org/opensearch/crypto/CryptoManagerRegistry.java +++ b/server/src/main/java/org/opensearch/crypto/CryptoHandlerRegistry.java @@ -13,12 +13,11 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.opensearch.cluster.metadata.CryptoMetadata; import org.opensearch.common.SetOnce; +import org.opensearch.common.crypto.CryptoHandler; import org.opensearch.common.crypto.MasterKeyProvider; import org.opensearch.common.settings.Settings; -import org.opensearch.common.unit.TimeValue; -import org.opensearch.encryption.CryptoManager; -import org.opensearch.encryption.CryptoManagerFactory; import org.opensearch.plugins.CryptoKeyProviderPlugin; +import org.opensearch.plugins.CryptoPlugin; import java.util.HashMap; import java.util.List; @@ -27,19 +26,19 @@ /** * During node bootstrap, installed key provider extensions responsible for generating data keys are loaded. - * Crypto factories against the respective extensions are cached. A crypto factory is used to register crypto - * manager against an {@link org.opensearch.common.blobstore.EncryptedBlobStore} + * Crypto factories against the respective KP plugins are cached. A crypto factory is used to register crypto + * handler against an {@link org.opensearch.common.blobstore.EncryptedBlobStore} */ -public class CryptoManagerRegistry { - private static final Logger logger = LogManager.getLogger(CryptoManagerRegistry.class); +public class CryptoHandlerRegistry { + private static final Logger logger = LogManager.getLogger(CryptoHandlerRegistry.class); // Package private for tests SetOnce> registry = new SetOnce<>(); // Package private for tests - SetOnce cryptoManagerFactory = new SetOnce(); - private final Map registeredCryptoManagers = new HashMap<>(); + SetOnce cryptoHandlerPlugin = new SetOnce<>(); + private final Map registeredCryptoHandlers = new HashMap<>(); - private static volatile CryptoManagerRegistry instance; + private static volatile CryptoHandlerRegistry instance; private static final Object lock = new Object(); /** @@ -48,22 +47,37 @@ public class CryptoManagerRegistry { * @param cryptoPlugins The list of installed crypto key provider plugins. * @param settings Crypto settings. */ - protected CryptoManagerRegistry(List cryptoPlugins, Settings settings) { - cryptoManagerFactory.set(new CryptoManagerFactory("ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY", TimeValue.timeValueDays(2), 500)); - registry.set(loadCryptoFactories(cryptoPlugins)); + protected CryptoHandlerRegistry( + List cryptoPlugins, + List cryptoKeyProviderPlugins, + Settings settings + ) { + if (cryptoPlugins == null || cryptoPlugins.size() == 0) { + throw new IllegalStateException("No crypto plugin installation found."); + } + if (cryptoPlugins.size() > 1) { + throw new IllegalStateException("More than 1 implementation of crypto plugin found."); + } + + cryptoHandlerPlugin.set(cryptoPlugins.get(0)); + registry.set(loadCryptoFactories(cryptoKeyProviderPlugins)); } - public static CryptoManagerRegistry getInstance() { + public static CryptoHandlerRegistry getInstance() { return instance; } - public static CryptoManagerRegistry initRegistry(List cryptoPlugins, Settings settings) { - CryptoManagerRegistry curInstance = instance; + public static CryptoHandlerRegistry initRegistry( + List cryptoPlugins, + List cryptoKeyProviderPlugins, + Settings settings + ) { + CryptoHandlerRegistry curInstance = instance; if (curInstance == null) { synchronized (lock) { curInstance = instance; if (curInstance == null) { - instance = curInstance = new CryptoManagerRegistry(cryptoPlugins, settings); + instance = curInstance = new CryptoHandlerRegistry(cryptoPlugins, cryptoKeyProviderPlugins, settings); } } } @@ -71,23 +85,23 @@ public static CryptoManagerRegistry initRegistry(List c } // For tests - protected Map loadCryptoFactories(List cryptoPlugins) { + protected Map loadCryptoFactories(List cryptoKPPlugins) { Map cryptoFactories = new HashMap<>(); - for (CryptoKeyProviderPlugin cryptoPlugin : cryptoPlugins) { - if (cryptoFactories.containsKey(cryptoPlugin.type())) { - throw new IllegalArgumentException("Crypto plugin key provider type [" + cryptoPlugin.type() + "] is already registered"); + for (CryptoKeyProviderPlugin cryptoKPPlugin : cryptoKPPlugins) { + if (cryptoFactories.containsKey(cryptoKPPlugin.type())) { + throw new IllegalArgumentException("Crypto plugin key provider type [" + cryptoKPPlugin.type() + "] is already registered"); } - cryptoFactories.put(cryptoPlugin.type(), cryptoPlugin); + cryptoFactories.put(cryptoKPPlugin.type(), cryptoKPPlugin); } return Map.copyOf(cryptoFactories); } /** - * Retrieves the crypto factory associated with the given key provider type (extension id). + * Retrieves the crypto factory associated with the given key provider type . * - * @param keyProviderType The unique extension type for which the factory is to be fetched. - * @return The crypto factory used to create {@link CryptoManager} + * @param keyProviderType The unique provider type for which the factory is to be fetched. + * @return The crypto factory used to create {@link CryptoHandler} * instances in a {@link org.opensearch.common.blobstore.EncryptedBlobStore}. * @throws IllegalStateException If the crypto registry is not yet loaded. */ @@ -106,26 +120,26 @@ public CryptoKeyProviderPlugin getCryptoKeyProviderPlugin(String keyProviderType * @return The crypto manager for performing encrypt/decrypt operations. * @throws CryptoRegistryException If the key provider is not installed or there is an error during crypto manager creation. */ - public CryptoManager fetchCryptoManager(CryptoMetadata cryptoMetadata) { - CryptoManager cryptoManager = registeredCryptoManagers.get(cryptoMetadata); - if (cryptoManager == null) { - synchronized (registeredCryptoManagers) { - cryptoManager = registeredCryptoManagers.get(cryptoMetadata); - if (cryptoManager == null) { + public CryptoHandler fetchCryptoHandler(CryptoMetadata cryptoMetadata) { + CryptoHandler cryptoHandler = registeredCryptoHandlers.get(cryptoMetadata); + if (cryptoHandler == null) { + synchronized (registeredCryptoHandlers) { + cryptoHandler = registeredCryptoHandlers.get(cryptoMetadata); + if (cryptoHandler == null) { Runnable onClose = () -> { - synchronized (registeredCryptoManagers) { - registeredCryptoManagers.remove(cryptoMetadata); + synchronized (registeredCryptoHandlers) { + registeredCryptoHandlers.remove(cryptoMetadata); } }; - cryptoManager = createCryptoManager(cryptoMetadata, onClose); - registeredCryptoManagers.put(cryptoMetadata, cryptoManager); + cryptoHandler = createCryptoHandler(cryptoMetadata, onClose); + registeredCryptoHandlers.put(cryptoMetadata, cryptoHandler); } } } - return cryptoManager; + return cryptoHandler; } - private CryptoManager createCryptoManager(CryptoMetadata cryptoMetadata, Runnable onClose) { + private CryptoHandler createCryptoHandler(CryptoMetadata cryptoMetadata, Runnable onClose) { logger.debug("creating crypto client [{}][{}]", cryptoMetadata.keyProviderType(), cryptoMetadata.keyProviderName()); CryptoKeyProviderPlugin keyProviderPlugin = getCryptoKeyProviderPlugin(cryptoMetadata.keyProviderType()); if (keyProviderPlugin == null) { @@ -134,8 +148,8 @@ private CryptoManager createCryptoManager(CryptoMetadata cryptoMetadata, Runnabl try { MasterKeyProvider masterKeyProvider = keyProviderPlugin.createKeyProvider(cryptoMetadata); - return Objects.requireNonNull(cryptoManagerFactory.get()) - .getOrCreateCryptoManager(masterKeyProvider, cryptoMetadata.keyProviderName(), cryptoMetadata.keyProviderType(), onClose); + return Objects.requireNonNull(cryptoHandlerPlugin.get()) + .getOrCreateCryptoHandler(masterKeyProvider, cryptoMetadata.keyProviderName(), cryptoMetadata.keyProviderType(), onClose); } catch (Exception e) { logger.warn( diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index fdf8b616ccb6c..67b39e8f29d9b 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -115,7 +115,7 @@ import org.opensearch.core.indices.breaker.CircuitBreakerService; import org.opensearch.core.indices.breaker.NoneCircuitBreakerService; import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.crypto.CryptoManagerRegistry; +import org.opensearch.crypto.CryptoHandlerRegistry; import org.opensearch.discovery.Discovery; import org.opensearch.discovery.DiscoveryModule; import org.opensearch.env.Environment; @@ -174,6 +174,7 @@ import org.opensearch.plugins.CircuitBreakerPlugin; import org.opensearch.plugins.ClusterPlugin; import org.opensearch.plugins.CryptoKeyProviderPlugin; +import org.opensearch.plugins.CryptoPlugin; import org.opensearch.plugins.DiscoveryPlugin; import org.opensearch.plugins.EnginePlugin; import org.opensearch.plugins.ExtensionAwarePlugin; @@ -935,7 +936,11 @@ protected Node( xContentRegistry, recoverySettings ); - CryptoManagerRegistry.initRegistry(pluginsService.filterPlugins(CryptoKeyProviderPlugin.class), settings); + CryptoHandlerRegistry.initRegistry( + pluginsService.filterPlugins(CryptoPlugin.class), + pluginsService.filterPlugins(CryptoKeyProviderPlugin.class), + settings + ); RepositoriesService repositoryService = repositoriesModule.getRepositoryService(); repositoriesServiceReference.set(repositoryService); SnapshotsService snapshotsService = new SnapshotsService( diff --git a/server/src/main/java/org/opensearch/plugins/CryptoPlugin.java b/server/src/main/java/org/opensearch/plugins/CryptoPlugin.java new file mode 100644 index 0000000000000..ad348d07e23d3 --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/CryptoPlugin.java @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.common.crypto.CryptoHandler; +import org.opensearch.common.crypto.MasterKeyProvider; + +/** + * Crypto plugin to provide encryption and decryption support. + * @opensearch.api + */ +@ExperimentalApi +public interface CryptoPlugin { + + /** + * To create a crypto handler for handling encryption and decryption ops. + * @param keyProvider key provider instance to provide keys used in encrypting data. + * @param keyProviderName Name of key provider to distinguish between multiple instances created with different + * configurations of same keyProviderType. + * @param keyProviderType Unique type of key provider to distinguish between different key provider implementations. + * @param onClose Closes key provider or other clean up operations on close. + * @return crypto handler instance. + */ + CryptoHandler getOrCreateCryptoHandler( + MasterKeyProvider keyProvider, + String keyProviderName, + String keyProviderType, + Runnable onClose + ); +} diff --git a/server/src/test/java/org/opensearch/crypto/CryptoManagerRegistryTests.java b/server/src/test/java/org/opensearch/crypto/CryptoHandlerRegistryTests.java similarity index 76% rename from server/src/test/java/org/opensearch/crypto/CryptoManagerRegistryTests.java rename to server/src/test/java/org/opensearch/crypto/CryptoHandlerRegistryTests.java index f6c8f71bd653c..55347c2452c09 100644 --- a/server/src/test/java/org/opensearch/crypto/CryptoManagerRegistryTests.java +++ b/server/src/test/java/org/opensearch/crypto/CryptoHandlerRegistryTests.java @@ -9,10 +9,11 @@ package org.opensearch.crypto; import org.opensearch.cluster.metadata.CryptoMetadata; +import org.opensearch.common.crypto.CryptoHandler; import org.opensearch.common.crypto.MasterKeyProvider; import org.opensearch.common.settings.Settings; -import org.opensearch.encryption.CryptoManager; import org.opensearch.plugins.CryptoKeyProviderPlugin; +import org.opensearch.plugins.CryptoPlugin; import org.opensearch.test.OpenSearchTestCase; import org.junit.Before; @@ -24,9 +25,9 @@ import org.mockito.ArgumentMatchers; import org.mockito.Mockito; -public class CryptoManagerRegistryTests extends OpenSearchTestCase { +public class CryptoHandlerRegistryTests extends OpenSearchTestCase { - private TestCryptoManagerRegistry cryptoManagerRegistry; + private TestCryptoHandlerRegistry cryptoManagerRegistry; private String pluginTypeWithCreationFailure; private CryptoKeyProviderPlugin cryptoPlugin1; private CryptoKeyProviderPlugin cryptoPlugin2; @@ -57,18 +58,18 @@ public void setup() { .thenThrow(new RuntimeException("Injected failure")); cryptoPlugins.add(cryptoPluginCreationFailure); - cryptoManagerRegistry = new TestCryptoManagerRegistry(cryptoPlugins, Settings.EMPTY); + cryptoManagerRegistry = new TestCryptoHandlerRegistry(cryptoPlugins, Settings.EMPTY); } - static class TestCryptoManagerRegistry extends CryptoManagerRegistry { + static class TestCryptoHandlerRegistry extends CryptoHandlerRegistry { - protected TestCryptoManagerRegistry(List cryptoPlugins, Settings settings) { - super(cryptoPlugins, settings); + protected TestCryptoHandlerRegistry(List cryptoPlugins, Settings settings) { + super(List.of(Mockito.mock(CryptoPlugin.class)), cryptoPlugins, settings); } @Override - public Map loadCryptoFactories(List cryptoPlugins) { - return super.loadCryptoFactories(cryptoPlugins); + public Map loadCryptoFactories(List cryptoKPPlugins) { + return super.loadCryptoFactories(cryptoKPPlugins); } } @@ -115,44 +116,39 @@ public void testCryptoManagerMissing() { String pluginName = UUID.randomUUID().toString(); String pluginType = UUID.randomUUID().toString(); CryptoMetadata cryptoMetadata = new CryptoMetadata(pluginName, pluginType, Settings.EMPTY); - expectThrows(CryptoRegistryException.class, () -> cryptoManagerRegistry.fetchCryptoManager(cryptoMetadata)); + expectThrows(CryptoRegistryException.class, () -> cryptoManagerRegistry.fetchCryptoHandler(cryptoMetadata)); } public void testCryptoManagerCreationFailure() { String pluginName = UUID.randomUUID().toString(); CryptoMetadata cryptoMetadata = new CryptoMetadata(pluginName, pluginTypeWithCreationFailure, Settings.EMPTY); - expectThrows(CryptoRegistryException.class, () -> cryptoManagerRegistry.fetchCryptoManager(cryptoMetadata)); + expectThrows(CryptoRegistryException.class, () -> cryptoManagerRegistry.fetchCryptoHandler(cryptoMetadata)); } public void testCryptoManagerCreationSuccess() { String pluginName1 = UUID.randomUUID().toString(); CryptoMetadata cryptoMetadata = new CryptoMetadata(pluginName1, cryptoPlugin1.type(), Settings.EMPTY); - CryptoManager createdCryptoManager1 = cryptoManagerRegistry.fetchCryptoManager(cryptoMetadata); - assertNotNull(createdCryptoManager1); - assertEquals(cryptoPlugin1.type(), createdCryptoManager1.type()); - assertEquals(cryptoMetadata.keyProviderName(), createdCryptoManager1.name()); - assertEquals(cryptoMetadata.keyProviderType(), createdCryptoManager1.type()); + CryptoHandler cryptoHandler = cryptoManagerRegistry.fetchCryptoHandler(cryptoMetadata); + assertNotNull(cryptoHandler); String pluginName2 = UUID.randomUUID().toString(); - CryptoManager createdCryptoManager2 = cryptoManagerRegistry.fetchCryptoManager( + CryptoHandler cryptoHandler2 = cryptoManagerRegistry.fetchCryptoHandler( new CryptoMetadata(pluginName2, cryptoPlugin2.type(), Settings.EMPTY) ); - assertNotNull(createdCryptoManager2); - assertEquals(pluginName2, createdCryptoManager2.name()); - assertEquals(cryptoPlugin2.type(), createdCryptoManager2.type()); - CryptoManager createdCryptoManager3 = cryptoManagerRegistry.fetchCryptoManager( + assertNotNull(cryptoHandler2); + CryptoHandler cryptoHandler3 = cryptoManagerRegistry.fetchCryptoHandler( new CryptoMetadata(pluginName1, cryptoPlugin1.type(), Settings.EMPTY) ); - assertNotNull(createdCryptoManager3); - assertEquals(createdCryptoManager1, createdCryptoManager3); + assertNotNull(cryptoHandler3); + assertEquals(cryptoHandler, cryptoHandler3); - CryptoManager createdCryptoMgrNewType = cryptoManagerRegistry.fetchCryptoManager( + CryptoHandler cryptoHandlerNewType = cryptoManagerRegistry.fetchCryptoHandler( new CryptoMetadata(pluginName1, cryptoPlugin2.type(), Settings.EMPTY) ); - assertNotNull(createdCryptoMgrNewType); - assertNotEquals(createdCryptoManager1, createdCryptoMgrNewType); - assertNotEquals(createdCryptoManager2, createdCryptoMgrNewType); - assertNotEquals(createdCryptoManager3, createdCryptoMgrNewType); + assertNotNull(cryptoHandlerNewType); + assertNotEquals(cryptoHandler, cryptoHandlerNewType); + assertNotEquals(cryptoHandler2, cryptoHandlerNewType); + assertNotEquals(cryptoHandler3, cryptoHandlerNewType); } } diff --git a/server/src/test/java/org/opensearch/repositories/RepositoriesServiceTests.java b/server/src/test/java/org/opensearch/repositories/RepositoriesServiceTests.java index 1ab48b30af2f9..c23bdeb4a7099 100644 --- a/server/src/test/java/org/opensearch/repositories/RepositoriesServiceTests.java +++ b/server/src/test/java/org/opensearch/repositories/RepositoriesServiceTests.java @@ -57,6 +57,7 @@ import org.opensearch.common.crypto.CryptoHandler; import org.opensearch.common.crypto.DecryptedRangedStreamProvider; import org.opensearch.common.crypto.EncryptedHeaderContentSupplier; +import org.opensearch.common.crypto.MasterKeyProvider; import org.opensearch.common.io.InputStreamContainer; import org.opensearch.common.lifecycle.Lifecycle; import org.opensearch.common.lifecycle.LifecycleListener; @@ -65,7 +66,6 @@ import org.opensearch.core.common.Strings; import org.opensearch.core.index.shard.ShardId; import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.encryption.CryptoManager; import org.opensearch.index.mapper.MapperService; import org.opensearch.index.snapshots.IndexShardSnapshotStatus; import org.opensearch.index.snapshots.blobstore.RemoteStoreShardShallowCopySnapshot; @@ -73,6 +73,7 @@ import org.opensearch.index.store.lockmanager.RemoteStoreLockManagerFactory; import org.opensearch.indices.recovery.RecoverySettings; import org.opensearch.indices.recovery.RecoveryState; +import org.opensearch.plugins.CryptoPlugin; import org.opensearch.repositories.blobstore.MeteredBlobStoreRepository; import org.opensearch.snapshots.SnapshotId; import org.opensearch.snapshots.SnapshotInfo; @@ -89,7 +90,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; @@ -102,6 +102,8 @@ public class RepositoriesServiceTests extends OpenSearchTestCase { private RepositoriesService repositoriesService; + private final String kpTypeA = "kp-type-a"; + private final String kpTypeB = "kp-type-b"; @Override public void setUp() throws Exception { @@ -229,28 +231,28 @@ public void testWithSameKeyProviderNames() { "repoName", MeteredRepositoryTypeA.TYPE, keyProviderName, - TestCryptoManagerTypeA.TYPE + kpTypeA ); repositoriesService.applyClusterState(new ClusterChangedEvent("new repo", clusterStateWithRepoTypeA, emptyState())); assertThat(repositoriesService.repositoriesStats().size(), equalTo(1)); MeteredRepositoryTypeA repository = (MeteredRepositoryTypeA) repositoriesService.repository("repoName"); assertNotNull(repository); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); ClusterState clusterStateWithRepoTypeB = createClusterStateWithKeyProvider( "repoName", MeteredRepositoryTypeB.TYPE, keyProviderName, - TestCryptoManagerTypeB.TYPE + kpTypeA ); repositoriesService.applyClusterState(new ClusterChangedEvent("new repo", clusterStateWithRepoTypeB, emptyState())); assertThat(repositoriesService.repositoriesStats().size(), equalTo(2)); MeteredRepositoryTypeB repositoryB = (MeteredRepositoryTypeB) repositoriesService.repository("repoName"); assertNotNull(repositoryB); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); } public void testCryptoManagersUnchangedWithSameCryptoMetadata() { @@ -259,21 +261,21 @@ public void testCryptoManagersUnchangedWithSameCryptoMetadata() { "repoName", MeteredRepositoryTypeA.TYPE, keyProviderName, - TestCryptoManagerTypeA.TYPE + kpTypeA ); repositoriesService.applyClusterState(new ClusterChangedEvent("new repo", clusterStateWithRepoTypeA, emptyState())); assertThat(repositoriesService.repositoriesStats().size(), equalTo(1)); MeteredRepositoryTypeA repository = (MeteredRepositoryTypeA) repositoriesService.repository("repoName"); assertNotNull(repository); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); repositoriesService.applyClusterState(new ClusterChangedEvent("new repo", clusterStateWithRepoTypeA, emptyState())); assertThat(repositoriesService.repositoriesStats().size(), equalTo(1)); repository = (MeteredRepositoryTypeA) repositoriesService.repository("repoName"); assertNotNull(repository); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); } public void testRepositoryUpdateWithDifferentCryptoMetadata() { @@ -283,7 +285,7 @@ public void testRepositoryUpdateWithDifferentCryptoMetadata() { "repoName", MeteredRepositoryTypeA.TYPE, keyProviderName, - TestCryptoManagerTypeA.TYPE + kpTypeA ); ClusterService clusterService = mock(ClusterService.class); @@ -303,13 +305,13 @@ public void testRepositoryUpdateWithDifferentCryptoMetadata() { assertThat(repositoriesService.repositoriesStats().size(), equalTo(1)); MeteredRepositoryTypeA repository = (MeteredRepositoryTypeA) repositoriesService.repository("repoName"); assertNotNull(repository); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); expectThrows(IllegalArgumentException.class, () -> repositoriesService.registerRepository(request, null)); CryptoSettings cryptoSettings = new CryptoSettings(keyProviderName); - cryptoSettings.keyProviderType(TestCryptoManagerTypeA.TYPE); + cryptoSettings.keyProviderType(kpTypeA); cryptoSettings.settings(Settings.builder().put("key-1", "val-1")); request.cryptoSettings(cryptoSettings); expectThrows(IllegalArgumentException.class, () -> repositoriesService.registerRepository(request, null)); @@ -320,7 +322,7 @@ public void testRepositoryUpdateWithDifferentCryptoMetadata() { cryptoSettings.keyProviderName(keyProviderName); - cryptoSettings.keyProviderType(TestCryptoManagerTypeA.TYPE); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); repositoriesService.registerRepository(request, null); } @@ -332,7 +334,7 @@ public void testCryptoManagerClusterStateChanges() { String keyProviderName = "kp-name-1"; String repoName = "repoName"; - String keyProviderType = TestCryptoManagerTypeA.TYPE; + String keyProviderType = kpTypeA; Settings.Builder settings = Settings.builder(); PutRepositoryRequest request = createPutRepositoryEncryptedRequest( repoName, @@ -353,12 +355,12 @@ public void testCryptoManagerClusterStateChanges() { ); repositoriesService.registerRepository(request, null); MeteredRepositoryTypeA repository = (MeteredRepositoryTypeA) repositoriesService.repository(repoName); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); assertTrue(verified.get()); // No change - keyProviderType = TestCryptoManagerTypeA.TYPE; + keyProviderType = kpTypeA; settings = Settings.builder(); request = createPutRepositoryEncryptedRequest(repoName, MeteredRepositoryTypeA.TYPE, keyProviderName, settings, keyProviderType); verified.set(false); @@ -374,13 +376,13 @@ public void testCryptoManagerClusterStateChanges() { repositoriesService.registerRepository(request, null); repository = (MeteredRepositoryTypeA) repositoriesService.repository(repoName); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); assertTrue(verified.get()); // Same crypto client in new repo repoName = "repoName-2"; - keyProviderType = TestCryptoManagerTypeA.TYPE; + keyProviderType = kpTypeA; settings = Settings.builder(); request = createPutRepositoryEncryptedRequest(repoName, MeteredRepositoryTypeA.TYPE, keyProviderName, settings, keyProviderType); verified.set(false); @@ -395,13 +397,13 @@ public void testCryptoManagerClusterStateChanges() { ); repositoriesService.registerRepository(request, null); repository = (MeteredRepositoryTypeA) repositoriesService.repository(repoName); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeA); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeA, repository.cryptoHandler.kpType); assertTrue(verified.get()); // Different crypto client in new repo repoName = "repoName-3"; - keyProviderType = TestCryptoManagerTypeB.TYPE; + keyProviderType = kpTypeB; settings = Settings.builder(); request = createPutRepositoryEncryptedRequest(repoName, MeteredRepositoryTypeA.TYPE, keyProviderName, settings, keyProviderType); verified.set(false); @@ -416,8 +418,8 @@ public void testCryptoManagerClusterStateChanges() { ); repositoriesService.registerRepository(request, null); repository = (MeteredRepositoryTypeA) repositoriesService.repository(repoName); - assertNotNull(repository.cryptoManager); - assertTrue(repository.cryptoManager instanceof TestCryptoManagerTypeB); + assertNotNull(repository.cryptoHandler); + assertEquals(kpTypeB, repository.cryptoHandler.kpType); assertTrue(verified.get()); } @@ -530,6 +532,13 @@ private void assertThrowsOnRegister(String repoName) { } private static class TestCryptoProvider implements CryptoHandler { + final String kpName; + final String kpType; + + public TestCryptoProvider(String kpName, String kpType) { + this.kpName = kpName; + this.kpType = kpType; + } @Override public Object initEncryptionMetadata() { @@ -584,75 +593,27 @@ public DecryptedRangedStreamProvider createDecryptingStreamOfRange( public long estimateDecryptedLength(Object cryptoContext, long contentLength) { return 0; } - } - - private static abstract class TestCryptoManager implements CryptoManager { - private final String name; - private final AtomicInteger ref; - - private final CryptoHandler cryptoProvider; - - public TestCryptoManager(Settings settings, String keyProviderName) { - this.name = keyProviderName; - this.ref = new AtomicInteger(1); - this.cryptoProvider = new TestCryptoProvider(); - } @Override - public void incRef() { - ref.incrementAndGet(); - } + public void close() throws IOException { - @Override - public boolean tryIncRef() { - ref.incrementAndGet(); - return true; - } - - @Override - public boolean decRef() { - ref.decrementAndGet(); - return true; } - - public int getReferenceCount() { - return ref.get(); - } - - @Override - public String name() { - return name; - } - - public CryptoHandler getCryptoProvider() { - return cryptoProvider; - } - } - - private static class TestCryptoManagerTypeA extends TestCryptoManager { - public static final String TYPE = "type-A"; - - public TestCryptoManagerTypeA(Settings settings, String keyProviderName) { - super(settings, keyProviderName); - } - - @Override - public String type() { - return TYPE; - } - } - private static class TestCryptoManagerTypeB extends TestCryptoManager { - public static final String TYPE = "type-B"; + private static abstract class TestCryptoHandler implements CryptoPlugin { + private final Settings settings; - public TestCryptoManagerTypeB(Settings settings, String keyProviderName) { - super(settings, keyProviderName); + public TestCryptoHandler(Settings settings) { + this.settings = settings; } - @Override - public String type() { - return TYPE; + public CryptoHandler getOrCreateCryptoHandler( + MasterKeyProvider keyProvider, + String keyProviderName, + String keyProviderType, + Runnable onClose + ) { + return new TestCryptoProvider(keyProviderName, keyProviderType); } } @@ -880,7 +841,7 @@ public void close() { private static class MeteredRepositoryTypeA extends MeteredBlobStoreRepository { private static final String TYPE = "type-a"; private static final RepositoryStats STATS = new RepositoryStats(Map.of("GET", 10L)); - private final CryptoManager cryptoManager; + private final TestCryptoProvider cryptoHandler; private MeteredRepositoryTypeA(RepositoryMetadata metadata, ClusterService clusterService) { super( @@ -893,18 +854,12 @@ private MeteredRepositoryTypeA(RepositoryMetadata metadata, ClusterService clust ); if (metadata.cryptoMetadata() != null) { - switch (metadata.cryptoMetadata().keyProviderType()) { - case TestCryptoManagerTypeA.TYPE: - cryptoManager = new TestCryptoManagerTypeA(null, metadata.cryptoMetadata().keyProviderName()); - break; - case TestCryptoManagerTypeB.TYPE: - cryptoManager = new TestCryptoManagerTypeB(null, metadata.cryptoMetadata().keyProviderName()); - break; - default: - cryptoManager = null; - } + cryptoHandler = new TestCryptoProvider( + metadata.cryptoMetadata().keyProviderName(), + metadata.cryptoMetadata().keyProviderType() + ); } else { - cryptoManager = null; + cryptoHandler = null; } } @@ -927,7 +882,7 @@ public BlobPath basePath() { private static class MeteredRepositoryTypeB extends MeteredBlobStoreRepository { private static final String TYPE = "type-b"; private static final RepositoryStats STATS = new RepositoryStats(Map.of("LIST", 20L)); - private final CryptoManager cryptoManager; + private final TestCryptoProvider cryptoHandler; private MeteredRepositoryTypeB(RepositoryMetadata metadata, ClusterService clusterService) { super( @@ -940,18 +895,12 @@ private MeteredRepositoryTypeB(RepositoryMetadata metadata, ClusterService clust ); if (metadata.cryptoMetadata() != null) { - switch (metadata.cryptoMetadata().keyProviderType()) { - case TestCryptoManagerTypeA.TYPE: - cryptoManager = new TestCryptoManagerTypeA(null, metadata.cryptoMetadata().keyProviderName()); - break; - case TestCryptoManagerTypeB.TYPE: - cryptoManager = new TestCryptoManagerTypeB(null, metadata.cryptoMetadata().keyProviderName()); - break; - default: - cryptoManager = null; - } + cryptoHandler = new TestCryptoProvider( + metadata.cryptoMetadata().keyProviderName(), + metadata.cryptoMetadata().keyProviderType() + ); } else { - cryptoManager = null; + cryptoHandler = null; } }