diff --git a/cmd/config-current.go b/cmd/config-current.go index 47d37fc98..503324319 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -374,8 +374,7 @@ func validateSubSysConfig(s config.Config, subSys string, objAPI ObjectLayer) er subSys = config.PolicyPluginSubSys fallthrough case config.PolicyPluginSubSys: - if ppargs, err := polplugin.LookupConfig(s[config.PolicyPluginSubSys][config.Default], - NewHTTPTransport(), xhttp.DrainBody); err != nil { + if ppargs, err := polplugin.LookupConfig(s, GetDefaultConnSettings(), xhttp.DrainBody); err != nil { return err } else if ppargs.URL == nil { // Check if legacy opa is configured. diff --git a/cmd/iam.go b/cmd/iam.go index 9aa470c11..3581f37a2 100644 --- a/cmd/iam.go +++ b/cmd/iam.go @@ -233,8 +233,7 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer, etcdClient *etc setGlobalAuthNPlugin(idplugin.New(authNPluginCfg)) - authZPluginCfg, err := polplugin.LookupConfig(s[config.PolicyPluginSubSys][config.Default], - NewHTTPTransport(), xhttp.DrainBody) + authZPluginCfg, err := polplugin.LookupConfig(s, GetDefaultConnSettings(), xhttp.DrainBody) if err != nil { logger.LogIf(ctx, fmt.Errorf("Unable to initialize AuthZPlugin: %w", err)) } diff --git a/cmd/utils.go b/cmd/utils.go index 356d4a47c..e90d4e972 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -568,6 +568,15 @@ func ToS3ETag(etag string) string { return etag } +// GetDefaultConnSettings returns default HTTP connection settings. +func GetDefaultConnSettings() xhttp.ConnSettings { + return xhttp.ConnSettings{ + DNSCache: globalDNSCache, + DialTimeout: rest.DefaultTimeout, + RootCAs: globalRootCAs, + } +} + // NewInternodeHTTPTransport returns a transport for internode MinIO // connections. func NewInternodeHTTPTransport() func() http.RoundTripper { diff --git a/docs/iam/access-management-plugin.md b/docs/iam/access-management-plugin.md index abba4d2d8..f18b1e11c 100644 --- a/docs/iam/access-management-plugin.md +++ b/docs/iam/access-management-plugin.md @@ -46,16 +46,19 @@ Only the last operation would fail with a permissions error. Access Management Plugin can be configured with environment variables: ```sh -$ mc admin config set dminio1 policy_plugin --env +$ mc admin config set myminio policy_plugin --env KEY: policy_plugin enable Access Management Plugin for policy enforcement ARGS: -MINIO_POLICY_PLUGIN_URL* (url) plugin hook endpoint (HTTP(S)) e.g. "http://localhost:8181/v1/data/httpapi/authz/allow" -MINIO_POLICY_PLUGIN_AUTH_TOKEN (string) authorization token for plugin hook endpoint -MINIO_POLICY_PLUGIN_COMMENT (sentence) optionally add a comment to this setting +MINIO_POLICY_PLUGIN_URL* (url) plugin hook endpoint (HTTP(S)) e.g. "http://localhost:8181/v1/data/httpapi/authz/allow" +MINIO_POLICY_PLUGIN_AUTH_TOKEN (string) authorization header for plugin hook endpoint +MINIO_POLICY_PLUGIN_ENABLE_HTTP2 (bool) Enable experimental HTTP2 support to connect to plugin service (default: 'off') +MINIO_POLICY_PLUGIN_COMMENT (sentence) optionally add a comment to this setting ``` +By default this plugin uses HTTP 1.x. To enable HTTP2 use the `MINIO_POLICY_PLUGIN_ENABLE_HTTP2` environment variable. + ## Request and Response MinIO will make a `POST` request with a JSON body to the given plugin URL. If the auth token parameter is set, it will be sent as an authorization header. diff --git a/docs/iam/access-manager-plugin.go b/docs/iam/access-manager-plugin.go index 5ff914b76..fe818af75 100644 --- a/docs/iam/access-manager-plugin.go +++ b/docs/iam/access-manager-plugin.go @@ -22,6 +22,7 @@ package main import ( "encoding/json" + "flag" "fmt" "io" "log" @@ -29,6 +30,16 @@ import ( "strings" ) +var ( + keyFile string + certFile string +) + +func init() { + flag.StringVar(&keyFile, "key-file", "", "Path to TLS cert key file") + flag.StringVar(&certFile, "cert-file", "", "Path to TLS cert file") +} + func writeErrorResponse(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ @@ -77,8 +88,22 @@ func mainHandler(w http.ResponseWriter, r *http.Request) { } func main() { + flag.Parse() + serveFunc := func() error { + return http.ListenAndServe(":8080", nil) + } + + if certFile != "" || keyFile != "" { + if certFile == "" || keyFile == "" { + log.Fatal("Please provide both a key file and a cert file to enable TLS.") + } + serveFunc = func() error { + return http.ListenAndServeTLS(":8080", certFile, keyFile, nil) + } + } + http.HandleFunc("/", mainHandler) log.Print("Listening on :8080") - log.Fatal(http.ListenAndServe(":8080", nil)) + log.Fatal(serveFunc()) } diff --git a/internal/config/config.go b/internal/config/config.go index 73c7d210f..7ad90f4d2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1076,7 +1076,7 @@ func getEnvVarName(subSys, target, param string) string { Default, target) } -var resolvableSubsystems = set.CreateStringSet(IdentityOpenIDSubSys, IdentityLDAPSubSys) +var resolvableSubsystems = set.CreateStringSet(IdentityOpenIDSubSys, IdentityLDAPSubSys, PolicyPluginSubSys) // ValueSource represents the source of a config parameter value. type ValueSource uint8 diff --git a/internal/config/policy/plugin/config.go b/internal/config/policy/plugin/config.go index 3f0673fe0..078248f07 100644 --- a/internal/config/policy/plugin/config.go +++ b/internal/config/policy/plugin/config.go @@ -22,20 +22,23 @@ import ( "encoding/json" "io" "net/http" + "time" "github.com/minio/minio/internal/config" - "github.com/minio/pkg/env" + xhttp "github.com/minio/minio/internal/http" iampolicy "github.com/minio/pkg/iam/policy" xnet "github.com/minio/pkg/net" ) // Authorization Plugin config and env variables const ( - URL = "url" - AuthToken = "auth_token" + URL = "url" + AuthToken = "auth_token" + EnableHTTP2 = "enable_http2" - EnvPolicyPluginURL = "MINIO_POLICY_PLUGIN_URL" - EnvPolicyPluginAuthToken = "MINIO_POLICY_PLUGIN_AUTH_TOKEN" + EnvPolicyPluginURL = "MINIO_POLICY_PLUGIN_URL" + EnvPolicyPluginAuthToken = "MINIO_POLICY_PLUGIN_AUTH_TOKEN" + EnvPolicyPluginEnableHTTP2 = "MINIO_POLICY_PLUGIN_ENABLE_HTTP2" ) // DefaultKVS - default config for Authz plugin config @@ -49,10 +52,14 @@ var ( Key: AuthToken, Value: "", }, + config.KV{ + Key: EnableHTTP2, + Value: "off", + }, } ) -// Args opa general purpose policy engine configuration. +// Args for general purpose policy engine configuration. type Args struct { URL *xnet.URL `json:"url"` AuthToken string `json:"authToken"` @@ -114,27 +121,43 @@ func Enabled(kvs config.KVS) bool { } // LookupConfig lookup AuthZPlugin from config, override with any ENVs. -func LookupConfig(kv config.KVS, transport *http.Transport, closeRespFn func(io.ReadCloser)) (Args, error) { +func LookupConfig(s config.Config, httpSettings xhttp.ConnSettings, closeRespFn func(io.ReadCloser)) (Args, error) { args := Args{} - if err := config.CheckValidKeys(config.PolicyPluginSubSys, kv, DefaultKVS); err != nil { + if err := s.CheckValidKeys(config.PolicyPluginSubSys, nil); err != nil { return args, err } - pluginURL := env.Get(EnvPolicyPluginURL, kv.Get(URL)) + getCfg := func(cfgParam string) string { + // As parameters are already validated, we skip checking + // if the config param was found. + val, _ := s.ResolveConfigParam(config.PolicyPluginSubSys, config.Default, cfgParam) + return val + } + + pluginURL := getCfg(URL) if pluginURL == "" { return args, nil } - authToken := env.Get(EnvPolicyPluginAuthToken, kv.Get(AuthToken)) - u, err := xnet.ParseHTTPURL(pluginURL) if err != nil { return args, err } + + enableHTTP2 := false + if v := getCfg(EnableHTTP2); v != "" { + enableHTTP2, err = config.ParseBool(v) + if err != nil { + return args, err + } + } + httpSettings.EnableHTTP2 = enableHTTP2 + transport := httpSettings.NewHTTPTransportWithTimeout(time.Minute) + args = Args{ URL: u, - AuthToken: authToken, + AuthToken: getCfg(AuthToken), Transport: transport, CloseRespFn: closeRespFn, } diff --git a/internal/config/policy/plugin/help.go b/internal/config/policy/plugin/help.go index 1f27e30be..d71872c0c 100644 --- a/internal/config/policy/plugin/help.go +++ b/internal/config/policy/plugin/help.go @@ -34,11 +34,17 @@ var ( }, config.HelpKV{ Key: AuthToken, - Description: "authorization token for plugin hook endpoint" + defaultHelpPostfix(AuthToken), + Description: "authorization header for plugin hook endpoint" + defaultHelpPostfix(AuthToken), Optional: true, Type: "string", Sensitive: true, }, + config.HelpKV{ + Key: EnableHTTP2, + Description: "Enable experimental HTTP2 support to connect to plugin service" + defaultHelpPostfix(EnableHTTP2), + Optional: true, + Type: "bool", + }, config.HelpKV{ Key: config.Comment, Description: config.DefaultComment,