In our scala apis we are using logstash-logback-encoder
to create json logs. We want to encrypt a particular field. Masking is not enough as the value needs to be decrypted if need be from logs. What would be the best way to achieve this?
One way could be to create an implementation of JsonGeneratorDecorator
like there is one for masking. But given that we know which field to mask, is there an easier way to achieve this?
UPDATE : Solution
I used the suggestion provided by @Phil Clay in the answer. However, there was a small catch. The intention behind ValueMasker
is to decide what/when to mask on the basis of values. For ex, using a RegEx to match against all values (net.logstash.logback.mask.RegexValueMasker)
. Because of their very generic usecase, ValueMaskers
are less efficient/performant. However, my use case is more specific as there is a specific field to be masked. By definition FieldMasker
should be used but it doesn't provide a handle to the value to allow encryption. In the end, I created a custom ValueMasker
but used the logic from net.logstash.logback.mask.FieldNameBasedFieldMasker
as below:
class FieldNameBasedEncryptionMasker extends ValueMasker {
private var salt: String = ""
private var fieldNames: Set[String] = Set.empty
def addFieldName(fieldName: String): Unit =
fieldNames = fieldNames + fieldName
def setSalt(saltValue: String): Unit =
salt = saltValue
override def mask(context: JsonStreamContext, value: Any): AnyRef = {
if (context.hasCurrentName && fieldNames.contains(context.getCurrentName) && value
.isInstanceOf[CharSequence]) {
// encrypt value
} else null
}
}
This can be configured in `logback.xml as:
<appender name="stash" class="net.logstash.logback.appender.LogstashSocketAppender">
<host>$host</host>
<port>$port</port>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app_name":"${LOG_APP_NAME:-undefined}", "app_env":"${LOG_ENV:-local}"}</customFields>
<jsonGeneratorDecorator class="net.logstash.logback.mask.MaskingJsonGeneratorDecorator">
<valueMasker class="FieldNameBasedEncryptionMasker">
<salt>$logging-encryption-salt</salt>
<fieldName>fieldNameToEncrypt1</fieldName>
<fieldName>fieldNameToEncrypt2</fieldName>
</valueMasker>
</jsonGeneratorDecorator>
</encoder>
</appender>
You could create a custom implementation of net.logstash.logback.mask.ValueMasker
that encrypts specific fields, instead of returning a standard masked value such as ****
.
Then configure the encoder to use your custom masker like this:
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<jsonGeneratorDecorator class="net.logstash.logback.mask.MaskingJsonGeneratorDecorator">
<valueMasker class="your.custom.EncryptingMasker"/>
</jsonGeneratorDecorator>
</encoder>