Scrub secrets from process arguments (#13225)

This commit is contained in:
Lauri Tulmin 2025-02-12 05:10:37 +02:00 committed by GitHub
parent 1a620b28ea
commit 77bf68ac90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 18 deletions

View File

@ -84,6 +84,17 @@ testing {
} }
tasks { tasks {
test {
dependsOn(jar)
doFirst {
// use the final jar instead of directories with built classes to test the mrjar functionality
classpath = jar.get().outputs.files + classpath
}
systemProperty("testSecret", "test")
systemProperty("testPassword", "test")
systemProperty("testNotRedacted", "test")
}
check { check {
dependsOn(testing.suites) dependsOn(testing.suites)
} }

View File

@ -14,7 +14,6 @@ import java.io.File;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean; import java.lang.management.RuntimeMXBean;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -35,6 +34,9 @@ public final class ProcessResource {
// Important: This is statically used in buildResource, so must be declared/initialized first. // Important: This is statically used in buildResource, so must be declared/initialized first.
private static final Pattern JAR_FILE_PATTERN = private static final Pattern JAR_FILE_PATTERN =
Pattern.compile("^\\S+\\.(jar|war)", Pattern.CASE_INSENSITIVE); Pattern.compile("^\\S+\\.(jar|war)", Pattern.CASE_INSENSITIVE);
// scrub values for system properties containing "secret" or "password" in the name
private static final Pattern SCRUB_PATTERN =
Pattern.compile("(-D.*(password|secret).*=).*", Pattern.CASE_INSENSITIVE);
private static final Resource INSTANCE = buildResource(); private static final Resource INSTANCE = buildResource();
@ -94,12 +96,14 @@ public final class ProcessResource {
if (args.length > 0) { if (args.length > 0) {
List<String> commandArgs = new ArrayList<>(args.length + 1); List<String> commandArgs = new ArrayList<>(args.length + 1);
commandArgs.add(executablePath.toString()); commandArgs.add(executablePath.toString());
commandArgs.addAll(Arrays.asList(args)); for (String arg : args) {
commandArgs.add(scrub(arg));
}
attributes.put(PROCESS_COMMAND_ARGS, commandArgs); attributes.put(PROCESS_COMMAND_ARGS, commandArgs);
} else { // Java 8 } else { // Java 8
StringBuilder commandLine = new StringBuilder(executablePath); StringBuilder commandLine = new StringBuilder(executablePath);
for (String arg : runtime.getInputArguments()) { for (String arg : runtime.getInputArguments()) {
commandLine.append(' ').append(arg); commandLine.append(' ').append(scrub(arg));
} }
// sun.java.command isn't well document and may not be available on all systems. // sun.java.command isn't well document and may not be available on all systems.
String javaCommand = System.getProperty("sun.java.command"); String javaCommand = System.getProperty("sun.java.command");
@ -118,5 +122,9 @@ public final class ProcessResource {
return Resource.create(attributes.build(), SchemaUrls.V1_24_0); return Resource.create(attributes.build(), SchemaUrls.V1_24_0);
} }
private static String scrub(String argument) {
return SCRUB_PATTERN.matcher(argument).replaceFirst("$1***");
}
private ProcessResource() {} private ProcessResource() {}
} }

View File

@ -19,32 +19,39 @@ class ProcessResourceTest {
@Test @Test
@SetSystemProperty(key = "os.name", value = "Linux 4.12") @SetSystemProperty(key = "os.name", value = "Linux 4.12")
void notWindows() { void notWindows() {
Resource resource = ProcessResource.buildResource(); assertResource(false);
assertThat(resource.getSchemaUrl()).isEqualTo(SchemaUrls.V1_24_0);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH))
.matches(".*[/\\\\]java");
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_COMMAND_LINE))
.contains(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH));
// With Java 9+ and a compiled jar, ResourceAttributes.PROCESS_COMMAND_ARGS
// will be set instead of ResourceAttributes.PROCESS_COMMAND_LINE
} }
@Test @Test
@SetSystemProperty(key = "os.name", value = "Windows 10") @SetSystemProperty(key = "os.name", value = "Windows 10")
void windows() { void windows() {
assertResource(true);
}
private static void assertResource(boolean windows) {
Resource resource = ProcessResource.buildResource(); Resource resource = ProcessResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(SchemaUrls.V1_24_0); assertThat(resource.getSchemaUrl()).isEqualTo(SchemaUrls.V1_24_0);
Attributes attributes = resource.getAttributes(); Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_PID)).isGreaterThan(1); assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH)) assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH))
.matches(".*[/\\\\]java\\.exe"); .matches(windows ? ".*[/\\\\]java\\.exe" : ".*[/\\\\]java");
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_COMMAND_LINE))
.contains(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH));
// With Java 9+ and a compiled jar, ResourceAttributes.PROCESS_COMMAND_ARGS // With Java 9+ and a compiled jar, ResourceAttributes.PROCESS_COMMAND_ARGS
// will be set instead of ResourceAttributes.PROCESS_COMMAND_LINE // will be set instead of ResourceAttributes.PROCESS_COMMAND_LINE
boolean java8 = "1.8".equals(System.getProperty("java.specification.version"));
if (java8) {
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_COMMAND_LINE))
.contains(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH))
.contains("-DtestSecret=***")
.contains("-DtestPassword=***")
.contains("-DtestNotRedacted=test");
} else {
assertThat(attributes.get(ProcessIncubatingAttributes.PROCESS_COMMAND_ARGS))
.contains(attributes.get(ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH))
.contains("-DtestSecret=***")
.contains("-DtestPassword=***")
.contains("-DtestNotRedacted=test");
}
} }
} }

View File

@ -31,6 +31,7 @@ class DeclarativeConfigTest {
+ " value: my-service\n" + " value: my-service\n"
+ "tracer_provider:\n"; + "tracer_provider:\n";
boolean java8 = "1.8".equals(System.getProperty("java.specification.version"));
OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk openTelemetrySdk =
FileConfiguration.parseAndCreate( FileConfiguration.parseAndCreate(
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)));
@ -56,7 +57,8 @@ class DeclarativeConfigTest {
assertThat(attributeKeys).contains("os.description"); assertThat(attributeKeys).contains("os.description");
assertThat(attributeKeys).contains("os.type"); assertThat(attributeKeys).contains("os.type");
// ProcessResourceComponentProvider // ProcessResourceComponentProvider
assertThat(attributeKeys).contains("process.command_line"); assertThat(attributeKeys)
.contains(java8 ? "process.command_line" : "process.command_args");
assertThat(attributeKeys).contains("process.executable.path"); assertThat(attributeKeys).contains("process.executable.path");
assertThat(attributeKeys).contains("process.pid"); assertThat(attributeKeys).contains("process.pid");
// ProcessRuntimeResourceComponentProvider // ProcessRuntimeResourceComponentProvider