Represent your rego rules programmatically.


policy enforcer logo

Policy Enforcer

Policy enforcer is a open source tool that allows you to easily create complex authorization policy. Supports RBAC, ABAC and resource filtering based on them.

go version  go report  license  tweet  tweet

Features

  • Generate your complex authorization policy easily with code.
  • Export the rego (policy language for defining rules that are evaluated by the OPA engine) you created with the code.
  • Filter data based on your authorization logic.
  • Make decisions about multiple resources from one policy.
  • Get the details of the decisions made.
  • Add custom messages and handle decision messages.

👇 Setup

Install

go get github.com/Permify/policy-enforcer

Run Tests

go test

Import enforcer.

import enforcer `github.com/Permify/policy-enforcer`

🚀 Usage

var user = User{
    ID:   1,
    Roles:  []string{"admin"},
    Attributes: map[string]interface{}{
            "tenure": 8,
    },
}

blog := map[string]interface{}{
    "id":     1,
    "status": "PUBLIC",
}

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin").SetKey("is admin")
var isSenior = enforcer.NewRule("user.tenure > 8").SetFailMessage("user is not senior")
var isManager = enforcer.NewRule("'manager' in user.roles").SetFailMessage("user is not manager")
var isPublic = enforcer.NewRule("blog.status == 'PUBLIC'").SetFailMessage("blog is not public")

policy := enforcer.New()
    
// set user object
policy.Set("user", user)
policy.Set("blog", blog)

// its means the user must be either an admin or a senior manager or blog is public
policy.Option(isAdmin).Option(isSenior, isManager).Option(isPublic)

result, err := policy.IsAuthorized()

Output

{
    Allows: {
        {
            Allow: true // final result
        }, 	
    },
    Details: {
        {
            Allow: true, // is admin result
            Key: "is_admin", 
            Message: ""
        },
        {
            Allow: true,  // is senior result
            Key: "tcuaxhxkqfdafplsjfbc", // if the key is not set it is created automatically
            Message: ""
        },
        {
            Allow: true, // is public result
            Key: (string) (len=20) "lgtemapezqleqyhyzryw",
            Message: (string) ""
        },
        {
            Allow: false, // is manager result
            Key: "xoeffrswxpldnjobcsnv", // if the key is not set it is created automatically
            Message: "user is not manager"
        }
    }
}

🔗 Multiple Resource Response

You can check authorization of multiple resources at once.

example scenario

  • If the user is admin, can edit all listed resources. (Admin)
  • If the user owns the resource, they can only edit their own resources. (Resource Owner)

Admin

policy := enforcer.New()

policy.SetUser(enforcer.User{
    ID:    "1",
    Roles: []string{"admin"}, // admin
    Attributes: map[string]interface{}{
        "tenure": 9,
    },
})

policy.SetResources(
    enforcer.Resource{
        ID:   "1",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "1",
        },
    },
    enforcer.Resource{
        ID:   "2",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "2",
        },
    },
)

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin")
var isResourceOwner = enforcer.NewRule("resource.attributes.owner_id == '1'")

// its means the user must be either an admin or a resource owner
policy.Option(isAdmin).Option(isResourceOwner)

var r, err = policy.IsAuthorized()
{
    Allows: {
        {
            Allow: true, // its true because user is admin
            Meta: {
                "id": "1"
                "type": "posts",
            }
        },
        {
            Allow: true, // its true because user is admin
            Meta: {
                "id": "2",
                "type": "posts"
            }
        }
    },
    Details: {
        {
            Allow: true,
            Key: "lgtemapezqleqyhyzryw",
            Message: ""
        }
    }
}

Resource Owner

policy := New()

policy.SetUser(enforcer.User{
    ID:    "1",
    Roles: []string{"manager"},
    Attributes: map[string]interface{}{
        "tenure": 9,
    },
})

policy.SetResources(
    enforcer.Resource{
        ID:   "1",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "1",
        },
    },
    enforcer.Resource{
        ID:   "2",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "2",
        },
    },
)

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin")
var isResourceOwner = enforcer.NewRule("resource.attributes.owner_id == '1'")

// its means the user must be either an admin or a resource owner
policy.Option(isAdmin).Option(isResourceOwner)

var r, err = policy.IsAuthorized()

Output

{
    Allows: {
        {
            Allow: true, // its true because user is owner of the this resource
            Meta: {
                "id": "1"
                "type": "posts",
            }
        },
        {
            Allow: false, // its false because user is not owner of the this resource
            Meta: {
                "id": "2",
                "type": "posts"
            }
        }
    },
    Details: {
        {
            Allow: false,
            Key: "lgtemapezqleqyhyzryw",
            Message: "user is not an admin"
        }
    }
}

🍃 Data Filtering

Filter resources that match the rules you created

example scenario

  • User can only edit their own posts. Fetch all of the posts it can edit
policy := New()

policy.SetUser(enforcer.User{
    ID:    "1",
    Roles: []string{"manager"},
    Attributes: map[string]interface{}{
        "tenure": 9,
    },
})

policy.SetResources(
    enforcer.Resource{
        ID:   "1",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "1",
        },
    },
    enforcer.Resource{
        ID:   "2",
        Type: "posts",
        Attributes: map[string]interface{}{
            "owner_id": "2",
        },
    },
)

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin")
var isResourceOwner = enforcer.NewRule("resource.attributes.owner_id == '1'")

// its means the user must be either an admin or a resource owner
policy.Option(isAdmin).Option(isResourceOwner)

resources, err := policy.AuthorizedResources()

Output

{
    {
        ID: "1",
        Type: "posts",
        Attributes: {
            "owner_id": "1"
        }
    }
}

🚨 Create New Rule

the user should a manager role among their roles

var isManager = NewRule("'manager' in user.roles")

The user's tenure must be at least 8 years and the user should a manager role among their roles.

var isSeniorManager = NewRule("user.attributes.tenure > 8", "'manager' in user.roles")

The user is the owner of the resource or resources.

var isResourceOwner = NewRule("resource.attributes.owner.id == '1'")

⁉ī¸ Set Fail Message

After the set fail message function decides on the policy, if the rule is false, this message will be printed on the error

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin")

Output

Details: {
    {
        Allow: false, // result
        Key: "xoeffrswxpldnjobcsnv",
        Message: "user is not an admin" // when it fails the message will appear here
    },
}

🔑 Set Key

You can use it when you do not want the key to be generated automatically. This will allow you to perceive your details better.

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetKey("is admin").SetFailMessage("user is not an admin")

Output

Details: {
    {
        Allow: true, // result
        Key: "is_admin",
        Message: "" // when true, the message does not appear
    },
}

Options

Options allow you to establish an or relationship between rules and create a more organized and legible authorization structure.

// its means the user must be either an admin or a senior and manager
enforcer.Option(isAdmin).Option(isSenior, isManager)

To Rego Function

You can export the rego policies you created with the code with this function.

Example 1

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin").SetKey("is admin")
var isSenior = enforcer.NewRule("user.tenure > 8").SetFailMessage("user is not senior")
var isManager = enforcer.NewRule("'manager' in user.roles").SetFailMessage("user is not manager")

policy := enforcer.New()

// its means the user must be either an admin or a senior manager
policy.Option(isAdmin).Option(isSenior, isManager)

fmt.Println(policy.ToRego())

Output

package app.permify

import future.keywords.every

# imports

import input.user as user

default allow = false

# options

allow {
  is_admin
}

allow {
  tcuaxhxkqfdafplsjfbc
  xoeffrswxpldnjobcsnv
}

# rules

tcuaxhxkqfdafplsjfbc {
  user.attributes.tenure > 8
}

xoeffrswxpldnjobcsnv {
  "manager" in user.roles
}

is_admin {
  "admin" in user.roles
}

Example 2

policy := enforcer.New()

var isAdmin = enforcer.NewRule("'admin' in user.roles").SetFailMessage("user is not an admin")
var isResourceOwner = enforcer.NewRule("resource.attributes.owner_id == '1'")

// its means the user must be either an admin or a resource owner
policy.Option(isAdmin).Option(isResourceOwner)

fmt.Println(policy.ToRego())

Output

package app.permify

import future.keywords.every

# imports
import input.user as user
import input.resources as resources

# options

allows[output] {
    resource := resources[_]
    lgtemapezqleqyhyzryw
    output := {"id": resource.id, "type": resource.type}
}

allows[output] {
    resource := resources[_]
    jjpjzpfrfegmotafeths(resource)
    output := {"id": resource.id, "type": resource.type}
}

# rules

lgtemapezqleqyhyzryw {
    "admin" in user.roles
}

jjpjzpfrfegmotafeths(resource) {
    resource.attributes.owner_id == "1"
}

Iterator

You can review allow and meta with iterator.

result, err := policy.IsAuthorized()

for result.hasNext() {
    allow := result.getNext()
    fmt.Sprintf("is authorized: %s",  allow.Allow)
}

Validate

Validate your rules and debug.

err := NewRule("'admin i user.roles").Validate() // return error

Need More, Check Out our API

Permify API is an authorization API which you can add complex rbac and abac solutions.

❤ī¸ Let's get connected:

guilyx | Twitter guilyx's LinkdeIN guilyx's Discord

Owner
Permify
Permify is a plug-&-play authorization API that helps dev teams create granular access control and user management systems without breaking a sweat!
Permify
Similar Resources

Jenkins CLI allows you manage your Jenkins as an easy way

Quick start įŽ€äŊ“中文 Jenkins CLI Jenkins CLI allows you manage your Jenkins in an easy way. No matter if you're a plugin developer, administrator or just

Jan 4, 2023

Manage your ssh alias configs easily.

Manage your ssh alias configs easily.

manssh manssh is a command line tool for managing your ssh alias config easily, inspired by storm project, powered by Go. Note: This project is actual

Nov 9, 2022

grafana-sync Keep your grafana dashboards in sync.

grafana-sync Keep your grafana dashboards in sync. Table of Contents grafana-sync Table of Contents Installing Getting Started Pull Save all dashboard

Dec 14, 2022

k8s-image-swapper Mirror images into your own registry and swap image references automatically.

k8s-image-swapper Mirror images into your own registry and swap image references automatically.

k8s-image-swapper Mirror images into your own registry and swap image references automatically. k8s-image-swapper is a mutating webhook for Kubernetes

Dec 27, 2022

Easily run your Compose application to the cloud with compose-cli

This CLI tool makes it easy to run Docker containers and Docker Compose applications in the cloud using either Amazon Elastic Container Service (ECS) or Microsoft Azure Container Instances (ACI) using the Docker commands you already know.

Jan 8, 2023

đŸļ Kubernetes CLI To Manage Your Clusters In Style!

đŸļ Kubernetes CLI To Manage Your Clusters In Style!

K9s - Kubernetes CLI To Manage Your Clusters In Style! K9s provides a terminal UI to interact with your Kubernetes clusters. The aim of this project i

Jan 9, 2023

Open URL in your local web browser from the SSH-connected remote environment.

opener Open URL in your local web browser from the SSH-connected remote environment. How does opener work? opener is a daemon process that runs locall

Oct 20, 2022

Validation of best practices in your Kubernetes clusters

Validation of best practices in your Kubernetes clusters

Best Practices for Kubernetes Workload Configuration Fairwinds' Polaris keeps your clusters sailing smoothly. It runs a variety of checks to ensure th

Jan 9, 2023

🛅 Backup your Kubernetes Stateful Applications

Stash Stash by AppsCode is a cloud-native data backup and recovery solution for Kubernetes workloads. If you are running production workloads in Kuber

Jan 7, 2023
A small drunken bishop written in Go to represent bytes.

Go, Little Drunken Bishop! go get github.com/eloonstra/go-little-drunken-bishop Table of Contents How does it work? Usage Example License Contributin

Mar 13, 2022
Generate Prometheus rules for your SLOs

prometheus-slo Generates Prometheus rules for alerting on SLOs. Based on https://developers.soundcloud.com/blog/alerting-on-slos. Usage Build and Run

Nov 27, 2022
Library/tool to change a yaml given a rules file

golang-yaml-rules/yaml-transform Library/tool to change a yaml given a rules file Using jsonpath ( https://github.com/vmware-labs/yaml-jsonpath ), thi

Feb 11, 2022
Monitor your Website and APIs from your Computer. Get Notified through Slack, E-mail when your server is down or response time is more than expected.
Monitor your Website and APIs from your Computer. Get Notified through Slack, E-mail when your server is down or response time is more than expected.

StatusOK Monitor your Website and APIs from your computer.Get notified through Slack or E-mail when your server is down or response time is more than

Dec 27, 2022
Supporting your devops by shortening your strings using common abbreviations and clever guesswork

abbreviate Shorten your strings using common abbreviations. Supported by Tidelift Motivation This tool comes out of a frustration of the name of resou

Dec 14, 2022
💓 小įąŗ手įŽ¯åŽžæ—ļåŋƒįŽ‡æ•°æŽé‡‡é›† - Your Soul, Your Beats!

?? mebeats 小įąŗ手įŽ¯åŽžæ—ļåŋƒįŽ‡æ•°æŽé‡‡é›† - Your Soul, Your Beats! cmd/mebeats-client: the mebeats client. It collects the heart rate data from Mi Band and reports to s

Dec 31, 2022
Kusk makes your OpenAPI definition the source of truth for API resources in your cluster
Kusk makes your OpenAPI definition the source of truth for API resources in your cluster

Kusk - use OpenAPI to configure Kubernetes What is Kusk? Developers deploying their REST APIs in Kubernetes shouldn't have to worry about managing res

Dec 16, 2022
A shields.io API for your youtube channel to protect your api key
A shields.io API for your youtube channel to protect your api key

Youtube-Channel-Badge A shields.io API for your youtube channel to protect your

Dec 23, 2021
A simple download file manager that sorts your files into your desired folders, This was meant to be a small project and nothing big.

GoDFM Simply go to the tags and download the .exe file (or compile it yourself by running go build). Add it to your environment paths by going to sett

Aug 9, 2022
Enable your Go applications to self update

go-selfupdate Enable your Golang applications to self update. Inspired by Chrome based on Heroku's hk. Features Tested on Mac, Linux, Arm, and Windows

Jan 3, 2023