Enforce permissions at an API gateway or proxy
Understand the design choices for enforcing Permit.io permissions at an API gateway or reverse proxy, before you set up a specific integration. This page is for developers who add an authorization layer in front of their services, such as Kong, NGINX, or AWS API Gateway, in addition to or instead of permit.check() calls in application code.
A gateway or proxy acts as a policy enforcement point (PEP): it asks a policy decision point (PDP) whether the authenticated user can call the requested endpoint, then forwards or blocks the request. Gateway checks work at the endpoint level. Keep finer-grained checks, such as checks on a specific record, in your application code.
Gateway and proxy integrations
| Integration | How the gateway asks the PDP | What it takes to block a denied request | Guide |
|---|---|---|---|
| AWS API Gateway | A Lambda authorizer calls the PDP with the Permit Python SDK | The authorizer returns a Deny policy, and API Gateway blocks the call | AWS API Gateway |
| Kong Gateway | The Kong OPA plugin calls the PDP's /kong endpoint | A reverse proxy between Kong and the PDP, because the plugin can't send the PDP its API key | Kong API Gateway |
| NGINX | The auth_request module sends a subrequest to the PDP's /nginx_allowed endpoint | An njs or Lua handler, because /nginx_allowed returns HTTP 200 for a denied check and auth_request reads only the status code | NGINX |
| Other gateways or custom proxies | Your gateway calls the PDP HTTP API | Your gateway reads the allow field of the response and blocks the request | Call the PDP API directly |
Model endpoints as resources and actions
Each HTTP endpoint and method is a small, well-defined operation, which makes it a natural unit for a gateway decision. In both modeling methods, URL mapping and endpoint resources, the PDP checks the permissions of the user who authenticated the request.
Map URLs to existing resources and actions
With URL mapping, you keep the resources and actions of your existing policy and add rules that map each HTTP method and URL to a resource and an action. One policy then serves both your application code and the gateway, and you don't create a policy entry for every endpoint.
For example, a document resource with a write action can map to both POST /blogs and POST /articles. URL mapping fits API gateways well, because gateway routes already list every endpoint in a structured form.
To set up mapping rules and send URL checks to the PDP, see Check permissions by URL with simple URL mapping.
Model each endpoint as a resource
With the second method, you create a dedicated policy for the gateway: the endpoint URL is the resource, and the HTTP method is the action. A policy that follows your endpoint naming convention gives you a rule per endpoint. The trade-off is that the gateway policy duplicates rules you may already have in the application policy.
Map the request to the decision request
Both methods use the same convention to turn an HTTP request into a decision request:
| Request part | Decision request field |
|---|---|
| URL or endpoint | Resource |
| HTTP method | Action |
| Token of the authenticated user | User |
The gateway maps these request parts to the fields the PDP expects. When a decision needs more detail than the URL, method, and user, such as an attribute read from the request, add a transformer to the gateway configuration. A transformer builds the decision request from the HTTP request, for all endpoints or for a subset of endpoints.
Choose a policy model for gateway checks
The policy model changes how much request data the gateway has to extract:
| Policy model | Gateway work | Trade-off |
|---|---|---|
| Role-based access control (RBAC) | Map the endpoint to a resource and use the user's roles | Least work, but the decision can't depend on the specific object |
| Attribute-based access control (ABAC) | Extract attributes from the request, such as fields in the body | Transforming the request into attributes adds work to every request |
| Relationship-based access control (ReBAC) | Extract the resource instance, such as an ID in the path | You need a consistent way to read the instance from each request |
Pick the simplest model that answers the question the gateway must decide, and keep object-level decisions in application code when the request doesn't carry enough data.
Manage the gateway policy as code
Most gateways and proxies are configured with infrastructure-as-code files. Declare the Permit policy for the gateway the same way, with the Permit Terraform provider, so gateway routes and the policy that protects them change in the same review and deployment.
The following Terraform resource declares a document resource whose actions use HTTP methods as keys:
resource "permitio_resource" "document" {
key = "document"
name = "document"
description = "documents endpoint"
actions = {
"GET" = {
"name" = "read"
}
"POST" = {
"name" = "write"
}
"PUT" = {
"name" = "update"
}
"DELETE" = {
"name" = "delete"
"description" = "delete a document"
}
}
attributes = {
"title" = {
"description" = "the title of the document"
"type" = "string"
}
}
}
Run the PDP next to the gateway
The gateway calls a PDP for every request it authorizes. Run an Edge PDP in the same network as the gateway or proxy, so authorization requests don't leave your network and each check avoids a round trip to an external service. You can run the PDP container with Docker or a Helm chart. See Deploy the PDP to production.
You can connect the gateway to the PDP in two ways:
- Gateway plugin. The Permit PDP is built on Open Policy Agent (OPA), and it exposes an endpoint for the Kong OPA plugin at
/kong. The Kong OPA plugin has no configuration field for the headers it sends, so it can't send the PDP the API key the PDP requires, and the setup needs a reverse proxy between Kong and the PDP that adds the header. See Authorize Kong Gateway requests with Permit. - PDP HTTP API. For a custom gateway or proxy, or when you prefer a direct call, send the decision request to the PDP API. See Call the PDP API directly.
The PDP answers an authorization request without an Authorization: Bearer <API key> header with HTTP 401. Configure the gateway, or a proxy in front of the PDP, to send your environment API key (Get your API key) on every request to the PDP. Without the header, every request the gateway tries to authorize fails.
Filter response data
A gateway check returns allow or deny for the whole request. Data filtering returns only the objects the user can access, for example when a GET endpoint returns a list of documents. You can filter data in two ways:
- Filter with the Permit API. Call a data filtering method from the service behind the list endpoint, so the endpoint returns only allowed objects. This option works with your existing Permit policy. See Filter data by permission.
- Partial evaluation with custom Rego. Write custom Rego with the GitOps feature, and use OPA partial evaluation to generate a filter query from the policy. This option takes more development and maintenance.
For help with partial evaluation, ask in the Permit Slack community.