data-mask
The data-mask plugin masks sensitive information in request headers, bodies, and URL queries when using logging plugins. Note that it does not modify the actual request or response traffic.
To mask sensitive information in the gateway's access log, see Mask Sensitive Data in Access Log.
The plugin can be configured on routes, services, or as a global plugin. However, be aware that global plugins are always executed before route- or service-level plugins, so data masking may occur after logging.
For instance, if a logging plugin is configured globally while data-mask is applied at the route level, requests will be logged before masking occurs, and sensitive data will appear in plaintext.
To ensure the intended behavior, it is recommended to configure both plugins at the same level:
- Both at the global level (recommended if suitable for your use case)
- Both at the route or service level
Examples
The examples below demonstrate how you can use the data-mask plugin for different scenarios.
While all examples use the file-logger plugin for logging, the plugin is used only to demonstrate the results of data masking. Select the logging plugin that best suits your environment.
Mask Sensitive Information in URL Query
The following example demonstrates how you can mask sensitive information in the request URL queries, before the request is logged to a local file by the file-logger plugin.
Create a route with the file-logger plugin to log requests and the data-mask plugin with three data masking rules:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "data-mask-route",
"uri": "/anything",
"plugins": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "query"
},
{
"action": "replace",
"name": "token",
"type": "query",
"value": "*****"
},
{
"action": "regex",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "query",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"path": "/tmp/mask-query.log"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: data-mask-service
routes:
- name: data-mask-route
uris:
- /anything
plugins:
data-mask:
request:
- action: remove
name: password
type: query
- action: replace
name: token
type: query
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: query
value: "$1-****-****-$2"
file-logger:
path: /tmp/mask-query.log
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: data-mask-query-plugin-config
spec:
plugins:
- name: data-mask
config:
request:
- action: remove
name: password
type: query
- action: replace
name: token
type: query
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: query
value: "$1-****-****-$2"
- name: file-logger
config:
path: /tmp/mask-query.log
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: data-mask-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: data-mask-query-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
Apply the configuration to your cluster:
kubectl apply -f data-mask-query-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: data-mask-route
spec:
ingressClassName: apisix
http:
- name: data-mask-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: data-mask
enable: true
config:
request:
- action: remove
name: password
type: query
- action: replace
name: token
type: query
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: query
value: "$1-****-****-$2"
- name: file-logger
enable: true
config:
path: /tmp/mask-query.log
Apply the configuration to your cluster:
kubectl apply -f data-mask-query-ic.yaml
❶ Configure the data masking rule to remove password URL query from the request.
❷ Configure the data masking rule to replace the value of token URL query with *****.
❸ Configure the data masking rule that matches card number in the URL query with RegEx and mask the middle portion of the card number.
❹ path to the log file on the filesystem where logs should be saved.
Send a request to the route with sensitive information in URL queries:
curl -i "http://127.0.0.1:9080/anything?password=abc&token=xyz&card=1234-1234-1234-1234"
You should receive an HTTP/1.1 200 OK response.
Navigating to the /tmp/mask-query.log file and examining the log content, you should see a log entry similar to the following:
{
"request": {
"uri": "/anything?token=*****&card=1234-****-****-1234",
"method": "GET",
"url": "http://127.0.0.1:9080/anything?token=*****&card=1234-****-****-1234",
"querystring": {
"token": "*****",
"card": "1234-****-****-1234"
}
}
}
Mask Sensitive Information in Request Headers
The following example demonstrates how you can mask sensitive information in request headers, before the request is logged to a local file by the file-logger plugin.
Create a route with the file-logger plugin to log requests and the data-mask plugin with three data masking rules:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "data-mask-route",
"uri": "/anything",
"plugins": {
"data-mask": {
"request": [
{
"action": "remove",
"name": "password",
"type": "header"
},
{
"action": "replace",
"name": "token",
"type": "header",
"value": "*****"
},
{
"action": "regex",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "header",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"path": "/tmp/mask-header.log"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: data-mask-service
routes:
- name: data-mask-route
uris:
- /anything
plugins:
data-mask:
request:
- action: remove
name: password
type: header
- action: replace
name: token
type: header
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: header
value: "$1-****-****-$2"
file-logger:
path: /tmp/mask-header.log
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: data-mask-header-plugin-config
spec:
plugins:
- name: data-mask
config:
request:
- action: remove
name: password
type: header
- action: replace
name: token
type: header
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: header
value: "$1-****-****-$2"
- name: file-logger
config:
path: /tmp/mask-header.log
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: data-mask-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: data-mask-header-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
Apply the configuration to your cluster:
kubectl apply -f data-mask-header-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: data-mask-route
spec:
ingressClassName: apisix
http:
- name: data-mask-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: data-mask
enable: true
config:
request:
- action: remove
name: password
type: header
- action: replace
name: token
type: header
value: "*****"
- action: regex
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: header
value: "$1-****-****-$2"
- name: file-logger
enable: true
config:
path: /tmp/mask-header.log
Apply the configuration to your cluster:
kubectl apply -f data-mask-header-ic.yaml
❶ Configure the data masking rule to remove password header from the request.
❷ Configure the data masking rule to replace the value of token request header with *****.
❸ Configure the data masking rule that matches card number in the request header with RegEx and mask the middle portion of the card number.
❹ path to the log file on the filesystem where logs should be saved.
Send a POST request to the route with sensitive information in headers:
curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "password: abc" \
-H "token: xyz" \
-H "card: 1234-1234-1234-1234"
You should receive an HTTP/1.1 200 OK response.
Navigating to the /tmp/mask-header.log file and examining the log content, you should see a log entry similar to the following:
{
"request": {
"uri": "/anything",
"method": "GET",
"url": "http://127.0.0.1:9080/anything",
"headers": {
"user-agent": "curl/8.6.0",
"token": "*****",
"card": "1234-****-****-1234"
}
}
}
Mask Sensitive Information in URL-Encoded Request Bodies
The following example demonstrates how you can mask sensitive information in URL-encoded request bodies, before the request is logged to a local file by the file-logger plugin.
Create a route with the file-logger plugin to log requests and the data-mask plugin with three data masking rules:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "data-mask-route",
"uri": "/anything",
"plugins": {
"data-mask": {
"request": [
{
"action": "remove",
"body_format": "urlencoded",
"name": "password",
"type": "body"
},
{
"action": "replace",
"body_format": "urlencoded",
"name": "token",
"type": "body",
"value": "*****"
},
{
"action": "regex",
"body_format": "urlencoded",
"name": "card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "body",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"include_req_body": true,
"path": "/tmp/mask-urlencoded-body.log"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: data-mask-service
routes:
- name: data-mask-route
uris:
- /anything
plugins:
data-mask:
request:
- action: remove
body_format: urlencoded
name: password
type: body
- action: replace
body_format: urlencoded
name: token
type: body
value: "*****"
- action: regex
body_format: urlencoded
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
file-logger:
include_req_body: true
path: /tmp/mask-urlencoded-body.log
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: data-mask-urlencoded-plugin-config
spec:
plugins:
- name: data-mask
config:
request:
- action: remove
body_format: urlencoded
name: password
type: body
- action: replace
body_format: urlencoded
name: token
type: body
value: "*****"
- action: regex
body_format: urlencoded
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
- name: file-logger
config:
include_req_body: true
path: /tmp/mask-urlencoded-body.log
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: data-mask-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: data-mask-urlencoded-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
Apply the configuration to your cluster:
kubectl apply -f data-mask-urlencoded-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: data-mask-route
spec:
ingressClassName: apisix
http:
- name: data-mask-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: data-mask
enable: true
config:
request:
- action: remove
body_format: urlencoded
name: password
type: body
- action: replace
body_format: urlencoded
name: token
type: body
value: "*****"
- action: regex
body_format: urlencoded
name: card
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
- name: file-logger
enable: true
config:
include_req_body: true
path: /tmp/mask-urlencoded-body.log
Apply the configuration to your cluster:
kubectl apply -f data-mask-urlencoded-ic.yaml
❶ Configure the data masking rule to remove password information from the request body.
❷ Configure the data masking rule to replace token information in the request body with *****.
❸ Configure the data masking rule that matches card number in the request body with RegEx and mask the middle portion of the card number.
❹ Include the request body in the log.
Send a request to the route:
curl -i "http://127.0.0.1:9080/anything" \
--data-urlencode "password=abc" \
--data-urlencode "token=xyz" \
--data-urlencode "card=1234-1234-1234-1234"
You should receive an HTTP/1.1 200 OK response.
Navigating to the /tmp/mask-urlencoded-body.log file and examining the log content, you should see a log entry similar to the following:
{
"request": {
"uri": "/anything",
"body": "token=*****&card=1234-****-****-1234",
"method": "POST",
"url": "http://127.0.0.1:9080/anything"
}
}
Mask Sensitive Information in JSON-Encoded Request Bodies
The following example demonstrates how you can mask sensitive information in JSON-encoded request bodies using JSON path syntax in the plugin to look for the target field, before the request is logged to a local file by the file-logger plugin.
Create a route with the file-logger plugin to log requests and the data-mask plugin with three data masking rules:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "data-mask-route",
"uri": "/anything",
"plugins": {
"data-mask": {
"request": [
{
"action": "remove",
"body_format": "json",
"name": "$.password",
"type": "body"
},
{
"action": "replace",
"body_format": "json",
"name": "users[*].token",
"type": "body",
"value": "*****"
},
{
"action": "regex",
"body_format": "json",
"name": "$.users[*].credit.card",
"regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)",
"type": "body",
"value": "$1-****-****-$2"
}
]
},
"file-logger": {
"include_req_body": true,
"path": "/tmp/mask-json-body.log"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: data-mask-service
routes:
- name: data-mask-route
uris:
- /anything
plugins:
data-mask:
request:
- action: remove
body_format: json
name: "$.password"
type: body
- action: replace
body_format: json
name: "users[*].token"
type: body
value: "*****"
- action: regex
body_format: json
name: "$.users[*].credit.card"
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
file-logger:
include_req_body: true
path: /tmp/mask-json-body.log
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: data-mask-json-plugin-config
spec:
plugins:
- name: data-mask
config:
request:
- action: remove
body_format: json
name: "$.password"
type: body
- action: replace
body_format: json
name: "users[*].token"
type: body
value: "*****"
- action: regex
body_format: json
name: "$.users[*].credit.card"
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
- name: file-logger
config:
include_req_body: true
path: /tmp/mask-json-body.log
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: data-mask-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: data-mask-json-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
Apply the configuration to your cluster:
kubectl apply -f data-mask-json-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: data-mask-route
spec:
ingressClassName: apisix
http:
- name: data-mask-route
match:
paths:
- /anything
upstreams:
- name: httpbin-external-domain
plugins:
- name: data-mask
enable: true
config:
request:
- action: remove
body_format: json
name: "$.password"
type: body
- action: replace
body_format: json
name: "users[*].token"
type: body
value: "*****"
- action: regex
body_format: json
name: "$.users[*].credit.card"
regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)"
type: body
value: "$1-****-****-$2"
- name: file-logger
enable: true
config:
include_req_body: true
path: /tmp/mask-json-body.log
Apply the configuration to your cluster:
kubectl apply -f data-mask-json-ic.yaml
❶ Configure the data masking rule to remove password information from the request body.
❷ Configure the data masking rule to replace token information in the request body with *****.
❸ Configure the data masking rule that matches card number in the request body with RegEx and mask the middle portion of the card number.
❹ Include the request body in the log.
Send a request to the route with sensitive information in the request body:
curl -i "http://127.0.0.1:9080/anything" -X POST -d '
{
"password": "abc",
"users": [
{
"token": "xyz",
"credit": {
"card": "1234-1234-1234-1234"
}
},
{
"token": "xyz",
"credit": {
"card": "1234-1234-1234-1234"
}
}
]
}'
You should receive an HTTP/1.1 200 OK response.
Navigating to the /tmp/mask-json-body.log file and examining the log content, you should see a log entry similar to the following:
{
"request": {
"uri": "/anything",
"body": "{\"users\":[{\"token\":\"*****\",\"credit\":{\"card\":\"1234-****-****-1234\"}},{\"token\":\"*****\",\"credit\":{\"card\":\"1234-****-****-1234\"}}]}",
"method": "POST",
"url": "http://127.0.0.1:9080/anything"
}
}