mirror of
https://github.com/Graylog2/graylog2-server.git
synced 2026-03-13 09:32:21 +08:00
Data Node: Add reverse lookups for local loopback-addresses as well. (#17022)
* Include local reverse lookups for loopback addresses in CSR. * Add reverse lookups for local loopback-addresses to CSR. * Suppressing forbidden method invocation warning.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.graylog.datanode.bootstrap.preflight;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bouncycastle.operator.OperatorException;
|
||||
import org.graylog.datanode.configuration.DatanodeConfiguration;
|
||||
import org.graylog.security.certutil.CertConstants;
|
||||
@@ -36,6 +37,7 @@ import org.graylog2.cluster.preflight.DataNodeProvisioningConfig;
|
||||
import org.graylog2.cluster.preflight.DataNodeProvisioningService;
|
||||
import org.graylog2.plugin.periodical.Periodical;
|
||||
import org.graylog2.plugin.system.NodeId;
|
||||
import org.graylog2.shared.SuppressForbidden;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -43,8 +45,13 @@ import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Singleton
|
||||
public class DataNodeConfigurationPeriodical extends Periodical {
|
||||
@@ -89,48 +96,92 @@ public class DataNodeConfigurationPeriodical extends Periodical {
|
||||
public void doRun() {
|
||||
LOG.debug("checking if this DataNode is supposed to take configuration steps.");
|
||||
var cfg = dataNodeProvisioningService.getPreflightConfigFor(nodeId.getNodeId());
|
||||
if (cfg == null) {
|
||||
if (cfg.isEmpty()) {
|
||||
// write default config if none exists for this node
|
||||
dataNodeProvisioningService.save(DataNodeProvisioningConfig.builder().nodeId(nodeId.getNodeId()).state(DataNodeProvisioningConfig.State.UNCONFIGURED).build());
|
||||
} else if (DataNodeProvisioningConfig.State.CONFIGURED.equals(cfg.state())) {
|
||||
writeInitialProvisioningConfig();
|
||||
return;
|
||||
}
|
||||
cfg.ifPresent(c -> {
|
||||
final var state = c.state();
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case CONFIGURED -> writeCsr(c);
|
||||
case SIGNED -> readSignedCertificate(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void readSignedCertificate(DataNodeProvisioningConfig cfg) {
|
||||
if (cfg.certificate() == null) {
|
||||
LOG.error("Config entry in signed state, but no certificate data present in Mongo");
|
||||
} else {
|
||||
try {
|
||||
var node = nodeService.byNodeId(nodeId);
|
||||
var csr = csrGenerator.generateCSR(passwordSecret, node.getHostname(), cfg.altNames(), privateKeyEncryptedStorage);
|
||||
csrStorage.writeCsr(csr, nodeId.getNodeId());
|
||||
LOG.info("created CSR for this node");
|
||||
} catch (CSRGenerationException | IOException | NodeNotFoundException | OperatorException ex) {
|
||||
LOG.error("error generating a CSR: " + ex.getMessage(), ex);
|
||||
dataNodeProvisioningService.save(cfg.toBuilder().state(DataNodeProvisioningConfig.State.ERROR).errorMsg(ex.getMessage()).build());
|
||||
}
|
||||
} else if (DataNodeProvisioningConfig.State.SIGNED.equals(cfg.state())) {
|
||||
if (cfg.certificate() == null) {
|
||||
LOG.error("Config entry in signed state, but no certificate data present in Mongo");
|
||||
} else {
|
||||
try {
|
||||
final Optional<CertificateChain> certificateChain = certMongoStorage.readCertChain(nodeId.getNodeId());
|
||||
if (certificateChain.isPresent()) {
|
||||
final char[] secret = passwordSecret;
|
||||
KeyStore nodeKeystore = certificateAndPrivateKeyMerger.merge(
|
||||
certificateChain.get(),
|
||||
privateKeyEncryptedStorage,
|
||||
secret,
|
||||
secret,
|
||||
CertConstants.DATANODE_KEY_ALIAS
|
||||
);
|
||||
final Optional<CertificateChain> certificateChain = certMongoStorage.readCertChain(nodeId.getNodeId());
|
||||
if (certificateChain.isPresent()) {
|
||||
final char[] secret = passwordSecret;
|
||||
KeyStore nodeKeystore = certificateAndPrivateKeyMerger.merge(
|
||||
certificateChain.get(),
|
||||
privateKeyEncryptedStorage,
|
||||
secret,
|
||||
secret,
|
||||
CertConstants.DATANODE_KEY_ALIAS
|
||||
);
|
||||
|
||||
final KeystoreMongoLocation location = new KeystoreMongoLocation(nodeId.getNodeId(), KeystoreMongoCollections.DATA_NODE_KEYSTORE_COLLECTION);
|
||||
keystoreStorage.writeKeyStore(location, nodeKeystore, secret, secret);
|
||||
final KeystoreMongoLocation location = new KeystoreMongoLocation(nodeId.getNodeId(), KeystoreMongoCollections.DATA_NODE_KEYSTORE_COLLECTION);
|
||||
keystoreStorage.writeKeyStore(location, nodeKeystore, secret, secret);
|
||||
|
||||
//should be in one transaction, but we miss transactions...
|
||||
dataNodeProvisioningService.changeState(nodeId.getNodeId(), DataNodeProvisioningConfig.State.STORED);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Config entry in signed state, but wrong certificate data present in Mongo");
|
||||
//should be in one transaction, but we miss transactions...
|
||||
dataNodeProvisioningService.changeState(nodeId.getNodeId(), DataNodeProvisioningConfig.State.STORED);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Config entry in signed state, but wrong certificate data present in Mongo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCsr(DataNodeProvisioningConfig cfg) {
|
||||
try {
|
||||
final var node = nodeService.byNodeId(nodeId);
|
||||
final var altNames = ImmutableList.<String>builder()
|
||||
.addAll(Optional.ofNullable(cfg.altNames()).orElse(Collections.emptyList()))
|
||||
.addAll(determineAltNames())
|
||||
.build();
|
||||
final var csr = csrGenerator.generateCSR(passwordSecret, node.getHostname(), altNames, privateKeyEncryptedStorage);
|
||||
csrStorage.writeCsr(csr, nodeId.getNodeId());
|
||||
LOG.info("created CSR for this node");
|
||||
} catch (CSRGenerationException | IOException | NodeNotFoundException | OperatorException ex) {
|
||||
LOG.error("error generating a CSR: " + ex.getMessage(), ex);
|
||||
dataNodeProvisioningService.save(cfg.asError(ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInitialProvisioningConfig() {
|
||||
dataNodeProvisioningService.save(DataNodeProvisioningConfig.builder()
|
||||
.nodeId(nodeId.getNodeId())
|
||||
.state(DataNodeProvisioningConfig.State.UNCONFIGURED)
|
||||
.build());
|
||||
}
|
||||
|
||||
private Iterable<String> determineAltNames() {
|
||||
return Stream.of("127.0.0.1", "::1")
|
||||
.map(this::reverseLookup)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@SuppressForbidden("Deliberate use of InetAddress#getHostName")
|
||||
private String reverseLookup(String ipAddress) {
|
||||
try {
|
||||
final var inetAddress = InetAddress.getByName(ipAddress);
|
||||
final var reverseLookup = inetAddress.getHostName();
|
||||
return reverseLookup.equals(ipAddress) ? null : reverseLookup;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Logger getLogger() {
|
||||
return LOG;
|
||||
|
||||
Reference in New Issue
Block a user