Masking logs
Подключение
Maven
<dependency>
<groupId>ru.romanow.logging</groupId>
<artifactId>log-masking-lib</artifactId>
<version>${log-masking-lib.version}</version>
</dependency>
Gradle
testImplementation "ru.romanow.logging:log-masking-lib:$logMaskingVersion"
Реализация
Для маскирования логов используется
плагин MaskingConverter
.
Для его подключения используется annotation processor org.apache.logging.log4j:log4j-core
, который собирает плагины
в $buildDir/tmp/kapt3/classes/main/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
.
В шаблоне этот конвертер вызывается как %mask{ %msg }
:
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %mask{ %msg }%n"/>
Отправка в ELK выполняется в формате JSON через fluent-bit (по адресу localhost:5170), для сборки сообщения
используется JsonTemplateLayout
(шаблон layout.json, для маскирования
используется pattern resolver как %mask{ %msg }
.
Тестирование
$ docker compose up -d
$ ./gradlew bootRun --args='--spring.profiles.active=docker'
$ curl http://localhost:8080/api/v1/send \
-H 'Content-Type: application/json' \
-d '{"lastName": "Alex"}'
$ docker compose logs -f fluent-bit
Вывод fluent-bit:
fluent-bit | {"localTime"=>"2024-05-14T20:47:40.589Z", "level"=>"INFO", "text"=>"Initializing Servlet 'dispatcherServlet'", "levelInt"=>6, "loggerName"=>"org.springframework.web.servlet.DispatcherServlet", "threadName"=>"http-nio-8080-exec-1", "appName"=>"log-masking", "appType"=>"JAVA"}]
fluent-bit | {"localTime"=>"2024-05-14T20:47:40.590Z", "level"=>"INFO", "text"=>"Completed initialization in 1 ms", "levelInt"=>6, "loggerName"=>"org.springframework.web.servlet.DispatcherServlet", "threadName"=>"http-nio-8080-exec-1", "appName"=>"log-masking", "appType"=>"JAVA"}]
fluent-bit | {"localTime"=>"2024-05-14T20:47:40.620Z", "level"=>"INFO", "text"=>"{"lastName":"<masked>"}", "levelInt"=>6, "loggerName"=>"ru.romanow.logging.web.LogSender", "threadName"=>"http-nio-8080-exec-1", "appName"=>"log-masking", "appType"=>"JAVA"}]
Правила маскирования
Тип поля:
email
–>romanowalex@mail.ru
->r**********@mail.ru
firstName
–> не маскируетсяlastName
,middleName
–> if (name.length > 7)Ab*****c
elseA*****
text
–> в зависимости от длины:- 1 ->
*
- 1..4 ->
1234
->1***
- 5..9 ->
123456789
->1******89
(length * 60%) - 10..15 ->
12345678901
->12*******01
(length * 60%) - 16 + ->
12345678901234567
->123***********567
(length * 60%)
- 1 ->
Конфигурация:
application:
masking:
- field: fullName
type: FULL_NAME
- field: lastName
type: LAST_NAME
- field: email
type: EMAIL
- field: JWT
type: TEXT
- regex: Authorization\s*:\s*(\S+)
type: TEXT