The most flexible policy engine in the world
Tags: authz, zerotrust, aws, sso
Published: 2023-06-10 17:46:00

Today we’re excited to announce our custom policy integration. This allows you to extend our policy language with an API call to one of your systems, allowing you to code up any policy logic you’d like.

[This post was originally published on the Border0.com blog here](https://www.border0.com/blogs/the-most-flexible-policy-engine-in-the-world)

Policies are the center of controlling who should have access to your services. So it makes sense we provide Border0 administrators with a flexible Policy engine, one that allows you to express your typical use cases. Out of the box, we enable admins to write policies that allow you to make decisions based on the user’s Identity, IP range, country, Time of Day, and date range. And with the recently added PagerDuty integration, you can now even include PagerDuty-specific rules, such as only allowing access to users who are on-call or when there’s an incident.‍

While we’d love to be able to support all of the use cases we hear you ask about, there will always be cases that are unique to a single customer. Or cases where a policy decision needs to be made based on data that are proprietary and not accessible to our policy engine. Today we solve that!‍

{% embed https://www.youtube.com/watch?v=l8xs3Fu--jY %}
_Tl;dr .. Don’t like reading blog articles… just watch the video demo!_

## Limitless possibilities

Imagine the policies you could build if you weren’t limited by a vendor’s policy language. You could build policies like The “Weather Condition” Policy: If the user’s location (based on IP address) is currently experiencing rain, allow access. If it’s not raining, you should probably be outside enjoying the sun! Or how about the “Friday Rule” Policy: Deny access to all SSH and Database services on Fridays, as a way to enforce the no “deployments on Fridays” rule. Or maybe the “Celestial Event” Policy, where You’d deny access during certain celestial events such as full moon, meteor showers, or solar eclipses.

‍
Alright, these are kinda silly, but imagine, what if it would be possible?! Literally, any policy you can dream up! That would unleash some really powerful access policies.

‍
So that’s exactly what we did with the “HTTP policy integration”. We’ve extended the Border0 policy language to call any 3rd party HTTP API. Based on the HTTP response code or the content in the returned JSON, you can decide whether a policy passes or not and thus, whether a user should be allowed access.



## Extend policies to evaluate your data in real-time.

You can now create your own policy integration, all based on your data and logic. Some more realistic custom policy examples could be a “Compliance” Policy: Deny access if the user has not completed mandatory compliance training. This is crucial in regulated industries. Or the “Business Hours” Policy: Allow access only during official business hours as defined by the organization’s HR system and based on the user’s current location. This helps maintain a healthy work-life balance for employees. Or the “PTO” Policy: Deny access if the HR system marks the employee on vacation or leave.

Again, as you can see, we’re only limited by our own imagination and ability to query your systems.



![Policy flow using your custom API for policy decisions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jrdlneyoj1z3b9vphom.png)

## Let’s build an example

Now that we have explored a few ideas, let’s go ahead and build an example and see how easy it is to extend the policy logic to include data from 3rd party systems. For this example, I’ve built a simple Python Flask example API service; you can find the code here on GitHub: [https://github.com/borderzero/examples/tree/main/policy-integrations](https://github.com/borderzero/examples/tree/main/policy-integrations)

Our example has a few example endpoints, all meant as simple examples to learn from and for inspiration.‍

🌐 /businesshours
🌐 /fridayrule
🌐 /random
🌐 /rainorshine


We’ll use the [Friday Rule ](https://github.com/borderzero/examples/blob/main/policy-integrations/app.py#L18) as a simple example to walk you through. Though a simple example, it demonstrates how to read the request from the Border0 Policy engine API, call a 3rd party system, parse the results, apply some logic, and return the verdict.

‍
```
@app.route('/fridayrule', methods=['POST'])
def friday_rule_policy():
  auth_request()
  current_day = None
  try:
    data = request.json
    ip = data['ip']
    tz_info = get_timezone(ip)
    current_day = datetime.now(pytz.timezone(tz_info['timezone'])).weekday()
    app.logger.info(f"Current day: {current_day}")
  except Exception as e:
    app.logger.error(f"Error occurred: {str(e)}")
    return jsonify({'error': str(e)}), 400

  if current_day == 4:  # 0 is Monday, 4 is Friday  
    return jsonify({"current_day": current_day}), 401
  else:
    return jsonify({"current_day": current_day}), 200‍
```

Let’s briefly walk through this code together: The endpoint listens on /fridayrule and expects a POST request. We do a quick authentication check to ensure this request comes from the Border0 system by checking for a value in the header. The code then parses the posted JSON, which contains the relevant information for the user’s access request. Now we have access to the user’s IP addresses from which the user is trying to access the resource. Optionally, if we configure the post body in the integration to submit more data, we can also have access to the users identity (email), the the protocol field defines the type of resource, and socket id and name.

‍

Next, we call a 3rd party API in the get_timezone() function. This function callshttp://ip-api.com/json/{ip} and returns Geo IP data for the IP, including the timezone. We then parse that time zone and determine what day it is based on the user’s time zone. Finally, we check if it’s Friday; if so, we return a 401 HTTP response, indicating that access is denied. Otherwise, we’ll return a 200 HTTP code, indicating all went well and access is allowed.

‍

Now that we have some code, we need to run it somewhere. I like fly.io or replit.com, but anything that exposes this service on a public URL will do.

‍

Next, it’s time to configure Border0 to use this custom policy engine. We’ll go to the integrations tab in the organization settings to do so. From there, we can add the HTTP Policy integration and configure it accordingly.


![Configure the policy to use our custom API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyhj9v9r2gon6muylzdv.png)
‍

As you can see, we configured the HTTP URL of our newly created API and configured it as a POST request. Make sure to set the headers correctly; this is where we set the auth secret (optional).
Finally, we get to configure what the Body should look like. Note how this is all customizable and how you can include variables like the user’s email address, the IP address, the protocol, the socket id, and socket name.‍

Configuring the policy.

Now that the integration is configured, we can call it from any of your policies. In my example, I’ll update my default policy and include the newly created integration to the policy.‍


![require HTTP 200 response, and match a ‘jq’ expression](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4zb86s6o4cgd0e7sna1.png)

‍Note that you can specify the expected HTTP response code; the policy will return True if the returned HTTP code is the same as specified here. Administrators may also set a body expression evaluation using the jq language to evaluate the returned JSON. In this case, I’ve added both for demonstration purposes. Administrators may use both but should use at least one of these.

‍
When we call our newly created API manually, we can see that in this example, the API returns a JSON like this with a 200 response code:

```
$ curl -X POST \
   -H "Authorization: superSecret" \
   -H "Content-Type: application/json" \
   -d '{"ip":"24.80.188.202","user":"andree@border0.com","protocol":"ssh"}' \
   https://bitter-mountain-2383.fly.dev/fridayrule
   
{
  "current_day": 3
}
```

‍As visible in the JSON, the current day is returned as 3, which means Thursday. So, in this case, the require_body_repose_code jq expression will return true as the current day is not equal to 4 (which means Friday). With this, we achieved our objective to allow access on any day except Fridays.

‍
To test the evaluation manually, we can use curl and jq. In this example, the expression returns true since it’s not Friday.
```
$ curl -sq -X POST \
   -H "Authorization: superSecret" \
   -H "Content-Type: application/json" \
   -d '{"ip":"24.80.188.202","user":"andree@border0.com","protocol":"ssh"}' \
   https://bitter-mountain-2383.fly.dev/fridayrule |  jq '.current_day != 4'
   
true
```

## Wrap up

In this post, we saw how Border0 administrators can easily extend the Border0 policy engine to evaluate custom data sources with their own logic. With this, we’ve allowed admins to build true fine-grained access policies that meet their exact needs. As a bonus, multiple policy integration can be chained together in a single policy, allowing for further flexibility.‍

We looked at a simple API example that evaluated the users’ time zone and determined the current day of the week, which was used to decide whether it was Friday and if the user should be allowed in. Since it’s all built on well-understood primitives, i.e., a simple HTTP API call, it should be easy for folks to start building custom policy integrations.‍

We’re excited about the potential and can’t wait to hear what awesome policies you will build with this. Let us know what you’re building, [check out the docs](https://docs.border0.com/docs/the-generic-http-api-integration), or as always, feel free to reach out for assistance; we’d love to help you get started.



The Policy integration feature is available for both free and Premium accounts, so sign up today and give it a spin! Try out our [fully featured free community edition](https://portal.border0.com/register), or [schedule a demo ](https://www.border0.com/contact-us) and let us walk you through a custom demo; let’s geek out together 🤓