concourse/atc/policy/opa/opa.go

84 lines
2.3 KiB
Go

package opa
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc/policy"
)
type OpaConfig struct {
URL string `long:"opa-url" description:"OPA policy check endpoint."`
Timeout time.Duration `long:"opa-timeout" default:"5s" description:"OPA request timeout."`
ResultAllowedKey string `long:"opa-result-allowed-key" description:"Key name of if pass policy check in OPA returned result. Expects a boolean value." default:"result.allowed"`
ResultShouldBlockKey string `long:"opa-result-should-block-key" description:"Key name of if should block current action in OPA returned result. Expects a boolean value." default:"result.block"`
ResultMessagesKey string `long:"opa-result-messages-key" description:"Key name of messages in OPA returned result." default:"result.reasons"`
}
func init() {
policy.RegisterAgent(&OpaConfig{})
}
func (c *OpaConfig) Description() string { return "Open Policy Agent" }
func (c *OpaConfig) IsConfigured() bool { return c.URL != "" }
func (c *OpaConfig) NewAgent(logger lager.Logger) (policy.Agent, error) {
return opa{*c, logger}, nil
}
type opaInput struct {
Input policy.PolicyCheckInput `json:"input"`
}
type opa struct {
config OpaConfig
logger lager.Logger
}
func (c opa) Check(input policy.PolicyCheckInput) (policy.PolicyCheckResult, error) {
data := opaInput{input}
jsonBytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
c.logger.Debug("opa-check", lager.Data{"input": string(jsonBytes)})
req, err := http.NewRequest("POST", c.config.URL, bytes.NewBuffer(jsonBytes))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
client.Timeout = c.config.Timeout
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
statusCode := resp.StatusCode
if statusCode != http.StatusOK {
return nil, fmt.Errorf("opa returned status: %d", statusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("opa returned no response: %s", err.Error())
}
result, err := ParseOpaResult(body, c.config)
if err != nil {
return nil, fmt.Errorf("parsing opa results: %w", err)
}
return result, nil
}