diff --git a/cmd/config-current.go b/cmd/config-current.go index 723e24487..3b6f29cfa 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -30,7 +30,7 @@ import ( "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event/target" - "github.com/minio/minio/pkg/iam/policy" + iampolicy "github.com/minio/minio/pkg/iam/policy" "github.com/minio/minio/pkg/iam/validator" xnet "github.com/minio/minio/pkg/net" ) @@ -284,13 +284,24 @@ func (s *serverConfig) loadFromEnvs() { if u, err := xnet.ParseURL(jwksURL); err == nil { s.OpenID.JWKS.URL = u logger.FatalIf(s.OpenID.JWKS.PopulatePublicKey(), "Unable to populate public key from JWKS URL") + } else { + logger.FatalIf(err, "Unable to parse MINIO_IAM_JWKS_URL %s", jwksURL) } } if opaURL, ok := os.LookupEnv("MINIO_IAM_OPA_URL"); ok { if u, err := xnet.ParseURL(opaURL); err == nil { - s.Policy.OPA.URL = u - s.Policy.OPA.AuthToken = os.Getenv("MINIO_IAM_OPA_AUTHTOKEN") + opaArgs := iampolicy.OpaArgs{ + URL: u, + AuthToken: os.Getenv("MINIO_IAM_OPA_AUTHTOKEN"), + Transport: NewCustomHTTPTransport(), + CloseRespFn: xhttp.DrainBody, + } + s.Policy.OPA.URL = opaArgs.URL + s.Policy.OPA.AuthToken = opaArgs.AuthToken + logger.FatalIf(opaArgs.Validate(), "Unable to reach MINIO_IAM_OPA_URL %s", opaURL) + } else { + logger.FatalIf(err, "Unable to parse MINIO_IAM_OPA_URL %s", opaURL) } } } diff --git a/cmd/iam.go b/cmd/iam.go index 38eaa3cf4..1929db35e 100644 --- a/cmd/iam.go +++ b/cmd/iam.go @@ -1236,7 +1236,11 @@ func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool { func (sys *IAMSys) IsAllowed(args iampolicy.Args) bool { // If opa is configured, use OPA always. if globalPolicyOPA != nil { - return globalPolicyOPA.IsAllowed(args) + ok, err := globalPolicyOPA.IsAllowed(args) + if err != nil { + logger.LogIf(context.Background(), err) + } + return ok } // With claims set, we should do STS related checks and validation. diff --git a/pkg/iam/policy/opa.go b/pkg/iam/policy/opa.go index 49c4d41cb..8fe4dd879 100644 --- a/pkg/iam/policy/opa.go +++ b/pkg/iam/policy/opa.go @@ -37,6 +37,23 @@ type OpaArgs struct { // Validate - validate opa configuration params. func (a *OpaArgs) Validate() error { + req, err := http.NewRequest("POST", a.URL.String(), bytes.NewReader([]byte(""))) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + if a.AuthToken != "" { + req.Header.Set("Authorization", a.AuthToken) + } + + client := &http.Client{Transport: a.Transport} + resp, err := client.Do(req) + if err != nil { + return err + } + defer a.CloseRespFn(resp.Body) + return nil } @@ -92,9 +109,9 @@ func NewOpa(args OpaArgs) *Opa { } // IsAllowed - checks given policy args is allowed to continue the REST API. -func (o *Opa) IsAllowed(args Args) bool { +func (o *Opa) IsAllowed(args Args) (bool, error) { if o == nil { - return false + return false, nil } // OPA input @@ -103,12 +120,12 @@ func (o *Opa) IsAllowed(args Args) bool { inputBytes, err := json.Marshal(body) if err != nil { - return false + return false, err } req, err := http.NewRequest("POST", o.args.URL.String(), bytes.NewReader(inputBytes)) if err != nil { - return false + return false, err } req.Header.Set("Content-Type", "application/json") @@ -118,14 +135,14 @@ func (o *Opa) IsAllowed(args Args) bool { resp, err := o.client.Do(req) if err != nil { - return false + return false, err } defer o.args.CloseRespFn(resp.Body) // Read the body to be saved later. opaRespBytes, err := ioutil.ReadAll(resp.Body) if err != nil { - return false + return false, err } // Handle large OPA responses when OPA URL is of @@ -149,9 +166,9 @@ func (o *Opa) IsAllowed(args Args) bool { respBody.Seek(0, 0) var resultAllow opaResultAllow if err = json.NewDecoder(respBody).Decode(&resultAllow); err != nil { - return false + return false, err } - return resultAllow.Result.Allow + return resultAllow.Result.Allow, nil } - return result.Result + return result.Result, nil }