github.com/chenbh/concourse/v6@v6.4.2/atc/policy/opa/opa.go (about) 1 package opa 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "time" 10 11 "code.cloudfoundry.org/lager" 12 13 "github.com/chenbh/concourse/v6/atc/policy" 14 ) 15 16 type OpaConfig struct { 17 URL string `long:"opa-url" description:"OPA policy check endpoint."` 18 Timeout time.Duration `long:"opa-timeout" default:"5s" description:"OPA request timeout."` 19 } 20 21 func init() { 22 policy.RegisterAgent(&OpaConfig{}) 23 } 24 25 func (c *OpaConfig) Description() string { return "Open Policy Agent" } 26 func (c *OpaConfig) IsConfigured() bool { return c.URL != "" } 27 28 func (c *OpaConfig) NewAgent(logger lager.Logger) (policy.Agent, error) { 29 return opa{*c, logger}, nil 30 } 31 32 type opaInput struct { 33 Input policy.PolicyCheckInput `json:"input"` 34 } 35 36 type opaResult struct { 37 Result *bool `json:"result,omitempty"` 38 } 39 40 type opa struct { 41 config OpaConfig 42 logger lager.Logger 43 } 44 45 func (c opa) Check(input policy.PolicyCheckInput) (bool, error) { 46 data := opaInput{input} 47 jsonBytes, err := json.Marshal(data) 48 if err != nil { 49 return false, err 50 } 51 52 c.logger.Debug("opa-check", lager.Data{"input": string(jsonBytes)}) 53 54 req, err := http.NewRequest("POST", c.config.URL, bytes.NewBuffer(jsonBytes)) 55 if err != nil { 56 return false, err 57 } 58 req.Header.Set("Content-Type", "application/json") 59 60 client := &http.Client{} 61 client.Timeout = c.config.Timeout 62 resp, err := client.Do(req) 63 if err != nil { 64 return false, err 65 } 66 defer resp.Body.Close() 67 68 statusCode := resp.StatusCode 69 if statusCode != http.StatusOK { 70 return false, fmt.Errorf("opa returned status: %d", statusCode) 71 } 72 73 body, err := ioutil.ReadAll(resp.Body) 74 if err != nil { 75 return false, fmt.Errorf("opa returned no response: %s", err.Error()) 76 } 77 78 result := &opaResult{} 79 err = json.Unmarshal(body, &result) 80 if err != nil { 81 return false, fmt.Errorf("opa returned bad response: %s", err.Error()) 82 } 83 84 // If no result returned, meaning that the requested policy decision is 85 // undefined OPA, then consider as pass. 86 if result.Result == nil { 87 return true, nil 88 } 89 90 return *result.Result, nil 91 }