1

I am trying to use OPA as authorization service for Trino. I wrote a rego file according to my needs.

package mytrino

import rego.v1

default allow := false

allow if {
    input.action.operation == "ExecuteQuery"
    not input.action.resource
}

allow if {
    input.action.operation == "AccessCatalog"
}

allow if {
    input.action.operation == "FilterCatalogs"
}

allow if {
    input.action.operation == "FilterSchemas"
}

allow if {
    input.action.operation == "SelectFromColumns"
    input.action.resource.table.catalogName == "system"
}

allow if {
    response := http.send({
        "method": "post",
        "url": "http://host.docker.internal:8085/api/products/check-table-access",
        "headers": {"Content-Type": "application/json"},
        "body": {
            "user": input.context.identity.user,
            "table": input.action.resource.table.tableName
        }
    })
    response.status_code == 200
}

I was checking my API logs and I saw there have been requests that are 100% percent true without the last allow if statement. So I think even though the previous allow if's are true, it evaluate subsequent statements?

How can I prevent final allow if statement to make http requests if the previous ones are true?

Thank you a lot!

1 Answer 1

1

Rego rules are all evaluated at once, so if you want to block the calling of http.send then you can introduce a dependency on the other rules before calling it with a function like this:

package play

import rego.v1

default allow := false

# this will be true if the conditions that can be checked locally are validated ok
allow if deterministic_allow

allow if check_table_access(
    # this enforces a dependency of this rule on deterministic_allow
    # and so it will not be called until deterministic_allow is known
    deterministic_allow,
    input.context.identity.user,
    input.action.resource.table.tableName,
)

default deterministic_allow := false

deterministic_allow if {
    input.action.operation == "ExecuteQuery"
    not input.action.resource
}

deterministic_allow if {
    input.action.operation == "AccessCatalog"
}

deterministic_allow if {
    input.action.operation == "FilterCatalogs"
}

deterministic_allow if {
    input.action.operation == "FilterSchemas"
}

deterministic_allow if {
    input.action.operation == "SelectFromColumns"
    input.action.resource.table.catalogName == "system"
}

# when deterministic_allow is true, then this function just short circuits and returns true
check_table_access(true, _, _) := true

# when deterministic_allow is false, the http call is made to perform the final chance check
check_table_access(false, user, table_name) := result if {
    response := http.send({
        "method": "post",
        "url": "http://host.docker.internal:8085/api/products/check-table-access",
        "headers": {"Content-Type": "application/json"},
        "body": {
            "user": user,
            "table": table_name,
        },
    })

    result := response.status_code == 200
}

This is based on 'Expressing OR using helper functions'.

Sign up to request clarification or add additional context in comments.

1 Comment

Glad it worked! Take a look over that post as this is something folk often get hung up on. There are various ways to do OR in rego, different options are better for different scenarios too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.