*: add versioned user agent to sentry

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-06-20 11:54:10 +02:00
parent 1f190a9255
commit b6267fdf28
12 changed files with 32 additions and 12 deletions

View File

@ -1,5 +1,5 @@
"""authentik sentry integration""" """authentik sentry integration"""
from typing import Optional from typing import Any, Optional
from aioredis.errors import ConnectionClosedError, ReplyError from aioredis.errors import ConnectionClosedError, ReplyError
from billiard.exceptions import SoftTimeLimitExceeded, WorkerLostError from billiard.exceptions import SoftTimeLimitExceeded, WorkerLostError
@ -17,7 +17,7 @@ from ldap3.core.exceptions import LDAPException
from redis.exceptions import ConnectionError as RedisConnectionError from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError, ResponseError from redis.exceptions import RedisError, ResponseError
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from sentry_sdk import Hub from sentry_sdk import HttpTransport, Hub
from sentry_sdk import init as sentry_sdk_init from sentry_sdk import init as sentry_sdk_init
from sentry_sdk.api import set_tag from sentry_sdk.api import set_tag
from sentry_sdk.integrations.celery import CeleryIntegration from sentry_sdk.integrations.celery import CeleryIntegration
@ -30,6 +30,7 @@ from websockets.exceptions import WebSocketException
from authentik import __version__, get_build_hash from authentik import __version__, get_build_hash
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.lib.utils.http import authentik_user_agent
from authentik.lib.utils.reflection import class_to_path, get_env from authentik.lib.utils.reflection import class_to_path, get_env
LOGGER = get_logger() LOGGER = get_logger()
@ -52,6 +53,14 @@ class SentryIgnoredException(Exception):
"""Base Class for all errors that are suppressed, and not sent to sentry.""" """Base Class for all errors that are suppressed, and not sent to sentry."""
class SentryTransport(HttpTransport):
"""Custom sentry transport with custom user-agent"""
def __init__(self, options: dict[str, Any]) -> None:
super().__init__(options)
self._auth = self.parsed_dsn.to_auth(authentik_user_agent())
def sentry_init(**sentry_init_kwargs): def sentry_init(**sentry_init_kwargs):
"""Configure sentry SDK""" """Configure sentry SDK"""
sentry_env = CONFIG.y("error_reporting.environment", "customer") sentry_env = CONFIG.y("error_reporting.environment", "customer")
@ -72,6 +81,7 @@ def sentry_init(**sentry_init_kwargs):
before_send=before_send, before_send=before_send,
traces_sampler=traces_sampler, traces_sampler=traces_sampler,
release=f"authentik@{__version__}", release=f"authentik@{__version__}",
transport=SentryTransport,
**kwargs, **kwargs,
) )
set_tag("authentik.build_hash", get_build_hash("tagged")) set_tag("authentik.build_hash", get_build_hash("tagged"))

View File

@ -16,6 +16,7 @@ import (
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxyv2" "goauthentik.io/internal/outpost/proxyv2"
sentryutils "goauthentik.io/internal/utils/sentry" sentryutils "goauthentik.io/internal/utils/sentry"
webutils "goauthentik.io/internal/utils/web"
"goauthentik.io/internal/web" "goauthentik.io/internal/web"
"goauthentik.io/internal/web/tenant_tls" "goauthentik.io/internal/web/tenant_tls"
) )
@ -55,6 +56,7 @@ func main() {
TracesSampler: sentryutils.SamplerFunc(config.G.ErrorReporting.SampleRate), TracesSampler: sentryutils.SamplerFunc(config.G.ErrorReporting.SampleRate),
Release: fmt.Sprintf("authentik@%s", constants.VERSION), Release: fmt.Sprintf("authentik@%s", constants.VERSION),
Environment: config.G.ErrorReporting.Environment, Environment: config.G.ErrorReporting.Environment,
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgent(), http.DefaultTransport),
IgnoreErrors: []string{ IgnoreErrors: []string{
http.ErrAbortHandler.Error(), http.ErrAbortHandler.Error(),
}, },

View File

@ -25,4 +25,8 @@ func OutpostUserAgent() string {
return fmt.Sprintf("goauthentik.io/outpost/%s", FullVersion()) return fmt.Sprintf("goauthentik.io/outpost/%s", FullVersion())
} }
func UserAgent() string {
return fmt.Sprintf("authentik@%s", FullVersion())
}
const VERSION = "2022.6.3" const VERSION = "2022.6.3"

View File

@ -10,7 +10,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"goauthentik.io/internal/config" "goauthentik.io/internal/config"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/utils/web"
) )
type GoUnicorn struct { type GoUnicorn struct {
@ -70,7 +70,7 @@ func (g *GoUnicorn) Start() error {
func (g *GoUnicorn) healthcheck() { func (g *GoUnicorn) healthcheck() {
g.log.Debug("starting healthcheck") g.log.Debug("starting healthcheck")
h := &http.Client{ h := &http.Client{
Transport: ak.NewUserAgentTransport("goauthentik.io/proxy/healthcheck", http.DefaultTransport), Transport: web.NewUserAgentTransport("goauthentik.io/proxy/healthcheck", http.DefaultTransport),
} }
check := func() bool { check := func() bool {
res, err := h.Get("http://localhost:8000/-/health/live/") res, err := h.Get("http://localhost:8000/-/health/live/")

View File

@ -17,6 +17,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"goauthentik.io/api/v3" "goauthentik.io/api/v3"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
"goauthentik.io/internal/utils/web"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -54,7 +55,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
config.Host = akURL.Host config.Host = akURL.Host
config.Scheme = akURL.Scheme config.Scheme = akURL.Scheme
config.HTTPClient = &http.Client{ config.HTTPClient = &http.Client{
Transport: NewUserAgentTransport(constants.OutpostUserAgent(), NewTracingTransport(rsp.Context(), GetTLSTransport())), Transport: web.NewUserAgentTransport(constants.OutpostUserAgent(), web.NewTracingTransport(rsp.Context(), GetTLSTransport())),
} }
config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", token)) config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", token))

View File

@ -12,6 +12,7 @@ import (
"goauthentik.io/api/v3" "goauthentik.io/api/v3"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
sentryutils "goauthentik.io/internal/utils/sentry" sentryutils "goauthentik.io/internal/utils/sentry"
webutils "goauthentik.io/internal/utils/web"
) )
var initialSetup = false var initialSetup = false
@ -52,6 +53,7 @@ func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
Environment: globalConfig.ErrorReporting.Environment, Environment: globalConfig.ErrorReporting.Environment,
TracesSampler: sentryutils.SamplerFunc(float64(globalConfig.ErrorReporting.TracesSampleRate)), TracesSampler: sentryutils.SamplerFunc(float64(globalConfig.ErrorReporting.TracesSampleRate)),
Release: fmt.Sprintf("authentik@%s", constants.VERSION), Release: fmt.Sprintf("authentik@%s", constants.VERSION),
HTTPTransport: webutils.NewUserAgentTransport(constants.OutpostUserAgent(), http.DefaultTransport),
IgnoreErrors: []string{ IgnoreErrors: []string{
http.ErrAbortHandler.Error(), http.ErrAbortHandler.Error(),
}, },

View File

@ -17,6 +17,7 @@ import (
"goauthentik.io/api/v3" "goauthentik.io/api/v3"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/utils/web"
) )
var ( var (
@ -56,7 +57,7 @@ func NewFlowExecutor(ctx context.Context, flowSlug string, refConfig *api.Config
l.WithError(err).Warning("Failed to create cookiejar") l.WithError(err).Warning("Failed to create cookiejar")
panic(err) panic(err)
} }
transport := ak.NewUserAgentTransport(constants.OutpostUserAgent(), ak.NewTracingTransport(rsp.Context(), ak.GetTLSTransport())) transport := web.NewUserAgentTransport(constants.OutpostUserAgent(), web.NewTracingTransport(rsp.Context(), ak.GetTLSTransport()))
fe := &FlowExecutor{ fe := &FlowExecutor{
Params: url.Values{}, Params: url.Values{},
Answers: make(map[StageComponent]string), Answers: make(map[StageComponent]string),

View File

@ -11,7 +11,6 @@ import (
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxyv2/metrics" "goauthentik.io/internal/outpost/proxyv2/metrics"
"goauthentik.io/internal/utils/web" "goauthentik.io/internal/utils/web"
) )
@ -30,7 +29,7 @@ func (a *Application) configureProxy() error {
} }
rp := &httputil.ReverseProxy{Director: a.proxyModifyRequest(u)} rp := &httputil.ReverseProxy{Director: a.proxyModifyRequest(u)}
rsp := sentry.StartSpan(context.TODO(), "authentik.outposts.proxy.application_transport") rsp := sentry.StartSpan(context.TODO(), "authentik.outposts.proxy.application_transport")
rp.Transport = ak.NewTracingTransport(rsp.Context(), a.getUpstreamTransport()) rp.Transport = web.NewTracingTransport(rsp.Context(), a.getUpstreamTransport())
rp.ErrorHandler = a.newProxyErrorHandler() rp.ErrorHandler = a.newProxyErrorHandler()
rp.ModifyResponse = a.proxyModifyResponse rp.ModifyResponse = a.proxyModifyResponse
a.mux.PathPrefix("/").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { a.mux.PathPrefix("/").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {

View File

@ -9,6 +9,7 @@ import (
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxyv2/application" "goauthentik.io/internal/outpost/proxyv2/application"
"goauthentik.io/internal/utils/web"
) )
func (ps *ProxyServer) Refresh() error { func (ps *ProxyServer) Refresh() error {
@ -24,7 +25,7 @@ func (ps *ProxyServer) Refresh() error {
rsp := sentry.StartSpan(context.Background(), "authentik.outposts.proxy.application_ss") rsp := sentry.StartSpan(context.Background(), "authentik.outposts.proxy.application_ss")
ua := fmt.Sprintf(" (provider=%s)", provider.Name) ua := fmt.Sprintf(" (provider=%s)", provider.Name)
hc := &http.Client{ hc := &http.Client{
Transport: ak.NewUserAgentTransport(constants.OutpostUserAgent()+ua, ak.NewTracingTransport(rsp.Context(), ak.GetTLSTransport())), Transport: web.NewUserAgentTransport(constants.OutpostUserAgent()+ua, web.NewTracingTransport(rsp.Context(), ak.GetTLSTransport())),
} }
a, err := application.NewApplication(provider, hc, ps.cryptoStore, ps.akAPI) a, err := application.NewApplication(provider, hc, ps.cryptoStore, ps.akAPI)
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package ak package web
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package ak package web
import ( import (
"net/http" "net/http"

View File

@ -78,7 +78,7 @@ slug: "2022.6"
- web/elements: add spinner when loading dynamic routes - web/elements: add spinner when loading dynamic routes
- web/flows: add divider to identification stage for security key - web/flows: add divider to identification stage for security key
- web/flows: fix error when webauthn operations failed and user retries - web/flows: fix error when webauthn operations failed and user retries
- web/flows: remove autofocus from password field of identifications tage - web/flows: remove autofocus from password field of identifications stage
## Upgrading ## Upgrading