mirror of
https://github.com/openfaas/faas.git
synced 2025-06-19 04:26:35 +00:00
Differentiate external service auth from user auth
Signed-off-by: Alex Ellis <alexellis2@gmail.com>
This commit is contained in:
@ -39,7 +39,11 @@ type URLPathTransformer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeForwardingProxyHandler create a handler which forwards HTTP requests
|
// MakeForwardingProxyHandler create a handler which forwards HTTP requests
|
||||||
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy, notifiers []HTTPNotifier, baseURLResolver BaseURLResolver, urlPathTransformer URLPathTransformer) http.HandlerFunc {
|
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy,
|
||||||
|
notifiers []HTTPNotifier,
|
||||||
|
baseURLResolver BaseURLResolver,
|
||||||
|
urlPathTransformer URLPathTransformer,
|
||||||
|
serviceAuthInjector AuthInjector) http.HandlerFunc {
|
||||||
|
|
||||||
writeRequestURI := false
|
writeRequestURI := false
|
||||||
if _, exists := os.LookupEnv("write_request_uri"); exists {
|
if _, exists := os.LookupEnv("write_request_uri"); exists {
|
||||||
@ -54,7 +58,7 @@ func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy, notifiers [
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI)
|
statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI, serviceAuthInjector)
|
||||||
|
|
||||||
seconds := time.Since(start)
|
seconds := time.Since(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -96,13 +100,24 @@ func buildUpstreamRequest(r *http.Request, baseURL string, requestURL string) *h
|
|||||||
return upstreamReq
|
return upstreamReq
|
||||||
}
|
}
|
||||||
|
|
||||||
func forwardRequest(w http.ResponseWriter, r *http.Request, proxyClient *http.Client, baseURL string, requestURL string, timeout time.Duration, writeRequestURI bool) (int, error) {
|
func forwardRequest(w http.ResponseWriter,
|
||||||
|
r *http.Request,
|
||||||
|
proxyClient *http.Client,
|
||||||
|
baseURL string,
|
||||||
|
requestURL string,
|
||||||
|
timeout time.Duration,
|
||||||
|
writeRequestURI bool,
|
||||||
|
serviceAuthInjector AuthInjector) (int, error) {
|
||||||
|
|
||||||
upstreamReq := buildUpstreamRequest(r, baseURL, requestURL)
|
upstreamReq := buildUpstreamRequest(r, baseURL, requestURL)
|
||||||
if upstreamReq.Body != nil {
|
if upstreamReq.Body != nil {
|
||||||
defer upstreamReq.Body.Close()
|
defer upstreamReq.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if serviceAuthInjector != nil {
|
||||||
|
serviceAuthInjector.Inject(upstreamReq)
|
||||||
|
}
|
||||||
|
|
||||||
if writeRequestURI {
|
if writeRequestURI {
|
||||||
log.Printf("forwardRequest: %s %s\n", upstreamReq.Host, upstreamReq.URL.String())
|
log.Printf("forwardRequest: %s %s\n", upstreamReq.Host, upstreamReq.URL.String())
|
||||||
}
|
}
|
||||||
|
7
gateway/handlers/serviceauthinjector.go
Normal file
7
gateway/handlers/serviceauthinjector.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type AuthInjector interface {
|
||||||
|
Inject(r *http.Request)
|
||||||
|
}
|
@ -15,13 +15,13 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/openfaas/faas-provider/auth"
|
"github.com/openfaas/faas/gateway/handlers"
|
||||||
"github.com/openfaas/faas/gateway/requests"
|
"github.com/openfaas/faas/gateway/requests"
|
||||||
"github.com/openfaas/faas/gateway/scaling"
|
"github.com/openfaas/faas/gateway/scaling"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewExternalServiceQuery proxies service queries to external plugin via HTTP
|
// NewExternalServiceQuery proxies service queries to external plugin via HTTP
|
||||||
func NewExternalServiceQuery(externalURL url.URL, credentials *auth.BasicAuthCredentials) scaling.ServiceQuery {
|
func NewExternalServiceQuery(externalURL url.URL, authInjector handlers.AuthInjector) scaling.ServiceQuery {
|
||||||
timeout := 3 * time.Second
|
timeout := 3 * time.Second
|
||||||
|
|
||||||
proxyClient := http.Client{
|
proxyClient := http.Client{
|
||||||
@ -41,7 +41,7 @@ func NewExternalServiceQuery(externalURL url.URL, credentials *auth.BasicAuthCre
|
|||||||
return ExternalServiceQuery{
|
return ExternalServiceQuery{
|
||||||
URL: externalURL,
|
URL: externalURL,
|
||||||
ProxyClient: proxyClient,
|
ProxyClient: proxyClient,
|
||||||
Credentials: credentials,
|
AuthInjector: authInjector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ func NewExternalServiceQuery(externalURL url.URL, credentials *auth.BasicAuthCre
|
|||||||
type ExternalServiceQuery struct {
|
type ExternalServiceQuery struct {
|
||||||
URL url.URL
|
URL url.URL
|
||||||
ProxyClient http.Client
|
ProxyClient http.Client
|
||||||
Credentials *auth.BasicAuthCredentials
|
AuthInjector handlers.AuthInjector
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScaleServiceRequest request scaling of replica
|
// ScaleServiceRequest request scaling of replica
|
||||||
@ -71,8 +71,8 @@ func (s ExternalServiceQuery) GetReplicas(serviceName string) (scaling.ServiceQu
|
|||||||
|
|
||||||
req, _ := http.NewRequest(http.MethodGet, urlPath, nil)
|
req, _ := http.NewRequest(http.MethodGet, urlPath, nil)
|
||||||
|
|
||||||
if s.Credentials != nil {
|
if s.AuthInjector != nil {
|
||||||
req.SetBasicAuth(s.Credentials.User, s.Credentials.Password)
|
s.AuthInjector.Inject(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := s.ProxyClient.Do(req)
|
res, err := s.ProxyClient.Do(req)
|
||||||
@ -144,8 +144,8 @@ func (s ExternalServiceQuery) SetReplicas(serviceName string, count uint64) erro
|
|||||||
urlPath := fmt.Sprintf("%ssystem/scale-function/%s", s.URL.String(), serviceName)
|
urlPath := fmt.Sprintf("%ssystem/scale-function/%s", s.URL.String(), serviceName)
|
||||||
req, _ := http.NewRequest(http.MethodPost, urlPath, bytes.NewReader(requestBody))
|
req, _ := http.NewRequest(http.MethodPost, urlPath, bytes.NewReader(requestBody))
|
||||||
|
|
||||||
if s.Credentials != nil {
|
if s.AuthInjector != nil {
|
||||||
req.SetBasicAuth(s.Credentials.User, s.Credentials.Password)
|
s.AuthInjector.Inject(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/openfaas/faas-provider/auth"
|
"github.com/openfaas/faas/gateway/handlers"
|
||||||
"github.com/openfaas/faas/gateway/scaling"
|
"github.com/openfaas/faas/gateway/scaling"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -47,11 +47,10 @@ func TestGetReplicasNonExistentFn(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
|
||||||
var creds auth.BasicAuthCredentials
|
var injector handlers.AuthInjector
|
||||||
|
|
||||||
url, _ := url.Parse(testServer.URL + "/")
|
url, _ := url.Parse(testServer.URL + "/")
|
||||||
|
|
||||||
esq := NewExternalServiceQuery(*url, &creds)
|
esq := NewExternalServiceQuery(*url, injector)
|
||||||
|
|
||||||
svcQryResp, err := esq.GetReplicas("burt")
|
svcQryResp, err := esq.GetReplicas("burt")
|
||||||
|
|
||||||
@ -78,11 +77,10 @@ func TestGetReplicasExistentFn(t *testing.T) {
|
|||||||
AvailableReplicas: 0,
|
AvailableReplicas: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
var creds auth.BasicAuthCredentials
|
var injector handlers.AuthInjector
|
||||||
|
|
||||||
url, _ := url.Parse(testServer.URL + "/")
|
url, _ := url.Parse(testServer.URL + "/")
|
||||||
|
|
||||||
esq := NewExternalServiceQuery(*url, &creds)
|
esq := NewExternalServiceQuery(*url, injector)
|
||||||
|
|
||||||
svcQryResp, err := esq.GetReplicas("burt")
|
svcQryResp, err := esq.GetReplicas("burt")
|
||||||
|
|
||||||
@ -104,9 +102,9 @@ func TestSetReplicasNonExistentFn(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
|
||||||
var creds auth.BasicAuthCredentials
|
var injector handlers.AuthInjector
|
||||||
url, _ := url.Parse(testServer.URL + "/")
|
url, _ := url.Parse(testServer.URL + "/")
|
||||||
esq := NewExternalServiceQuery(*url, &creds)
|
esq := NewExternalServiceQuery(*url, injector)
|
||||||
|
|
||||||
err := esq.SetReplicas("burt", 1)
|
err := esq.SetReplicas("burt", 1)
|
||||||
|
|
||||||
@ -126,9 +124,10 @@ func TestSetReplicasExistentFn(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
|
|
||||||
var creds auth.BasicAuthCredentials
|
var injector handlers.AuthInjector
|
||||||
|
|
||||||
url, _ := url.Parse(testServer.URL + "/")
|
url, _ := url.Parse(testServer.URL + "/")
|
||||||
esq := NewExternalServiceQuery(*url, &creds)
|
esq := NewExternalServiceQuery(*url, injector)
|
||||||
|
|
||||||
err := esq.SetReplicas("burt", 1)
|
err := esq.SetReplicas("burt", 1)
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ func main() {
|
|||||||
|
|
||||||
log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
|
log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
|
||||||
|
|
||||||
|
// credentials is used for service-to-service auth
|
||||||
var credentials *auth.BasicAuthCredentials
|
var credentials *auth.BasicAuthCredentials
|
||||||
|
|
||||||
if config.UseBasicAuth {
|
if config.UseBasicAuth {
|
||||||
@ -57,12 +58,17 @@ func main() {
|
|||||||
exporter.StartServiceWatcher(*config.FunctionsProviderURL, metricsOptions, "func", servicePollInterval)
|
exporter.StartServiceWatcher(*config.FunctionsProviderURL, metricsOptions, "func", servicePollInterval)
|
||||||
metrics.RegisterExporter(exporter)
|
metrics.RegisterExporter(exporter)
|
||||||
|
|
||||||
reverseProxy := types.NewHTTPClientReverseProxy(config.FunctionsProviderURL, config.UpstreamTimeout, config.MaxIdleConns, config.MaxIdleConnsPerHost)
|
reverseProxy := types.NewHTTPClientReverseProxy(config.FunctionsProviderURL,
|
||||||
|
config.UpstreamTimeout,
|
||||||
|
config.MaxIdleConns,
|
||||||
|
config.MaxIdleConnsPerHost)
|
||||||
|
|
||||||
loggingNotifier := handlers.LoggingNotifier{}
|
loggingNotifier := handlers.LoggingNotifier{}
|
||||||
|
|
||||||
prometheusNotifier := handlers.PrometheusFunctionNotifier{
|
prometheusNotifier := handlers.PrometheusFunctionNotifier{
|
||||||
Metrics: &metricsOptions,
|
Metrics: &metricsOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
prometheusServiceNotifier := handlers.PrometheusServiceNotifier{
|
prometheusServiceNotifier := handlers.PrometheusServiceNotifier{
|
||||||
ServiceMetrics: metricsOptions.ServiceMetrics,
|
ServiceMetrics: metricsOptions.ServiceMetrics,
|
||||||
}
|
}
|
||||||
@ -83,20 +89,22 @@ func main() {
|
|||||||
functionURLTransformer = nilURLTransformer
|
functionURLTransformer = nilURLTransformer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serviceAuthInjector := &BasicAuthInjector{Credentials: credentials}
|
||||||
|
|
||||||
decorateExternalAuth := handlers.MakeExternalAuthHandler
|
decorateExternalAuth := handlers.MakeExternalAuthHandler
|
||||||
|
|
||||||
faasHandlers.Proxy = handlers.MakeForwardingProxyHandler(reverseProxy, functionNotifiers, functionURLResolver, functionURLTransformer)
|
faasHandlers.Proxy = handlers.MakeForwardingProxyHandler(reverseProxy, functionNotifiers, functionURLResolver, functionURLTransformer, nil)
|
||||||
|
|
||||||
faasHandlers.RoutelessProxy = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.RoutelessProxy = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.ListFunctions = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.ListFunctions = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.DeployFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.DeployFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.DeleteFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.DeleteFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.UpdateFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.UpdateFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.QueryFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.QueryFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
faasHandlers.InfoHandler = handlers.MakeInfoHandler(handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer))
|
faasHandlers.InfoHandler = handlers.MakeInfoHandler(handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector))
|
||||||
faasHandlers.SecretHandler = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.SecretHandler = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
|
|
||||||
alertHandler := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL, credentials)
|
alertHandler := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL, serviceAuthInjector)
|
||||||
faasHandlers.Alert = handlers.MakeNotifierWrapper(
|
faasHandlers.Alert = handlers.MakeNotifierWrapper(
|
||||||
handlers.MakeAlertHandler(alertHandler),
|
handlers.MakeAlertHandler(alertHandler),
|
||||||
forwardingNotifiers,
|
forwardingNotifiers,
|
||||||
@ -129,7 +137,7 @@ func main() {
|
|||||||
faasHandlers.ListFunctions = metrics.AddMetricsHandler(faasHandlers.ListFunctions, prometheusQuery)
|
faasHandlers.ListFunctions = metrics.AddMetricsHandler(faasHandlers.ListFunctions, prometheusQuery)
|
||||||
faasHandlers.Proxy = handlers.MakeCallIDMiddleware(faasHandlers.Proxy)
|
faasHandlers.Proxy = handlers.MakeCallIDMiddleware(faasHandlers.Proxy)
|
||||||
|
|
||||||
faasHandlers.ScaleFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)
|
faasHandlers.ScaleFunction = handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)
|
||||||
|
|
||||||
if credentials != nil {
|
if credentials != nil {
|
||||||
faasHandlers.Alert =
|
faasHandlers.Alert =
|
||||||
@ -211,7 +219,7 @@ func main() {
|
|||||||
//Start metrics server in a goroutine
|
//Start metrics server in a goroutine
|
||||||
go runMetricsServer()
|
go runMetricsServer()
|
||||||
|
|
||||||
r.HandleFunc("/healthz", handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer)).Methods(http.MethodGet)
|
r.HandleFunc("/healthz", handlers.MakeForwardingProxyHandler(reverseProxy, forwardingNotifiers, urlResolver, nilURLTransformer, serviceAuthInjector)).Methods(http.MethodGet)
|
||||||
|
|
||||||
r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods(http.MethodGet)
|
r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods(http.MethodGet)
|
||||||
|
|
||||||
@ -250,3 +258,11 @@ func runMetricsServer() {
|
|||||||
|
|
||||||
log.Fatal(s.ListenAndServe())
|
log.Fatal(s.ListenAndServe())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasicAuthInjector struct {
|
||||||
|
Credentials *auth.BasicAuthCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BasicAuthInjector) Inject(r *http.Request) {
|
||||||
|
r.SetBasicAuth(b.Credentials.User, b.Credentials.Password)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user