brewOPA

package module
v0.0.0-...-9a2bf68 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2022 License: Apache-2.0 Imports: 9 Imported by: 0

README

brewOPA logo

brewopa.org

brewOPA is an extensible open-source framework that enables developers to easily brew data access control policies for Open Policy Agent (OPA) by writing them in the human-friendly YAML.

Usage

Instantiate the validator with the brewOPA rego module.

validator, err := brewOPA.NewValidatorFromRego("../rego/brewOPA.rego")
if err != nil {
        fmt.Print("failed to create validator: %v", err)
}

Configure the validator with one or more data access policies.

data, err := ioutil.ReadFile("../rego/sample_data/policy.yaml")
if err != nil {
        fmt.Printf("failed to decode yaml: %v", err)
        return
}

policy, err := brewOPA.AccessPolicyFromYAML(data)
if err != nil {
        fmt.Print("failed to create access policy from YAML: %v", err)
        return
}

err = validator.AddPolicy("myPolicy", policy)
if err != nil {
        fmt.Printf("failed to add policy")
        return
}

Create and validate accesses to data.

access := brewOPA.NewAccess("invoices", "bob", 10, brewOPA.AccessTypeRead,
        brewOPA.TablesReferenced([]string{"finance.cards"}),
        brewOPA.ColumnsReferenced(map[string][]string{
                "finance.cards": []string{"card_number", "credit_limit"},
        }),
)

result, err := validator.Validate(context.Background(), access)
if err != nil {
        fmt.Printf("failed to validate access: %v", err)
        return
}

Access control via OPA REST APIs

Start OPA as a service (listening on port 8181 by default)

opa run -s

Create the access policy module

curl localhost:8181/v1/policies/brewOPA \
    -X PUT \
    -H "Content-Type: text/plain" \
    --data-binary @rego/brewOPA.rego

Deposit access policy to the namespace policies/:policyID Here, we deposit JSON (generated from the YAML using yq) because OPA's REST API doesn't support YAML.

curl localhost:8181/v1/data/policies/myPolicy \
    -X PUT \
    -H "Content-Type: text/plain" \
    -d '{
        "sensitiveAttrs": ["card_number", "credit_limit", "card_family"],
        "locations": [
            {
                "repo": "invoices",
                "schema": "finance",
                "table": "cards"
            }
        ],
        "rules": [
            {
                "deletes": {
                    "allow": true,
                    "rows": 1
                },
                "identities": ["bob"],
                "reads": {
                    "allow": true,
                    "attributes": ["credit_limit", "card_family"],
                    "rows": 10
                },
                "updates": {
                    "allow": true,
                    "attributes": ["credit_limit"],
                    "rows": 1
                }
            }
        ],
        "defaultRule": {
            "deletes": {
                "allow": false
            },
            "reads": {
                "allow": true,
                "attributes": "any",
                "rows": 1
            },
            "updates": {
                "allow": false
            }
        }
    }'

Query the access policy module providing data access parameters as input

curl localhost:8181/v1/data/dbAccess/main\?pretty\=true \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "input": {
            "user": "bob",
            "repo": "clinics",
            "accessType": "SELECT",
            "tablesReferenced": ["finance.cards"],
            "columnsReferenced": {
                "finance.cards": ["cust_id", "card_number", "credit_limit"]
            },
            "rowsAffected": 10
        }
    }'

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Access

type Access struct {
	Repository        string              `json:"repo"`
	User              string              `json:"user"`
	AccessType        AccessType          `json:"accessType"`
	RowsAffected      int64               `json:"rowsAffected"`
	TablesReferenced  []string            `json:"tablesReferenced,omitempty"`
	TablesUpdated     []string            `json:"tablesUpdated,omitempty"`
	TablesDeleted     []string            `json:"tablesDeleted,omitempty"`
	ColumnsReferenced map[string][]string `json:"columnsReferenced,omitempty"`
	ColumnsUpdated    map[string][]string `json:"columnsUpdated,omitempty"`
}

func NewAccess

func NewAccess(repository, user string,
	rowsAffected int64,
	accessType AccessType,
	opts ...AccessOption) Access

type AccessOption

type AccessOption func(*Access)

func ColumnsReferenced

func ColumnsReferenced(c map[string][]string) AccessOption

func ColumnsUpdated

func ColumnsUpdated(c map[string][]string) AccessOption

func TablesDeleted

func TablesDeleted(t []string) AccessOption

func TablesReferenced

func TablesReferenced(t []string) AccessOption

func TablesUpdated

func TablesUpdated(t []string) AccessOption

type AccessPolicy

type AccessPolicy struct {
	SensitiveAttributes []string       `json:"sensitiveAttrs" yaml:"sensitiveAttrs"`
	Locations           []DataLocation `json:"locations" yaml:"locations"`
	Rules               []Rule         `json:"rules" yaml:"rules"`
	DefaultRule         Rule           `json:"defaultRule" yaml:"defaultRule"`
}

func AccessPolicyFromYAML

func AccessPolicyFromYAML(policyYAML []byte) (AccessPolicy, error)

type AccessType

type AccessType int
const (
	AccessTypeRead AccessType = iota
	AccessTypeUpdate
	AccessTypeDelete
)

func (AccessType) String

func (a AccessType) String() string

type ContextedRule

type ContextedRule struct {
	Allow      bool     `json:"allow" yaml:"allow"`
	Rows       int64    `json:"rows" yaml:"rows"`
	Attributes []string `json:"attributes" yaml:"attributes"`
}

type DataLocation

type DataLocation struct {
	Repo   string `json:"repo" yaml:"repo"`
	Schema string `json:"schema" yaml:"schema"`
	Table  string `json:"table" yaml:"table"`
}

type EvaluatedRule

type EvaluatedRule struct {
	Violated      bool          `json:"violated"`
	ContextedRule ContextedRule `json:"contextedRule"`
}

EvaluatedRule contains a contexted rule applied to a table and whether or not it was violated.

type Result

type Result struct {
	Pass   bool                  `json:"pass"`
	Tables map[string]*TableRule `json:"tables"`
}

Result is the outcome of an access validation.

type Rule

type Rule struct {
	Identities []string      `json:"identities" yaml:"identities"`
	Reads      ContextedRule `json:"reads" yaml:"reads"`
	Updates    ContextedRule `json:"updates" yaml:"updates"`
	Deletes    ContextedRule `json:"deletes" yaml:"deletes"`
}

type TableRule

type TableRule struct {
	PolicyDefined bool                      `json:"policyDefined"`
	RulesApplied  map[string]*EvaluatedRule `json:"rulesApplied"`
}

TableRule details the contexted rules applied for a table during validation of an access.

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

func NewValidator

func NewValidator(regoModule []byte) (*Validator, error)

func NewValidatorFromRego

func NewValidatorFromRego(regoModulePath string) (*Validator, error)

NewValidatorFromRego returns a Validator initalized with the rego policy at the given file path as well as stored policy data. TODO: This should return an interface rather than a pointer to a struct.

Have it return QueryLogEvaluator for the moment...

func (*Validator) AddPolicy

func (v *Validator) AddPolicy(policyID string, policy AccessPolicy) error

func (*Validator) Validate

func (v *Validator) Validate(ctx context.Context, a Access) (*Result, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL