KafkaConfigSanitizer.java 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package com.provectus.kafka.ui.service;
  2. import static java.util.regex.Pattern.CASE_INSENSITIVE;
  3. import com.google.common.collect.ImmutableList;
  4. import java.util.Arrays;
  5. import java.util.Collection;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import java.util.regex.Pattern;
  10. import java.util.stream.Collectors;
  11. import org.apache.kafka.common.config.ConfigDef;
  12. import org.apache.kafka.common.config.SaslConfigs;
  13. import org.apache.kafka.common.config.SslConfigs;
  14. import org.springframework.beans.factory.annotation.Value;
  15. import org.springframework.stereotype.Component;
  16. @Component
  17. class KafkaConfigSanitizer {
  18. private static final String SANITIZED_VALUE = "******";
  19. private static final String[] REGEX_PARTS = {"*", "$", "^", "+"};
  20. private static final List<String> DEFAULT_PATTERNS_TO_SANITIZE = ImmutableList.<String>builder()
  21. .addAll(kafkaConfigKeysToSanitize())
  22. .add(
  23. "basic.auth.user.info", /* For Schema Registry credentials */
  24. "password", "secret", "token", "key", ".*credentials.*", /* General credential patterns */
  25. "aws.access.*", "aws.secret.*", "aws.session.*" /* AWS-related credential patterns */
  26. )
  27. .build();
  28. private final List<Pattern> sanitizeKeysPatterns;
  29. KafkaConfigSanitizer(
  30. @Value("${kafka.config.sanitizer.enabled:true}") boolean enabled,
  31. @Value("${kafka.config.sanitizer.patterns:}") List<String> patternsToSanitize
  32. ) {
  33. this.sanitizeKeysPatterns = enabled
  34. ? compile(patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize)
  35. : List.of();
  36. }
  37. private static List<Pattern> compile(Collection<String> patternStrings) {
  38. return patternStrings.stream()
  39. .map(p -> isRegex(p)
  40. ? Pattern.compile(p, CASE_INSENSITIVE)
  41. : Pattern.compile(".*" + p + "$", CASE_INSENSITIVE))
  42. .toList();
  43. }
  44. private static boolean isRegex(String str) {
  45. return Arrays.stream(REGEX_PARTS).anyMatch(str::contains);
  46. }
  47. private static Set<String> kafkaConfigKeysToSanitize() {
  48. final ConfigDef configDef = new ConfigDef();
  49. SslConfigs.addClientSslSupport(configDef);
  50. SaslConfigs.addClientSaslSupport(configDef);
  51. return configDef.configKeys().entrySet().stream()
  52. .filter(entry -> entry.getValue().type().equals(ConfigDef.Type.PASSWORD))
  53. .map(Map.Entry::getKey)
  54. .collect(Collectors.toSet());
  55. }
  56. public Object sanitize(String key, Object value) {
  57. if (value == null) {
  58. return null;
  59. }
  60. for (Pattern pattern : sanitizeKeysPatterns) {
  61. if (pattern.matcher(key).matches()) {
  62. return SANITIZED_VALUE;
  63. }
  64. }
  65. return value;
  66. }
  67. }