diff --git a/cmd/ldap/main.go b/cmd/ldap/main.go index eb16c0ffc0..2580b5c157 100644 --- a/cmd/ldap/main.go +++ b/cmd/ldap/main.go @@ -6,11 +6,13 @@ import ( "os" log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" "goauthentik.io/internal/common" "goauthentik.io/internal/config" "goauthentik.io/internal/debug" "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/ldap" ) @@ -21,59 +23,72 @@ Required environment variables: - AUTHENTIK_TOKEN: Token to authenticate with - AUTHENTIK_INSECURE: Skip SSL Certificate verification` -func main() { - log.SetLevel(log.DebugLevel) - log.SetFormatter(&log.JSONFormatter{ - FieldMap: log.FieldMap{ - log.FieldKeyMsg: "event", - log.FieldKeyTime: "timestamp", - }, - DisableHTMLEscape: true, - }) - debug.EnableDebugServer() - akURL := config.Get().AuthentikHost - if akURL == "" { - fmt.Println("env AUTHENTIK_HOST not set!") - fmt.Println(helpMessage) - os.Exit(1) - } - akToken := config.Get().AuthentikToken - if akToken == "" { - fmt.Println("env AUTHENTIK_TOKEN not set!") - fmt.Println(helpMessage) - os.Exit(1) - } +var rootCmd = &cobra.Command{ + Long: helpMessage, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.JSONFormatter{ + FieldMap: log.FieldMap{ + log.FieldKeyMsg: "event", + log.FieldKeyTime: "timestamp", + }, + DisableHTMLEscape: true, + }) + }, + Run: func(cmd *cobra.Command, args []string) { + debug.EnableDebugServer() + akURL := config.Get().AuthentikHost + if akURL == "" { + fmt.Println("env AUTHENTIK_HOST not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + akToken := config.Get().AuthentikToken + if akToken == "" { + fmt.Println("env AUTHENTIK_TOKEN not set!") + fmt.Println(helpMessage) + os.Exit(1) + } - akURLActual, err := url.Parse(akURL) - if err != nil { - fmt.Println(err) - fmt.Println(helpMessage) - os.Exit(1) - } + akURLActual, err := url.Parse(akURL) + if err != nil { + fmt.Println(err) + fmt.Println(helpMessage) + os.Exit(1) + } + + ex := common.Init() + defer common.Defer() + go func() { + for { + <-ex + os.Exit(0) + } + }() + + ac := ak.NewAPIController(*akURLActual, akToken) + if ac == nil { + os.Exit(1) + } + defer ac.Shutdown() + + ac.Server = ldap.NewServer(ac) + + err = ac.Start() + if err != nil { + log.WithError(err).Panic("Failed to run server") + } - ex := common.Init() - defer common.Defer() - go func() { for { <-ex - os.Exit(0) } - }() + }, +} - ac := ak.NewAPIController(*akURLActual, akToken) - if ac == nil { +func main() { + rootCmd.AddCommand(healthcheck.Command) + err := rootCmd.Execute() + if err != nil { os.Exit(1) } - defer ac.Shutdown() - - ac.Server = ldap.NewServer(ac) - - err = ac.Start() - if err != nil { - log.WithError(err).Panic("Failed to run server") - } - - for { - <-ex - } } diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index 52fb6b4bac..e58a161fb6 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -6,11 +6,13 @@ import ( "os" log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" "goauthentik.io/internal/common" "goauthentik.io/internal/config" "goauthentik.io/internal/debug" "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/proxyv2" ) @@ -24,59 +26,72 @@ Required environment variables: Optionally, you can set these: - AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST` -func main() { - log.SetLevel(log.DebugLevel) - log.SetFormatter(&log.JSONFormatter{ - FieldMap: log.FieldMap{ - log.FieldKeyMsg: "event", - log.FieldKeyTime: "timestamp", - }, - DisableHTMLEscape: true, - }) - debug.EnableDebugServer() - akURL := config.Get().AuthentikHost - if akURL == "" { - fmt.Println("env AUTHENTIK_HOST not set!") - fmt.Println(helpMessage) - os.Exit(1) - } - akToken := config.Get().AuthentikToken - if akToken == "" { - fmt.Println("env AUTHENTIK_TOKEN not set!") - fmt.Println(helpMessage) - os.Exit(1) - } +var rootCmd = &cobra.Command{ + Long: helpMessage, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.JSONFormatter{ + FieldMap: log.FieldMap{ + log.FieldKeyMsg: "event", + log.FieldKeyTime: "timestamp", + }, + DisableHTMLEscape: true, + }) + }, + Run: func(cmd *cobra.Command, args []string) { + debug.EnableDebugServer() + akURL := config.Get().AuthentikHost + if akURL == "" { + fmt.Println("env AUTHENTIK_HOST not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + akToken := config.Get().AuthentikToken + if akToken == "" { + fmt.Println("env AUTHENTIK_TOKEN not set!") + fmt.Println(helpMessage) + os.Exit(1) + } - akURLActual, err := url.Parse(akURL) - if err != nil { - fmt.Println(err) - fmt.Println(helpMessage) - os.Exit(1) - } + akURLActual, err := url.Parse(akURL) + if err != nil { + fmt.Println(err) + fmt.Println(helpMessage) + os.Exit(1) + } + + ex := common.Init() + defer common.Defer() + go func() { + for { + <-ex + os.Exit(0) + } + }() + + ac := ak.NewAPIController(*akURLActual, akToken) + if ac == nil { + os.Exit(1) + } + defer ac.Shutdown() + + ac.Server = proxyv2.NewProxyServer(ac) + + err = ac.Start() + if err != nil { + log.WithError(err).Panic("Failed to run server") + } - ex := common.Init() - defer common.Defer() - go func() { for { <-ex - os.Exit(0) } - }() + }, +} - ac := ak.NewAPIController(*akURLActual, akToken) - if ac == nil { +func main() { + rootCmd.AddCommand(healthcheck.Command) + err := rootCmd.Execute() + if err != nil { os.Exit(1) } - defer ac.Shutdown() - - ac.Server = proxyv2.NewProxyServer(ac) - - err = ac.Start() - if err != nil { - log.WithError(err).Panic("Failed to run server") - } - - for { - <-ex - } } diff --git a/cmd/radius/main.go b/cmd/radius/main.go new file mode 100644 index 0000000000..f442cb1017 --- /dev/null +++ b/cmd/radius/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + "net/url" + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "goauthentik.io/internal/common" + "goauthentik.io/internal/debug" + "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/ak/healthcheck" + "goauthentik.io/internal/outpost/radius" +) + +const helpMessage = `authentik radius + +Required environment variables: +- AUTHENTIK_HOST: URL to connect to (format "http://authentik.company") +- AUTHENTIK_TOKEN: Token to authenticate with +- AUTHENTIK_INSECURE: Skip SSL Certificate verification` + +var rootCmd = &cobra.Command{ + Long: helpMessage, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.JSONFormatter{ + FieldMap: log.FieldMap{ + log.FieldKeyMsg: "event", + log.FieldKeyTime: "timestamp", + }, + DisableHTMLEscape: true, + }) + }, + Run: func(cmd *cobra.Command, args []string) { + debug.EnableDebugServer() + akURL, found := os.LookupEnv("AUTHENTIK_HOST") + if !found { + fmt.Println("env AUTHENTIK_HOST not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + akToken, found := os.LookupEnv("AUTHENTIK_TOKEN") + if !found { + fmt.Println("env AUTHENTIK_TOKEN not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + + akURLActual, err := url.Parse(akURL) + if err != nil { + fmt.Println(err) + fmt.Println(helpMessage) + os.Exit(1) + } + + ex := common.Init() + defer common.Defer() + go func() { + for { + <-ex + os.Exit(0) + } + }() + + ac := ak.NewAPIController(*akURLActual, akToken) + if ac == nil { + os.Exit(1) + } + defer ac.Shutdown() + + ac.Server = radius.NewServer(ac) + + err = ac.Start() + if err != nil { + log.WithError(err).Panic("Failed to run server") + } + + for { + <-ex + } + + }, +} + +func main() { + rootCmd.AddCommand(healthcheck.Command) + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/radius/server.go b/cmd/radius/server.go deleted file mode 100644 index 60ce95f1a1..0000000000 --- a/cmd/radius/server.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "os" - - log "github.com/sirupsen/logrus" - - "goauthentik.io/internal/common" - "goauthentik.io/internal/debug" - "goauthentik.io/internal/outpost/ak" - "goauthentik.io/internal/outpost/radius" -) - -const helpMessage = `authentik radius - -Required environment variables: -- AUTHENTIK_HOST: URL to connect to (format "http://authentik.company") -- AUTHENTIK_TOKEN: Token to authenticate with -- AUTHENTIK_INSECURE: Skip SSL Certificate verification` - -func main() { - log.SetLevel(log.DebugLevel) - log.SetFormatter(&log.JSONFormatter{ - FieldMap: log.FieldMap{ - log.FieldKeyMsg: "event", - log.FieldKeyTime: "timestamp", - }, - DisableHTMLEscape: true, - }) - go debug.EnableDebugServer() - akURL, found := os.LookupEnv("AUTHENTIK_HOST") - if !found { - fmt.Println("env AUTHENTIK_HOST not set!") - fmt.Println(helpMessage) - os.Exit(1) - } - akToken, found := os.LookupEnv("AUTHENTIK_TOKEN") - if !found { - fmt.Println("env AUTHENTIK_TOKEN not set!") - fmt.Println(helpMessage) - os.Exit(1) - } - - akURLActual, err := url.Parse(akURL) - if err != nil { - fmt.Println(err) - fmt.Println(helpMessage) - os.Exit(1) - } - - ex := common.Init() - defer common.Defer() - go func() { - for { - <-ex - os.Exit(0) - } - }() - - ac := ak.NewAPIController(*akURLActual, akToken) - if ac == nil { - os.Exit(1) - } - defer ac.Shutdown() - - ac.Server = radius.NewServer(ac) - - err = ac.Start() - if err != nil { - log.WithError(err).Panic("Failed to run server") - } - - for { - <-ex - } -} diff --git a/cmd/server/healthcheck.go b/cmd/server/healthcheck.go index 68618052e4..57ee0f6509 100644 --- a/cmd/server/healthcheck.go +++ b/cmd/server/healthcheck.go @@ -25,7 +25,6 @@ var healthcheckCmd = &cobra.Command{ os.Exit(1) } mode := args[0] - config.Get() exitCode := 1 log.WithField("mode", mode).Debug("checking health") switch strings.ToLower(mode) { diff --git a/internal/outpost/ak/healthcheck/cmd.go b/internal/outpost/ak/healthcheck/cmd.go new file mode 100644 index 0000000000..3b12a5f235 --- /dev/null +++ b/internal/outpost/ak/healthcheck/cmd.go @@ -0,0 +1,38 @@ +package healthcheck + +import ( + "fmt" + "net/http" + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "goauthentik.io/internal/config" + "goauthentik.io/internal/utils/web" +) + +var Command = &cobra.Command{ + Use: "healthcheck", + Run: func(cmd *cobra.Command, args []string) { + config.Get() + os.Exit(check()) + }, +} + +func check() int { + h := &http.Client{ + Transport: web.NewUserAgentTransport("goauthentik.io/healthcheck", http.DefaultTransport), + } + url := fmt.Sprintf("http://%s/outpost.goauthentik.io/ping", config.Get().Listen.Metrics) + res, err := h.Head(url) + if err != nil { + log.WithError(err).Warning("failed to send healthcheck request") + return 1 + } + if res.StatusCode >= 400 { + log.WithField("status", res.StatusCode).Warning("unhealthy status code") + return 1 + } + log.Debug("successfully checked health") + return 0 +} diff --git a/ldap.Dockerfile b/ldap.Dockerfile index 53bdb1dc70..e4177ae19d 100644 --- a/ldap.Dockerfile +++ b/ldap.Dockerfile @@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH COPY --from=builder /go/ldap / -HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ] +HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/ldap", "healthcheck" ] EXPOSE 3389 6636 9300 diff --git a/proxy.Dockerfile b/proxy.Dockerfile index 92338318ee..cb39d09d69 100644 --- a/proxy.Dockerfile +++ b/proxy.Dockerfile @@ -32,7 +32,7 @@ COPY --from=web-builder /static/security.txt /web/security.txt COPY --from=web-builder /static/dist/ /web/dist/ COPY --from=web-builder /static/authentik/ /web/authentik/ -HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ] +HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/proxy", "healthcheck" ] EXPOSE 9000 9300 9443 diff --git a/radius.Dockerfile b/radius.Dockerfile index 1c5abbf6c8..5d8ce345ec 100644 --- a/radius.Dockerfile +++ b/radius.Dockerfile @@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH COPY --from=builder /go/radius / -HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ] +HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/radius", "healthcheck" ] EXPOSE 1812/udp 9300 diff --git a/tests/e2e/test_provider_oidc.py b/tests/e2e/test_provider_oidc.py index a828c446f1..0010591064 100644 --- a/tests/e2e/test_provider_oidc.py +++ b/tests/e2e/test_provider_oidc.py @@ -6,7 +6,6 @@ from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container -from docker.types import Healthcheck from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec @@ -41,14 +40,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): sleep(1) client: DockerClient = from_env() container = client.containers.run( - image="ghcr.io/beryju/oidc-test-client:v1", + image="ghcr.io/beryju/oidc-test-client:1.3", detach=True, network_mode="host", - healthcheck=Healthcheck( - test=["CMD", "wget", "--spider", "http://localhost:9009/health"], - interval=5 * 100 * 1000000, - start_period=1 * 100 * 1000000, - ), environment={ "OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_SECRET": self.client_secret, diff --git a/tests/e2e/test_provider_oidc_implicit.py b/tests/e2e/test_provider_oidc_implicit.py index 4fbdb92a46..0c8b58fd45 100644 --- a/tests/e2e/test_provider_oidc_implicit.py +++ b/tests/e2e/test_provider_oidc_implicit.py @@ -6,7 +6,6 @@ from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container -from docker.types import Healthcheck from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec @@ -41,14 +40,9 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): sleep(1) client: DockerClient = from_env() container = client.containers.run( - image="ghcr.io/beryju/oidc-test-client:v1", + image="ghcr.io/beryju/oidc-test-client:1.3", detach=True, network_mode="host", - healthcheck=Healthcheck( - test=["CMD", "wget", "--spider", "http://localhost:9009/health"], - interval=5 * 100 * 1000000, - start_period=1 * 100 * 1000000, - ), environment={ "OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_SECRET": self.client_secret, diff --git a/tests/e2e/test_provider_saml.py b/tests/e2e/test_provider_saml.py index d54a7304a2..378b65e631 100644 --- a/tests/e2e/test_provider_saml.py +++ b/tests/e2e/test_provider_saml.py @@ -6,7 +6,6 @@ from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container -from docker.types import Healthcheck from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec @@ -40,14 +39,9 @@ class TestProviderSAML(SeleniumTestCase): if force_post: metadata_url += f"&force_binding={SAML_BINDING_POST}" container = client.containers.run( - image="ghcr.io/beryju/saml-test-sp:latest", + image="ghcr.io/beryju/saml-test-sp:1.1", detach=True, network_mode="host", - healthcheck=Healthcheck( - test=["CMD", "wget", "--spider", "http://localhost:9009/health"], - interval=5 * 100 * 1000000, - start_period=1 * 100 * 1000000, - ), environment={ "SP_ENTITY_ID": provider.issuer, "SP_SSO_BINDING": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", diff --git a/website/docs/flow/context/index.md b/website/docs/flow/context/index.md index 5462670408..b4cc18954e 100644 --- a/website/docs/flow/context/index.md +++ b/website/docs/flow/context/index.md @@ -47,9 +47,7 @@ This data can be modified with policies. The data is also used by stages like [U Stores the final redirect URL that the user's browser will be sent to after the flow is finished executing successfully. This is set when an un-authenticated user attempts to access a secured application, and when a user authenticates/enrolls with an external source. -#### Identifications tage - -##### `pending_user_identifier` (string) +#### `pending_user_identifier` (string) If _Show matched user_ is disabled, this key will hold the user identifier entered by the user in the identification stage. @@ -165,7 +163,7 @@ Boolean set to true after the email form the email stage has been sent. Optionally override the email address that the email will be sent to. If not set, defaults to the email of `pending_user`. -#### Identifications tage +#### Identification stage ##### `pending_user_identifier` (string)