Search code examples
maskopaopen-policy-agentregosensitive-data

OPA: Mask sensitive data


I want to mask the password in my Open Policy Agent (OPA) logs.

This is my input data:

{
"decision_id":"71e99093-b980-4c67-bd0c-87fcc071571a",
"input":{
  "attributes":{
     .....
     ,
     "request":{
        "http":{
           "body":"{\r\n    \"username\": \"MyUsername\",\r\n    \"password\": \"MySecetPassword\"\r\n}",
           "headers":{
           ....
           },
           "method":"POST",
           "path":"/login",
           "protocol":"HTTP/1.1",
           "scheme":"http",
           "size":"63"
        },
        "time":"2022-09-06T05:51:13.802770Z"
     },
     ...
  },
  "parsed_body":{
     "password":"MySecetPassword",
     "username":"MyUsername"
  },
  "parsed_path":[
     "login"
  ],
  "parsed_query":{
     
  },
  "truncated_body":false,
  "version":{
     "encoding":"protojson",
     "ext_authz":"v3"
  }
},
"labels":{
  "id":"3987b552-f128-47f2-9b96-34289d677d76",
  "version":"0.35.0-envoy"
},
"level":"info",
"metrics":{
  "timer_rego_query_eval_ns":49451,
  "timer_server_handler_ns":395446
},
"msg":"Decision Log",
"path":"istio/authz/allow",
"requested_by":"",
"result":true,
"time":"2022-09-06T05:51:13Z",
"timestamp":"2022-09-06T05:51:13.804132822Z",
"type":"openpolicyagent.org/decision_logs"
}

My OPA mask rule:

mask[{"op": "upsert", "path": "/input/attributes/request/http/body", "value": x}] {
    # conditionally upsert password if it existed in the orginal event
    contains(input.attributes.request.http.body, "password")
    x := "***CENSORED***"
}

mask[{"op": "upsert", "path": "/input/parsed_body/password", "value": x}] {
    # conditionally upsert password if it existed in the orginal event
    input.parsed_body.password
    x := "***CENSORED***"
}

But when OPA checks the request, the sensitive data won't be masked with the new text. Any idea?!

I checked the rule in the The Rego Playground (https://play.openpolicyagent.org) which was fine...


Solution

  • From the OPA docs on the topic, you'll see that the original input attribute may be referenced under input.input (i.e. not just input, as that's the input attribute for the masking policy itself).

    package system.log
    
    mask["/input/password"] {
      # OPA provides the entire decision log event as input to the masking policy.
      # Refer to the original input document under input.input.
      input.input.resource == "user"
    }
    

    Changing input.attributes.request.http.body to input.input.attributes.request.http.body should do it.