From a6a6b3bd069b89c79202cdc4d94256b80a0a9aab Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 16 Sep 2021 10:03:31 +0200 Subject: [PATCH] outposts: add outpost_name label to metrics Signed-off-by: Jens Langhammer --- internal/outpost/ldap/bind.go | 18 ++++--- internal/outpost/ldap/instance_bind.go | 45 +++++++++------- internal/outpost/ldap/instance_search.go | 54 ++++++++++--------- internal/outpost/ldap/ldap.go | 6 +-- internal/outpost/ldap/metrics/metrics.go | 4 +- internal/outpost/ldap/{api.go => refresh.go} | 1 + internal/outpost/ldap/search.go | 9 ++-- .../proxyv2/application/application.go | 19 ++++--- .../outpost/proxyv2/application/mode_proxy.go | 1 + internal/outpost/proxyv2/application/utils.go | 9 ---- internal/outpost/proxyv2/handlers.go | 26 ++++----- internal/outpost/proxyv2/metrics/metrics.go | 4 +- internal/outpost/proxyv2/refresh.go | 2 +- 13 files changed, 105 insertions(+), 93 deletions(-) rename internal/outpost/ldap/{api.go => refresh.go} (98%) diff --git a/internal/outpost/ldap/bind.go b/internal/outpost/ldap/bind.go index c2dfb7e4d..4f835875a 100644 --- a/internal/outpost/ldap/bind.go +++ b/internal/outpost/ldap/bind.go @@ -42,10 +42,11 @@ func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LD defer func() { span.Finish() metrics.Requests.With(prometheus.Labels{ - "type": "bind", - "filter": "", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": ls.ac.Outpost.Name, + "type": "bind", + "filter": "", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Observe(float64(span.EndTime.Sub(span.StartTime))) req.log.WithField("took-ms", span.EndTime.Sub(span.StartTime).Milliseconds()).Info("Bind request") }() @@ -59,10 +60,11 @@ func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LD } req.log.WithField("request", "bind").Warning("No provider found for request") metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "no_provider", - "dn": bindDN, - "client": utils.GetIP(conn.RemoteAddr()), + "outpost_name": ls.ac.Outpost.Name, + "type": "bind", + "reason": "no_provider", + "dn": bindDN, + "client": utils.GetIP(conn.RemoteAddr()), }).Inc() return ldap.LDAPResultOperationsError, nil } diff --git a/internal/outpost/ldap/instance_bind.go b/internal/outpost/ldap/instance_bind.go index 846271922..f1bce89c0 100644 --- a/internal/outpost/ldap/instance_bind.go +++ b/internal/outpost/ldap/instance_bind.go @@ -51,19 +51,21 @@ func (pi *ProviderInstance) Bind(username string, req BindRequest) (ldap.LDAPRes passed, err := fe.Execute() if !passed { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "invalid_credentials", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "bind", + "reason": "invalid_credentials", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.LDAPResultInvalidCredentials, nil } if err != nil { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "flow_error", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "bind", + "reason": "flow_error", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() req.log.WithError(err).Warning("failed to execute flow") return ldap.LDAPResultOperationsError, nil @@ -73,19 +75,21 @@ func (pi *ProviderInstance) Bind(username string, req BindRequest) (ldap.LDAPRes if !access { req.log.Info("Access denied for user") metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "access_denied", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "bind", + "reason": "access_denied", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.LDAPResultInsufficientAccessRights, nil } if err != nil { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "access_check_fail", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "bind", + "reason": "access_check_fail", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() req.log.WithError(err).Warning("failed to check access") return ldap.LDAPResultOperationsError, nil @@ -96,10 +100,11 @@ func (pi *ProviderInstance) Bind(username string, req BindRequest) (ldap.LDAPRes userInfo, _, err := fe.ApiClient().CoreApi.CoreUsersMeRetrieve(context.Background()).Execute() if err != nil { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "bind", - "reason": "user_info_fail", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "bind", + "reason": "user_info_fail", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() req.log.WithError(err).Warning("failed to get user info") return ldap.LDAPResultOperationsError, nil diff --git a/internal/outpost/ldap/instance_search.go b/internal/outpost/ldap/instance_search.go index f6e89dee2..b2e73afb7 100644 --- a/internal/outpost/ldap/instance_search.go +++ b/internal/outpost/ldap/instance_search.go @@ -36,28 +36,31 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, filterEntity, err := ldap.GetFilterObjectClass(req.Filter) if err != nil { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "filter_parse_fail", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "filter_parse_fail", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", req.Filter) } if len(req.BindDN) < 1 { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "empty_bind_dn", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "empty_bind_dn", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", req.BindDN) } if !strings.HasSuffix(req.BindDN, baseDN) { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "invalid_bind_dn", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "invalid_bind_dn", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", req.BindDN, pi.BaseDN) } @@ -68,10 +71,11 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, if !ok { pi.log.Debug("User info not cached") metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "user_info_not_cached", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "user_info_not_cached", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") } @@ -84,10 +88,11 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, parsedFilter, err := ldap.CompileFilter(req.Filter) if err != nil { metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "filter_parse_fail", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "filter_parse_fail", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", req.Filter) } @@ -99,10 +104,11 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, switch filterEntity { default: metrics.RequestsRejected.With(prometheus.Labels{ - "type": "search", - "reason": "unhandled_filter_type", - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": pi.outpostName, + "type": "search", + "reason": "unhandled_filter_type", + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Inc() return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, req.Filter) case GroupObjectClass: diff --git a/internal/outpost/ldap/ldap.go b/internal/outpost/ldap/ldap.go index be3bf8709..8660fb22d 100644 --- a/internal/outpost/ldap/ldap.go +++ b/internal/outpost/ldap/ldap.go @@ -29,9 +29,9 @@ type ProviderInstance struct { s *LDAPServer log *log.Entry - tlsServerName *string - cert *tls.Certificate - + tlsServerName *string + cert *tls.Certificate + outpostName string searchAllowedGroups []*strfmt.UUID boundUsersMutex sync.RWMutex boundUsers map[string]UserFlags diff --git a/internal/outpost/ldap/metrics/metrics.go b/internal/outpost/ldap/metrics/metrics.go index 6723f4a56..efbe257aa 100644 --- a/internal/outpost/ldap/metrics/metrics.go +++ b/internal/outpost/ldap/metrics/metrics.go @@ -13,11 +13,11 @@ var ( Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "authentik_outpost_ldap_requests", Help: "The total number of configured providers", - }, []string{"type", "dn", "filter", "client"}) + }, []string{"outpost_name", "type", "dn", "filter", "client"}) RequestsRejected = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "authentik_outpost_ldap_requests_rejected", Help: "Total number of rejected requests", - }, []string{"type", "reason", "dn", "client"}) + }, []string{"outpost_name", "type", "reason", "dn", "client"}) ) func RunServer() { diff --git a/internal/outpost/ldap/api.go b/internal/outpost/ldap/refresh.go similarity index 98% rename from internal/outpost/ldap/api.go rename to internal/outpost/ldap/refresh.go index 7f6e84d99..5aee26985 100644 --- a/internal/outpost/ldap/api.go +++ b/internal/outpost/ldap/refresh.go @@ -50,6 +50,7 @@ func (ls *LDAPServer) Refresh() error { tlsServerName: provider.TlsServerName, uidStartNumber: *provider.UidStartNumber, gidStartNumber: *provider.GidStartNumber, + outpostName: ls.ac.Outpost.Name, } if provider.Certificate.Get() != nil { kp := provider.Certificate.Get() diff --git a/internal/outpost/ldap/search.go b/internal/outpost/ldap/search.go index 5f597c9f6..6b0461fda 100644 --- a/internal/outpost/ldap/search.go +++ b/internal/outpost/ldap/search.go @@ -46,10 +46,11 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n defer func() { span.Finish() metrics.Requests.With(prometheus.Labels{ - "type": "search", - "filter": req.Filter, - "dn": req.BindDN, - "client": utils.GetIP(req.conn.RemoteAddr()), + "outpost_name": ls.ac.Outpost.Name, + "type": "search", + "filter": req.Filter, + "dn": req.BindDN, + "client": utils.GetIP(req.conn.RemoteAddr()), }).Observe(float64(span.EndTime.Sub(span.StartTime))) req.log.WithField("took-ms", span.EndTime.Sub(span.StartTime).Milliseconds()).Info("Search request") }() diff --git a/internal/outpost/proxyv2/application/application.go b/internal/outpost/proxyv2/application/application.go index a83bebdcb..7d34c3271 100644 --- a/internal/outpost/proxyv2/application/application.go +++ b/internal/outpost/proxyv2/application/application.go @@ -31,6 +31,7 @@ type Application struct { endpint OIDCEndpoint oauthConfig oauth2.Config tokenVerifier *oidc.IDTokenVerifier + outpostName string sessions sessions.Store proxyConfig api.ProxyOutpostConfig @@ -40,7 +41,7 @@ type Application struct { mux *mux.Router } -func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore, akHost string) *Application { +func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore, ak *ak.APIController) *Application { gob.Register(Claims{}) externalHost, err := url.Parse(p.ExternalHost) @@ -56,7 +57,7 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore }) // Configure an OpenID Connect aware OAuth2 client. - endpoint := GetOIDCEndpoint(p, akHost) + endpoint := GetOIDCEndpoint(p, ak.Outpost.Config["authentik_host"].(string)) oauth2Config := oauth2.Config{ ClientID: *p.ClientId, ClientSecret: *p.ClientSecret, @@ -68,6 +69,7 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore a := &Application{ Host: externalHost.Host, log: log.WithField("logger", "authentik.outpost.proxy.bundle").WithField("provider", p.Name), + outpostName: ak.Outpost.Name, endpint: endpoint, oauthConfig: oauth2Config, tokenVerifier: verifier, @@ -103,12 +105,13 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, cs *ak.CryptoStore inner.ServeHTTP(rw, r) after := time.Since(before) metrics.Requests.With(prometheus.Labels{ - "type": "app", - "scheme": r.URL.Scheme, - "method": r.Method, - "path": r.URL.Path, - "host": web.GetHost(r), - "user": user, + "outpost_name": a.outpostName, + "type": "app", + "scheme": r.URL.Scheme, + "method": r.Method, + "path": r.URL.Path, + "host": web.GetHost(r), + "user": user, }).Observe(float64(after)) }) }) diff --git a/internal/outpost/proxyv2/application/mode_proxy.go b/internal/outpost/proxyv2/application/mode_proxy.go index a5fabb09d..14c0e1e63 100644 --- a/internal/outpost/proxyv2/application/mode_proxy.go +++ b/internal/outpost/proxyv2/application/mode_proxy.go @@ -50,6 +50,7 @@ func (a *Application) configureProxy() error { user = claims.Email } metrics.UpstreamTiming.With(prometheus.Labels{ + "outpost_name": a.outpostName, "upstream_host": u.String(), "scheme": r.URL.Scheme, "method": r.Method, diff --git a/internal/outpost/proxyv2/application/utils.go b/internal/outpost/proxyv2/application/utils.go index 019432d5c..fad584620 100644 --- a/internal/outpost/proxyv2/application/utils.go +++ b/internal/outpost/proxyv2/application/utils.go @@ -44,15 +44,6 @@ func (a *Application) getClaims(r *http.Request) (*Claims, error) { return &c, nil } -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - // toString Generic to string function, currently supports actual strings and integers func toString(in interface{}) string { switch v := in.(type) { diff --git a/internal/outpost/proxyv2/handlers.go b/internal/outpost/proxyv2/handlers.go index a49d27ab2..187aca38c 100644 --- a/internal/outpost/proxyv2/handlers.go +++ b/internal/outpost/proxyv2/handlers.go @@ -15,12 +15,13 @@ func (ps *ProxyServer) HandlePing(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(204) after := time.Since(before) metrics.Requests.With(prometheus.Labels{ - "method": r.Method, - "schema": r.URL.Scheme, - "path": r.URL.Path, - "host": web.GetHost(r), - "type": "ping", - "user": "", + "outpost_name": ps.akAPI.Outpost.Name, + "method": r.Method, + "schema": r.URL.Scheme, + "path": r.URL.Path, + "host": web.GetHost(r), + "type": "ping", + "user": "", }).Observe(float64(after)) } @@ -30,12 +31,13 @@ func (ps *ProxyServer) HandleStatic(rw http.ResponseWriter, r *http.Request) { http.StripPrefix("/akprox/static", staticFs).ServeHTTP(rw, r) after := time.Since(before) metrics.Requests.With(prometheus.Labels{ - "method": r.Method, - "schema": r.URL.Scheme, - "path": r.URL.Path, - "host": web.GetHost(r), - "type": "ping", - "user": "", + "outpost_name": ps.akAPI.Outpost.Name, + "method": r.Method, + "schema": r.URL.Scheme, + "path": r.URL.Path, + "host": web.GetHost(r), + "type": "ping", + "user": "", }).Observe(float64(after)) } diff --git a/internal/outpost/proxyv2/metrics/metrics.go b/internal/outpost/proxyv2/metrics/metrics.go index 585fb77da..b08467346 100644 --- a/internal/outpost/proxyv2/metrics/metrics.go +++ b/internal/outpost/proxyv2/metrics/metrics.go @@ -13,11 +13,11 @@ var ( Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "authentik_outpost_proxy_requests", Help: "The total number of configured providers", - }, []string{"method", "scheme", "path", "host", "type", "user"}) + }, []string{"outpost_name", "method", "scheme", "path", "host", "type", "user"}) UpstreamTiming = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "authentik_outpost_proxy_upstream_time", Help: "A summary of the duration we wait for the upstream reply", - }, []string{"method", "scheme", "path", "host", "upstream_host", "user"}) + }, []string{"outpost_name", "method", "scheme", "path", "host", "upstream_host", "user"}) ) func RunServer() { diff --git a/internal/outpost/proxyv2/refresh.go b/internal/outpost/proxyv2/refresh.go index 3eb81985f..5b4a0a7d2 100644 --- a/internal/outpost/proxyv2/refresh.go +++ b/internal/outpost/proxyv2/refresh.go @@ -24,7 +24,7 @@ func (ps *ProxyServer) Refresh() error { hc := &http.Client{ Transport: ak.NewUserAgentTransport(constants.OutpostUserAgent()+ua, ak.NewTracingTransport(context.TODO(), ak.GetTLSTransport())), } - a := application.NewApplication(provider, hc, ps.cryptoStore, ps.akAPI.Outpost.Config["authentik_host"].(string)) + a := application.NewApplication(provider, hc, ps.cryptoStore, ps.akAPI) apps[a.Host] = a } ps.apps = apps