--- title: HTTP API Authorization kind: tutorial weight: 3 --- Anything that exposes an HTTP API (whether an individual microservice or an application as a whole) needs to control who can run those APIs and when. OPA makes it easy to write fine-grained, context-aware policies to implement API authorization. ## Goals In this tutorial, you'll use a simple HTTP web server that accepts any HTTP GET request that you issue and echoes the OPA decision back as text. Both OPA and the web server will be run as containers. For this tutorial, our desired policy is: * People can see their own salaries (`GET /finance/salary/{user}` is permitted for `{user}`) * A manager can see their direct reports' salaries (`GET /finance/salary/{user}` is permitted for `{user}`'s manager) ## Prerequisites This tutorial requires [Docker Compose](https://docs.docker.com/compose/install/) to run a demo web server along with OPA. ## Steps ### 1. Bootstrap the tutorial environment using Docker Compose. First, create a `docker-compose.yml` file that runs OPA and the demo web server. **docker-compose.yml**: ```yaml version: '2' services: opa: image: openpolicyagent/opa:{{< current_docker_version >}} ports: - 8181:8181 # WARNING: OPA is NOT running with an authorization policy configured. This # means that clients can read and write policies in OPA. If you are # deploying OPA in an insecure environment, be sure to configure # authentication and authorization on the daemon. See the Security page for # details: https://www.openpolicyagent.org/docs/security.html. command: - "run" - "--server" - "--log-level=debug" api_server: image: openpolicyagent/demo-restful-api:0.2 ports: - 5000:5000 environment: - OPA_ADDR=http://opa:8181 - POLICY_PATH=/v1/data/httpapi/authz ``` Then run `docker-compose` to pull and run the containers. ```shell docker-compose -f docker-compose.yml up ``` Every time the demo web server receives an HTTP request, it asks OPA to decide whether an HTTP API is authorized or not using a single RESTful API call. An example code is [here](https://github.com/open-policy-agent/contrib/blob/master/api_authz/docker/echo_server.py), but the crux of the (Python) code is shown below. ```python # Grab basic information. We assume user is passed on a form. http_api_user = request.form['user'] # Get the path as a list (removing leading and trailing /) # Example: "/finance/salary/" will become ["finance", "salary"] http_api_path_list = request.path.strip("/").split("/") input_dict = { # create input to hand to OPA "input": { "user": http_api_user, "path": http_api_path_list, # Ex: ["finance", "salary", "alice"] "method": request.method # HTTP verb, e.g. GET, POST, PUT, ... } } # ask OPA for a policy decision # (in reality OPA URL would be constructed from environment) rsp = requests.post("http://127.0.0.1:8181/v1/data/httpapi/authz", json=input_dict) if rsp.json()["allow"]: # HTTP API allowed else: # HTTP API denied ``` ### 2. Load a policy into OPA. In another terminal, create a policy that allows users to request their own salary as well as the salary of their direct subordinates. ```shell cat >example.rego <example-hr.rego <example.rego <, [header, payload, signature])`. Let's try a few queries (note: you may need to escape the `?` characters in the queries for your shell): Check that `charlie` can't see `bob`'s salary. ```shell curl --user charlie:password localhost:5000/finance/salary/bob?token=$CHARLIE_TOKEN ``` Check that `charlie` can't pretend to be `bob` to see `alice`'s salary. ```shell curl --user charlie:password localhost:5000/finance/salary/alice?token=$BOB_TOKEN ``` Check that `david` can see `betty`'s salary. ```shell curl --user david:password localhost:5000/finance/salary/betty?token=$DAVID_TOKEN ``` Check that `bob` can see `alice`'s salary. ```shell curl --user bob:password localhost:5000/finance/salary/alice?token=$BOB_TOKEN ``` Check that `alice` can see her own salary. ```shell curl --user alice:password localhost:5000/finance/salary/alice?token=$ALICE_TOKEN ``` ## Wrap Up Congratulations for finishing the tutorial! You learned a number of things about API authorization with OPA: * OPA gives you fine-grained policy control over APIs once you set up the server to ask OPA for authorization. * You write allow/deny policies to control which APIs can be executed by whom. * You can import external data into OPA and write policies that depend on that data. * You can use OPA data structures to define abstractions over your data. The code for this tutorial can be found in the [open-policy-agent/contrib](https://github.com/open-policy-agent/contrib) repository.