summaryrefslogtreecommitdiffstats
path: root/node-admin
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@yahooinc.com>2022-11-04 10:37:05 +0100
committerTor Brede Vekterli <vekterli@yahooinc.com>2022-11-04 10:37:05 +0100
commit0da08eab292f4745a3d1620691a8753da0a62984 (patch)
tree911f86519390f029405d5a212c923a7b4eceb220 /node-admin
parent37e61132b52f4d198caf37142023c84051253a7f (diff)
Wire core dump encryption public key ID to core dump handler logic
Diffstat (limited to 'node-admin')
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java34
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/SecretSharedKeySupplier.java17
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java25
3 files changed, 67 insertions, 9 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
index 3a61f8b2619..f4cd35bc5bd 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
@@ -5,12 +5,14 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yahoo.config.provision.DockerImage;
+import com.yahoo.security.KeyId;
import com.yahoo.security.SecretSharedKey;
import com.yahoo.security.SharedKeyGenerator;
import com.yahoo.vespa.flags.BooleanFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.StringFlag;
import com.yahoo.vespa.hosted.node.admin.configserver.cores.CoreDumpMetadata;
import com.yahoo.vespa.hosted.node.admin.configserver.cores.Cores;
import com.yahoo.vespa.hosted.node.admin.configserver.cores.bindings.ReportCoreDumpRequest;
@@ -47,6 +49,7 @@ import java.util.function.Supplier;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import static com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder.nameEndsWith;
import static com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder.nameMatches;
@@ -79,8 +82,9 @@ public class CoredumpHandler {
private final Metrics metrics;
private final Clock clock;
private final Supplier<String> coredumpIdSupplier;
- private final Supplier<SecretSharedKey> secretSharedKeySupplier;
+ private final SecretSharedKeySupplier secretSharedKeySupplier;
private final BooleanFlag reportCoresViaCfgFlag;
+ private final StringFlag coreEncryptionPublicKeyIdFlag;
/**
* @param crashPathInContainer path inside the container where core dump are dumped
@@ -90,14 +94,23 @@ public class CoredumpHandler {
String crashPathInContainer, Path doneCoredumpsPath, Metrics metrics,
FlagSource flagSource) {
this(coreCollector, cores, coredumpReporter, crashPathInContainer, doneCoredumpsPath,
- metrics, Clock.systemUTC(), () -> UUID.randomUUID().toString(), () -> null /*TODO*/,
+ metrics, Clock.systemUTC(), () -> UUID.randomUUID().toString(), (ctx) -> Optional.empty() /*TODO*/,
flagSource);
}
+ // TODO remove redundant constructor once internal callsite has been updated
+ public CoredumpHandler(CoreCollector coreCollector, Cores cores, CoredumpReporter coredumpReporter,
+ String crashPathInContainer, Path doneCoredumpsPath, Metrics metrics,
+ SecretSharedKeySupplier secretSharedKeySupplier, FlagSource flagSource) {
+ this(coreCollector, cores, coredumpReporter, crashPathInContainer, doneCoredumpsPath,
+ metrics, Clock.systemUTC(), () -> UUID.randomUUID().toString(), secretSharedKeySupplier,
+ flagSource);
+ }
+
CoredumpHandler(CoreCollector coreCollector, Cores cores, CoredumpReporter coredumpReporter,
String crashPathInContainer, Path doneCoredumpsPath, Metrics metrics,
Clock clock, Supplier<String> coredumpIdSupplier,
- Supplier<SecretSharedKey> secretSharedKeySupplier, FlagSource flagSource) {
+ SecretSharedKeySupplier secretSharedKeySupplier, FlagSource flagSource) {
this.coreCollector = coreCollector;
this.cores = cores;
this.coredumpReporter = coredumpReporter;
@@ -108,6 +121,7 @@ public class CoredumpHandler {
this.coredumpIdSupplier = coredumpIdSupplier;
this.secretSharedKeySupplier = secretSharedKeySupplier;
this.reportCoresViaCfgFlag = Flags.REPORT_CORES_VIA_CFG.bindTo(flagSource);
+ this.coreEncryptionPublicKeyIdFlag = Flags.CORE_ENCRYPTION_PUBLIC_KEY_ID.bindTo(flagSource);
}
@@ -196,9 +210,16 @@ public class CoredumpHandler {
return Optional.of(enqueuedDir);
}
+ private String corePublicKeyFlagValue(NodeAgentContext context) {
+ return coreEncryptionPublicKeyIdFlag.with(FetchVector.Dimension.NODE_TYPE, context.nodeType().name()).value();
+ }
+
void processAndReportSingleCoredump(NodeAgentContext context, ContainerPath coredumpDirectory, Supplier<Map<String, Object>> nodeAttributesSupplier) {
try {
- Optional<SecretSharedKey> sharedCoreKey = Optional.ofNullable(secretSharedKeySupplier.get());
+ Optional<SecretSharedKey> sharedCoreKey = Optional.of(corePublicKeyFlagValue(context))
+ .filter(k -> !k.isEmpty())
+ .map(KeyId::ofString)
+ .flatMap(secretSharedKeySupplier::create);
Optional<String> decryptionToken = sharedCoreKey.map(k -> k.sealedSharedKey().toTokenString());
String metadata = getMetadata(context, coredumpDirectory, nodeAttributesSupplier, decryptionToken);
String coredumpId = coredumpDirectory.getFileName().toString();
@@ -359,7 +380,10 @@ public class CoredumpHandler {
dockerImage.ifPresent(metadata::setDockerImage);
dockerImage.flatMap(DockerImage::tag).ifPresent(metadata::setVespaVersion);
dockerImage.ifPresent(metadata::setDockerImage);
- Optional<SecretSharedKey> sharedCoreKey = Optional.ofNullable(secretSharedKeySupplier.get());
+ Optional<SecretSharedKey> sharedCoreKey = Optional.of(corePublicKeyFlagValue(context))
+ .filter(k -> !k.isEmpty())
+ .map(KeyId::ofString)
+ .flatMap(secretSharedKeySupplier::create);
sharedCoreKey.map(key -> key.sealedSharedKey().toTokenString()).ifPresent(metadata::setDecryptionToken);
String coreDumpId = coreDumpDirectory.getFileName().toString();
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/SecretSharedKeySupplier.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/SecretSharedKeySupplier.java
new file mode 100644
index 00000000000..5d33c80e0cb
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/SecretSharedKeySupplier.java
@@ -0,0 +1,17 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.node.admin.maintenance.coredump;
+
+import com.yahoo.security.KeyId;
+import com.yahoo.security.SecretSharedKey;
+
+import java.util.Optional;
+
+/**
+ * @author vekterli
+ */
+@FunctionalInterface
+public interface SecretSharedKeySupplier {
+
+ Optional<SecretSharedKey> create(KeyId publicKeyId);
+
+}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java
index 235007d7499..b096db2eaf4 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java
@@ -5,6 +5,7 @@ import com.yahoo.security.KeyId;
import com.yahoo.security.SealedSharedKey;
import com.yahoo.security.SecretSharedKey;
import com.yahoo.test.ManualClock;
+import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
import com.yahoo.vespa.hosted.node.admin.configserver.cores.Cores;
import com.yahoo.vespa.hosted.node.admin.container.metrics.DimensionMetrics;
@@ -61,8 +62,7 @@ public class CoredumpHandlerTest {
private final ManualClock clock = new ManualClock();
@SuppressWarnings("unchecked")
private final Supplier<String> coredumpIdSupplier = mock(Supplier.class);
- @SuppressWarnings("unchecked")
- private final Supplier<SecretSharedKey> secretSharedKeySupplier = mock(Supplier.class);
+ private final SecretSharedKeySupplier secretSharedKeySupplier = mock(SecretSharedKeySupplier.class);
private final InMemoryFlagSource flagSource = new InMemoryFlagSource();
private final CoredumpHandler coredumpHandler =
new CoredumpHandler(coreCollector, cores, coredumpReporter, containerCrashPath.pathInContainer(),
@@ -198,7 +198,7 @@ public class CoredumpHandlerTest {
@Test
void get_metadata_test_with_encryption() throws IOException {
- when(secretSharedKeySupplier.get()).thenReturn(makeFixedSecretSharedKey());
+ when(secretSharedKeySupplier.create(any())).thenReturn(Optional.of(makeFixedSecretSharedKey()));
do_get_metadata_test(Optional.of("AVeryCoolToken"), Optional.of("AnEvenCoolerToken"));
}
@@ -250,10 +250,27 @@ public class CoredumpHandlerTest {
@Test
void process_single_coredump_test_with_encryption() throws IOException {
- when(secretSharedKeySupplier.get()).thenReturn(makeFixedSecretSharedKey());
+ flagSource.withStringFlag(Flags.CORE_ENCRYPTION_PUBLIC_KEY_ID.id(), "bar-key");
+ when(secretSharedKeySupplier.create(KeyId.ofString("bar-key"))).thenReturn(Optional.of(makeFixedSecretSharedKey()));
do_process_single_coredump_test("dump_bash.core.431.zst.enc");
}
+ // TODO fail closed instead of open
+ @Test
+ void encryption_disabled_when_no_public_key_set_in_feature_flag() throws IOException {
+ flagSource.withStringFlag(Flags.CORE_ENCRYPTION_PUBLIC_KEY_ID.id(), ""); // empty -> not set
+ verify(secretSharedKeySupplier, never()).create(any());
+ do_process_single_coredump_test("dump_bash.core.431.zst"); // No .enc suffix; not encrypted
+ }
+
+ // TODO fail closed instead of open
+ @Test
+ void encryption_disabled_when_no_key_returned_for_key_id_specified_by_feature_flag() throws IOException {
+ flagSource.withStringFlag(Flags.CORE_ENCRYPTION_PUBLIC_KEY_ID.id(), "baz-key");
+ when(secretSharedKeySupplier.create(KeyId.ofString("baz-key"))).thenReturn(Optional.empty());
+ do_process_single_coredump_test("dump_bash.core.431.zst"); // No .enc suffix; not encrypted
+ }
+
@Test
void report_enqueued_and_processed_metrics() throws IOException {
Path processingPath = containerCrashPath.resolve("processing");