Add HTTP2 config option for policy plugin (#16225)

This commit is contained in:
Aditya Manthramurthy 2022-12-13 14:28:48 -08:00 committed by GitHub
parent 709eb283d9
commit 9e6cc847f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 23 deletions

View File

@ -374,8 +374,7 @@ func validateSubSysConfig(s config.Config, subSys string, objAPI ObjectLayer) er
subSys = config.PolicyPluginSubSys subSys = config.PolicyPluginSubSys
fallthrough fallthrough
case config.PolicyPluginSubSys: case config.PolicyPluginSubSys:
if ppargs, err := polplugin.LookupConfig(s[config.PolicyPluginSubSys][config.Default], if ppargs, err := polplugin.LookupConfig(s, GetDefaultConnSettings(), xhttp.DrainBody); err != nil {
NewHTTPTransport(), xhttp.DrainBody); err != nil {
return err return err
} else if ppargs.URL == nil { } else if ppargs.URL == nil {
// Check if legacy opa is configured. // Check if legacy opa is configured.

View File

@ -233,8 +233,7 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer, etcdClient *etc
setGlobalAuthNPlugin(idplugin.New(authNPluginCfg)) setGlobalAuthNPlugin(idplugin.New(authNPluginCfg))
authZPluginCfg, err := polplugin.LookupConfig(s[config.PolicyPluginSubSys][config.Default], authZPluginCfg, err := polplugin.LookupConfig(s, GetDefaultConnSettings(), xhttp.DrainBody)
NewHTTPTransport(), xhttp.DrainBody)
if err != nil { if err != nil {
logger.LogIf(ctx, fmt.Errorf("Unable to initialize AuthZPlugin: %w", err)) logger.LogIf(ctx, fmt.Errorf("Unable to initialize AuthZPlugin: %w", err))
} }

View File

@ -568,6 +568,15 @@ func ToS3ETag(etag string) string {
return etag 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 // NewInternodeHTTPTransport returns a transport for internode MinIO
// connections. // connections.
func NewInternodeHTTPTransport() func() http.RoundTripper { func NewInternodeHTTPTransport() func() http.RoundTripper {

View File

@ -46,16 +46,19 @@ Only the last operation would fail with a permissions error.
Access Management Plugin can be configured with environment variables: Access Management Plugin can be configured with environment variables:
```sh ```sh
$ mc admin config set dminio1 policy_plugin --env $ mc admin config set myminio policy_plugin --env
KEY: KEY:
policy_plugin enable Access Management Plugin for policy enforcement policy_plugin enable Access Management Plugin for policy enforcement
ARGS: ARGS:
MINIO_POLICY_PLUGIN_URL* (url) plugin hook endpoint (HTTP(S)) e.g. "http://localhost:8181/v1/data/httpapi/authz/allow" 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_AUTH_TOKEN (string) authorization header for plugin hook endpoint
MINIO_POLICY_PLUGIN_COMMENT (sentence) optionally add a comment to this setting 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 ## 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. 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.

View File

@ -22,6 +22,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -29,6 +30,16 @@ import (
"strings" "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) { func writeErrorResponse(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{ json.NewEncoder(w).Encode(map[string]string{
@ -77,8 +88,22 @@ func mainHandler(w http.ResponseWriter, r *http.Request) {
} }
func main() { 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) http.HandleFunc("/", mainHandler)
log.Print("Listening on :8080") log.Print("Listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil)) log.Fatal(serveFunc())
} }

View File

@ -1076,7 +1076,7 @@ func getEnvVarName(subSys, target, param string) string {
Default, target) Default, target)
} }
var resolvableSubsystems = set.CreateStringSet(IdentityOpenIDSubSys, IdentityLDAPSubSys) var resolvableSubsystems = set.CreateStringSet(IdentityOpenIDSubSys, IdentityLDAPSubSys, PolicyPluginSubSys)
// ValueSource represents the source of a config parameter value. // ValueSource represents the source of a config parameter value.
type ValueSource uint8 type ValueSource uint8

View File

@ -22,20 +22,23 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
"time"
"github.com/minio/minio/internal/config" "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" iampolicy "github.com/minio/pkg/iam/policy"
xnet "github.com/minio/pkg/net" xnet "github.com/minio/pkg/net"
) )
// Authorization Plugin config and env variables // Authorization Plugin config and env variables
const ( const (
URL = "url" URL = "url"
AuthToken = "auth_token" AuthToken = "auth_token"
EnableHTTP2 = "enable_http2"
EnvPolicyPluginURL = "MINIO_POLICY_PLUGIN_URL" EnvPolicyPluginURL = "MINIO_POLICY_PLUGIN_URL"
EnvPolicyPluginAuthToken = "MINIO_POLICY_PLUGIN_AUTH_TOKEN" EnvPolicyPluginAuthToken = "MINIO_POLICY_PLUGIN_AUTH_TOKEN"
EnvPolicyPluginEnableHTTP2 = "MINIO_POLICY_PLUGIN_ENABLE_HTTP2"
) )
// DefaultKVS - default config for Authz plugin config // DefaultKVS - default config for Authz plugin config
@ -49,10 +52,14 @@ var (
Key: AuthToken, Key: AuthToken,
Value: "", Value: "",
}, },
config.KV{
Key: EnableHTTP2,
Value: "off",
},
} }
) )
// Args opa general purpose policy engine configuration. // Args for general purpose policy engine configuration.
type Args struct { type Args struct {
URL *xnet.URL `json:"url"` URL *xnet.URL `json:"url"`
AuthToken string `json:"authToken"` AuthToken string `json:"authToken"`
@ -114,27 +121,43 @@ func Enabled(kvs config.KVS) bool {
} }
// LookupConfig lookup AuthZPlugin from config, override with any ENVs. // 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{} args := Args{}
if err := config.CheckValidKeys(config.PolicyPluginSubSys, kv, DefaultKVS); err != nil { if err := s.CheckValidKeys(config.PolicyPluginSubSys, nil); err != nil {
return args, err 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 == "" { if pluginURL == "" {
return args, nil return args, nil
} }
authToken := env.Get(EnvPolicyPluginAuthToken, kv.Get(AuthToken))
u, err := xnet.ParseHTTPURL(pluginURL) u, err := xnet.ParseHTTPURL(pluginURL)
if err != nil { if err != nil {
return args, err 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{ args = Args{
URL: u, URL: u,
AuthToken: authToken, AuthToken: getCfg(AuthToken),
Transport: transport, Transport: transport,
CloseRespFn: closeRespFn, CloseRespFn: closeRespFn,
} }

View File

@ -34,11 +34,17 @@ var (
}, },
config.HelpKV{ config.HelpKV{
Key: AuthToken, Key: AuthToken,
Description: "authorization token for plugin hook endpoint" + defaultHelpPostfix(AuthToken), Description: "authorization header for plugin hook endpoint" + defaultHelpPostfix(AuthToken),
Optional: true, Optional: true,
Type: "string", Type: "string",
Sensitive: true, Sensitive: true,
}, },
config.HelpKV{
Key: EnableHTTP2,
Description: "Enable experimental HTTP2 support to connect to plugin service" + defaultHelpPostfix(EnableHTTP2),
Optional: true,
Type: "bool",
},
config.HelpKV{ config.HelpKV{
Key: config.Comment, Key: config.Comment,
Description: config.DefaultComment, Description: config.DefaultComment,