package com.provectus.kafka.ui.service; import static java.util.regex.Pattern.CASE_INSENSITIVE; import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.SaslConfigs; import org.apache.kafka.common.config.SslConfigs; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class KafkaConfigSanitizer { private static final String SANITIZED_VALUE = "******"; private static final String[] REGEX_PARTS = {"*", "$", "^", "+"}; private static final List DEFAULT_PATTERNS_TO_SANITIZE = ImmutableList.builder() .addAll(kafkaConfigKeysToSanitize()) .add( "basic.auth.user.info", /* For Schema Registry credentials */ "password", "secret", "token", "key", ".*credentials.*", /* General credential patterns */ "aws.access.*", "aws.secret.*", "aws.session.*" /* AWS-related credential patterns */ ) .build(); private final List sanitizeKeysPatterns; KafkaConfigSanitizer( @Value("${kafka.config.sanitizer.enabled:true}") boolean enabled, @Value("${kafka.config.sanitizer.patterns:}") List patternsToSanitize ) { this.sanitizeKeysPatterns = enabled ? compile(patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize) : List.of(); } private static List compile(Collection patternStrings) { return patternStrings.stream() .map(p -> isRegex(p) ? Pattern.compile(p, CASE_INSENSITIVE) : Pattern.compile(".*" + p + "$", CASE_INSENSITIVE)) .toList(); } private static boolean isRegex(String str) { return Arrays.stream(REGEX_PARTS).anyMatch(str::contains); } private static Set kafkaConfigKeysToSanitize() { final ConfigDef configDef = new ConfigDef(); SslConfigs.addClientSslSupport(configDef); SaslConfigs.addClientSaslSupport(configDef); return configDef.configKeys().entrySet().stream() .filter(entry -> entry.getValue().type().equals(ConfigDef.Type.PASSWORD)) .map(Map.Entry::getKey) .collect(Collectors.toSet()); } public Object sanitize(String key, Object value) { if (value == null) { return null; } for (Pattern pattern : sanitizeKeysPatterns) { if (pattern.matcher(key).matches()) { return SANITIZED_VALUE; } } return value; } }