Refactoring/opensearch security setup (#16087)

* Start datanode jersey only after ssl configuration resolved, listen to change events

* Adapted DatanodeSecuritySetupIT to work with https version of the datanode interface

* simplify hostnames in DatanodeSecuritySetupIT

* code cleanup

* added changelog

* code cleanup

* disable security plugin and perf analyzer in matrix tests opensearch

* Fixed datanode jersey service

* Fixed opensearch instance env

* Opensearch security setup refactored

* code cleanup

* removed commented out code from datanodes JerseyService

* add fqdn to the http cert in the DatanodeSecuritySetupIT

* configure truststore only if the security is enabled

* code cleanup

* reintroduced root certificate finder

* adjusted class and methods visibility of RootCertificateFinder
This commit is contained in:
Tomas Dvorak
2023-08-02 14:33:50 +02:00
committed by GitHub
parent d5da3e0eca
commit e39a53ed2d
15 changed files with 315 additions and 442 deletions

View File

@@ -17,6 +17,7 @@
package org.graylog.datanode.configuration;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang3.RandomStringUtils;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
@@ -24,13 +25,16 @@ import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.graylog.datanode.configuration.variants.KeystoreInformation;
import org.graylog.security.certutil.CertConstants;
import org.graylog.security.certutil.keystore.storage.KeystoreContentMover;
import org.graylog.security.certutil.keystore.storage.KeystoreFileStorage;
import org.graylog.security.certutil.keystore.storage.location.KeystoreFileLocation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
@@ -41,7 +45,6 @@ import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@@ -51,33 +54,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
public class TruststoreCreatorTest {
private TruststoreCreator toTest;
@BeforeEach
void setUp() {
toTest = new TruststoreCreator();
}
@Test
void testTrustStoreCreation(@TempDir Path tempDir) throws Exception {
final Path trustStoreFile = tempDir.resolve("truststore.sec");
final char[] truststorePassword = "caramba! caramba!".toCharArray();
toTest.createTruststore(
Map.of(
"root", prepareSimpleCert("CN=ROOT", BigInteger.ONE),
"boot", prepareSimpleCert("CN=BOOT", BigInteger.TWO)
),
truststorePassword,
trustStoreFile);
final KeystoreInformation root = createKeystore(tempDir.resolve("root.p12"), "root","CN=ROOT", BigInteger.ONE);
final KeystoreInformation boot = createKeystore(tempDir.resolve("boot.p12"), "boot","CN=BOOT", BigInteger.TWO);
assertTrue(trustStoreFile.toFile().exists());
final KeystoreInformation truststore = TruststoreCreator.newTruststore()
.addRootCert("root", root, "root")
.addRootCert("boot", boot, "boot")
.persist(tempDir.resolve("truststore.sec"), "caramba! caramba!".toCharArray());
assertTrue(truststore.location().toFile().exists());
KeystoreFileStorage keystoreFileStorage = new KeystoreFileStorage(mock(KeystoreContentMover.class));
final Optional<KeyStore> keyStoreOptional = keystoreFileStorage.readKeyStore(new KeystoreFileLocation(trustStoreFile), truststorePassword);
final Optional<KeyStore> keyStoreOptional = keystoreFileStorage.readKeyStore(new KeystoreFileLocation(truststore.location()), truststore.password());
assertTrue(keyStoreOptional.isPresent());
@@ -102,7 +95,7 @@ public class TruststoreCreatorTest {
assertEquals(cnName, x509Certificate.getIssuerX500Principal().getName());
}
private X509Certificate prepareSimpleCert(final String cnName, final BigInteger serialNumber) throws GeneralSecurityException, OperatorCreationException {
private KeystoreInformation createKeystore(Path path, String alias, final String cnName, final BigInteger serialNumber) throws GeneralSecurityException, OperatorCreationException, IOException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEY_GENERATION_ALGORITHM);
java.security.KeyPair certKeyPair = keyGen.generateKeyPair();
X500Name name = new X500Name(cnName);
@@ -117,8 +110,20 @@ public class TruststoreCreatorTest {
ContentSigner signer = new JcaContentSignerBuilder(SIGNING_ALGORITHM).build(certKeyPair.getPrivate());
X509CertificateHolder certHolder = builder.build(signer);
return new JcaX509CertificateConverter().getCertificate(certHolder);
final X509Certificate signedCert = new JcaX509CertificateConverter().getCertificate(certHolder);
KeyStore trustStore = KeyStore.getInstance(CertConstants.PKCS12);
trustStore.load(null, null);
final char[] password = RandomStringUtils.randomAlphabetic(256).toCharArray();
trustStore.setKeyEntry(alias, certKeyPair.getPrivate(), password, new Certificate[]{signedCert});
try (final FileOutputStream fileOutputStream = new FileOutputStream(path.toFile())) {
trustStore.store(fileOutputStream, password);
}
return new KeystoreInformation(path, password);
}
}

View File

@@ -41,7 +41,9 @@ import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -65,7 +67,7 @@ public class DatanodeSecuritySetupIT {
private Path httpCert;
@BeforeEach
void setUp() {
void setUp() throws UnknownHostException {
String containerHostname = "graylog-datanode-host-" + RandomStringUtils.random(8, "0123456789abcdef");
// first generate a self-signed CA