Data Masking¶
Remove sensitive values before logging or returning a payload. Mask selected fields, or encrypt them with an optional provider.
Install¶
Use Go 1.27 or newer:
CGO_ENABLED=0 go get github.com/rambow-cloud/powertools-lambda-go/datamasking@v1.2.0
CGO_ENABLED=0 go get github.com/rambow-cloud/powertools-lambda-go/logger@v1.2.0
Mask a customer field¶
Mask the payload before passing it to Powertools Logger. The original payload stays unchanged, so log the returned copy. This example needs no AWS credentials; its log timestamp varies on each run.
Input
Code
package main
import (
"context"
"os"
"github.com/rambow-cloud/powertools-lambda-go/datamasking"
"github.com/rambow-cloud/powertools-lambda-go/logger"
)
func main() {
appLog := logger.New(logger.WithServiceName("orders"))
if err := run(appLog); err != nil {
if logErr := appLog.Error("Application failed", err); logErr != nil {
panic(logErr)
}
os.Exit(1)
}
}
func run(appLog *logger.Logger) error {
payload := map[string]any{
"customer": map[string]any{"name": "Ada", "ssn": "123-45-6789"},
"order_id": "ORD-123",
}
masker := datamasking.New(datamasking.Config{})
masked, err := masker.Erase(context.Background(), payload, datamasking.EraseOptions{
Fields: []string{"customer.ssn"},
})
if err != nil {
return err
}
if err := appLog.Info("Order received", logger.Fields{"order": masked}); err != nil {
return err
}
return nil
}
Output
{
"level": "INFO",
"message": "Order received",
"timestamp": "2026-10-15T00:00:00.000Z",
"service": "orders",
"sampling_rate": 0,
"order": {
"customer": {
"name": "Ada",
"ssn": "*****"
},
"order_id": "ORD-123"
}
}
Choose a custom mask¶
The default replacement is "*****", regardless of the original string length. Set CustomMask to use "[redacted]" instead. The following snippets run independently inside a function returning error, with a context ctx and the masker and appLog created above. Log excerpts omit Logger's standard fields.
replacement := "[redacted]"
masked, err := masker.Erase(ctx, payload, datamasking.EraseOptions{
Fields: []string{"customer.ssn"},
Rule: datamasking.Rule{CustomMask: &replacement},
})
if err != nil { return err }
return appLog.Info("Order received", logger.Fields{"order": masked})
Output (log excerpt)
{
"message": "Order received",
"order": {
"customer": {
"name": "Ada",
"ssn": "[redacted]"
},
"order_id": "ORD-123"
}
}
Mask every item in an array¶
This separate call omits CustomMask, so each email uses the default "*****". A custom mask affects only the call that supplies it; it does not change the masker. Pass the same Rule here if you want "[redacted]" for emails too.
payload := map[string]any{"customers": []any{
map[string]any{"email": "ada@example.com"},
map[string]any{"email": "grace@example.com"},
}}
masked, err := masker.Erase(ctx, payload, datamasking.EraseOptions{
Fields: []string{"customers[*].email"},
})
if err != nil { return err }
return appLog.Info("Customers received", logger.Fields{"payload": masked})
Output (log excerpt)
{
"message": "Customers received",
"payload": {
"customers": [
{
"email": "*****"
},
{
"email": "*****"
}
]
}
}
Encrypt instead of erasing¶
Configure a Provider and use Encrypt / Decrypt with TransformOptions. The KMS guide shows authenticated encryption with the AWS Encryption SDK.
Use regular-expression rules when you need to replace only part of a field.
Things to know¶
- Masks are irreversible; a replacement string is not encrypted data.
- Missing selectors fail by default.
IgnoreMissingwarns and continues. - Use
users.0.secretorusers[*].secretfor arrays;users[0].secretis not an array-index selector. - An omitted
Fieldsslice masks the whole value; an explicitly empty slice selects no fields.
Next steps¶
See the API and behavior notes for advanced options, and module installation for dependencies.