Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Mathis Joffre <[email protected]>
  • Loading branch information
Joffref committed Aug 24, 2022
0 parents commit b7a9d4f
Show file tree
Hide file tree
Showing 16 changed files with 3,105 additions and 0 deletions.
94 changes: 94 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Go template
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

/.idea/vcs.xml
/.idea/.gitignore
/.idea/modules.xml
/.idea/opa-middleware.iml
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Open Policy Agent Gin Middleware

This middleware integrates Open Policy Agent (OPA) to your gin app.
You can use it to enforce policies on endpoints.
You can use OPA as local policy engine, or as a remote policy engine.

## Installation

```bash
go get github.com/Joffref/opa-middleware
```

## Usage
### Local policy engine
```go
package main

import (
"github.com/Joffref/gin-opa-middleware"
"github.com/gin-gonic/gin"
)

var policy = `
package example.authz
default allow := false
allow {
input.method == "GET"
}`

func main() {
r := gin.Default()
r.Use(opa.Middleware(context.Background(), &opa.Config{
Policy: policy,
Query: "data.example.authz.allow",
InputCreationMethod: func(c *gin.Context) (map[string]interface{}, error) {
return map[string]interface{}{
"method": c.Request.Method,
}, nil
},
ExceptedResult: true,
DeniedStatusCode: 403,
Debug: true,
Logger: log.New(gin.DefaultWriter, "[opa] ", log.LstdFlags),
}))
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello World!")
})
r.Run()
}
```
### Remote policy engine
```go
package main

import (
"github.com/Joffref/gin-opa-middleware"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(opa.Middleware(context.Background(), &opa.Config{
URL: "http://localhost:8181",
Query: "data.example.authz.allow",
InputCreationMethod: func(c *gin.Context) (map[string]interface{}, error) {
return map[string]interface{}{
"method": c.Request.Method,
}, nil
},
ExceptedResult: true,
DeniedStatusCode: 403,
Debug: true,
Logger: log.New(gin.DefaultWriter, "[opa] ", log.LstdFlags),
}))
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello World!")
})
err := r.Run(":8080")
if err != nil {
return
}
}
```
84 changes: 84 additions & 0 deletions config/base_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package config

import (
"errors"
"github.com/open-policy-agent/opa/rego"
"log"
"net/http"
"time"
)

// Config is the configuration for the middleware.
type Config struct {
// URL is the URL of the OPA server, if not set Middleware will use Policy field.
// You must set either URL or Policy.
URL string `json:"url,omitempty"`

// Policy is the policy document to use, if not set Middleware will use URL field.
// You must set either URL or Policy.
Policy string `json:"policy,omitempty"`

instantiatedPolicy *rego.PreparedEvalQuery

// Query is the name of the policy to query.
Query string `json:"query,omitempty"`

// InputCreationMethod is a function that returns the value to be sent to the OPA server.
InputCreationMethod func(r *http.Request) (map[string]interface{}, error) `json:"binding_method,omitempty"`

// ExceptedResult is the result that the OPA server should return if the request is allowed.
// Default to true. At the moment only boolean values are supported.
ExceptedResult bool `json:"excepted_result,omitempty"`

// DeniedStatusCode is the status code that should be returned if the request is denied.
DeniedStatusCode int `json:"denied_status,omitempty"`

// DeniedMessage is the message that should be returned if the request is denied.
DeniedMessage string `json:"denied_message,omitempty"`

// Headers is a list of headers to send to the OPA server.
// All headers are sent to the OPA server except those in the IgnoredHeaders list.
Headers map[string]string `json:"headers,omitempty"`

// IgnoredHeaders is a list of headers to ignore when sending to the OPA server.
IgnoredHeaders []string `json:"excepted_headers,omitempty"`

// Debug is a flag that enables debug mode.
Debug bool `json:"debug,omitempty"`

// Logger is the logger that is use when debug mode is enabled.
// If not set, the default logger is used.
Logger *log.Logger `json:"logger,omitempty"`

// Timeout is the timeout for the request policy evaluation.
// If not set, the default is 10 seconds.
Timeout time.Duration `json:"timeout,omitempty"`
}

func (c *Config) Validate() error {
if c.Debug {
if c.Logger == nil {
c.Logger = log.Default()
}
}
c.ExceptedResult = true
if c.Timeout == 0 {
c.Timeout = 10 * time.Second
}
if c.URL == "" && c.Policy == "" {
return errors.New("[opa-middleware] You must set either URL or Policy")
}
if c.URL != "" && c.Policy != "" {
return errors.New("[opa-middleware] You must set either URL or Policy")
}
if c.InputCreationMethod == nil {
return errors.New("[opa-middleware] You must set BindingMethod")
}
if c.ExceptedResult != true && c.ExceptedResult != false {
return errors.New("[opa-middleware] You must set ExceptedResult")
}
if c.Query == "" {
return errors.New("[opa-middleware] You must set Query")
}
return nil
}
Loading

0 comments on commit b7a9d4f

Please sign in to comment.