root: optimise healthchecks (#5337)

* tests: remove redundant healthchecks

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* internal: do healthcheck within proxy instead of wget to use correct port

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tags

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-04-21 13:32:48 +03:00 committed by GitHub
parent 055ead54b5
commit 367f86ecfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 264 additions and 201 deletions

View File

@ -6,11 +6,13 @@ import (
"os" "os"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/config" "goauthentik.io/internal/config"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/ldap" "goauthentik.io/internal/outpost/ldap"
) )
@ -21,59 +23,72 @@ Required environment variables:
- AUTHENTIK_TOKEN: Token to authenticate with - AUTHENTIK_TOKEN: Token to authenticate with
- AUTHENTIK_INSECURE: Skip SSL Certificate verification` - AUTHENTIK_INSECURE: Skip SSL Certificate verification`
func main() { var rootCmd = &cobra.Command{
log.SetLevel(log.DebugLevel) Long: helpMessage,
log.SetFormatter(&log.JSONFormatter{ PersistentPreRun: func(cmd *cobra.Command, args []string) {
FieldMap: log.FieldMap{ log.SetLevel(log.DebugLevel)
log.FieldKeyMsg: "event", log.SetFormatter(&log.JSONFormatter{
log.FieldKeyTime: "timestamp", FieldMap: log.FieldMap{
}, log.FieldKeyMsg: "event",
DisableHTMLEscape: true, log.FieldKeyTime: "timestamp",
}) },
debug.EnableDebugServer() DisableHTMLEscape: true,
akURL := config.Get().AuthentikHost })
if akURL == "" { },
fmt.Println("env AUTHENTIK_HOST not set!") Run: func(cmd *cobra.Command, args []string) {
fmt.Println(helpMessage) debug.EnableDebugServer()
os.Exit(1) akURL := config.Get().AuthentikHost
} if akURL == "" {
akToken := config.Get().AuthentikToken fmt.Println("env AUTHENTIK_HOST not set!")
if akToken == "" { fmt.Println(helpMessage)
fmt.Println("env AUTHENTIK_TOKEN not set!") os.Exit(1)
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) akURLActual, err := url.Parse(akURL)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println(helpMessage) fmt.Println(helpMessage)
os.Exit(1) 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 { for {
<-ex <-ex
os.Exit(0)
} }
}() },
}
ac := ak.NewAPIController(*akURLActual, akToken) func main() {
if ac == nil { rootCmd.AddCommand(healthcheck.Command)
err := rootCmd.Execute()
if err != nil {
os.Exit(1) 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
}
} }

View File

@ -6,11 +6,13 @@ import (
"os" "os"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/config" "goauthentik.io/internal/config"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/proxyv2" "goauthentik.io/internal/outpost/proxyv2"
) )
@ -24,59 +26,72 @@ Required environment variables:
Optionally, you can set these: Optionally, you can set these:
- AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST` - AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST`
func main() { var rootCmd = &cobra.Command{
log.SetLevel(log.DebugLevel) Long: helpMessage,
log.SetFormatter(&log.JSONFormatter{ PersistentPreRun: func(cmd *cobra.Command, args []string) {
FieldMap: log.FieldMap{ log.SetLevel(log.DebugLevel)
log.FieldKeyMsg: "event", log.SetFormatter(&log.JSONFormatter{
log.FieldKeyTime: "timestamp", FieldMap: log.FieldMap{
}, log.FieldKeyMsg: "event",
DisableHTMLEscape: true, log.FieldKeyTime: "timestamp",
}) },
debug.EnableDebugServer() DisableHTMLEscape: true,
akURL := config.Get().AuthentikHost })
if akURL == "" { },
fmt.Println("env AUTHENTIK_HOST not set!") Run: func(cmd *cobra.Command, args []string) {
fmt.Println(helpMessage) debug.EnableDebugServer()
os.Exit(1) akURL := config.Get().AuthentikHost
} if akURL == "" {
akToken := config.Get().AuthentikToken fmt.Println("env AUTHENTIK_HOST not set!")
if akToken == "" { fmt.Println(helpMessage)
fmt.Println("env AUTHENTIK_TOKEN not set!") os.Exit(1)
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) akURLActual, err := url.Parse(akURL)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println(helpMessage) fmt.Println(helpMessage)
os.Exit(1) 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 { for {
<-ex <-ex
os.Exit(0)
} }
}() },
}
ac := ak.NewAPIController(*akURLActual, akToken) func main() {
if ac == nil { rootCmd.AddCommand(healthcheck.Command)
err := rootCmd.Execute()
if err != nil {
os.Exit(1) 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
}
} }

94
cmd/radius/main.go Normal file
View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -25,7 +25,6 @@ var healthcheckCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
mode := args[0] mode := args[0]
config.Get()
exitCode := 1 exitCode := 1
log.WithField("mode", mode).Debug("checking health") log.WithField("mode", mode).Debug("checking health")
switch strings.ToLower(mode) { switch strings.ToLower(mode) {

View File

@ -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
}

View File

@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
COPY --from=builder /go/ldap / 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 EXPOSE 3389 6636 9300

View File

@ -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/dist/ /web/dist/
COPY --from=web-builder /static/authentik/ /web/authentik/ 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 EXPOSE 9000 9300 9443

View File

@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
COPY --from=builder /go/radius / 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 EXPOSE 1812/udp 9300

View File

@ -6,7 +6,6 @@ from unittest.case import skipUnless
from docker import DockerClient, from_env from docker import DockerClient, from_env
from docker.models.containers import Container from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support import expected_conditions as ec
@ -41,14 +40,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
sleep(1) sleep(1)
client: DockerClient = from_env() client: DockerClient = from_env()
container = client.containers.run( container = client.containers.run(
image="ghcr.io/beryju/oidc-test-client:v1", image="ghcr.io/beryju/oidc-test-client:1.3",
detach=True, detach=True,
network_mode="host", network_mode="host",
healthcheck=Healthcheck(
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
interval=5 * 100 * 1000000,
start_period=1 * 100 * 1000000,
),
environment={ environment={
"OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_ID": self.client_id,
"OIDC_CLIENT_SECRET": self.client_secret, "OIDC_CLIENT_SECRET": self.client_secret,

View File

@ -6,7 +6,6 @@ from unittest.case import skipUnless
from docker import DockerClient, from_env from docker import DockerClient, from_env
from docker.models.containers import Container from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support import expected_conditions as ec
@ -41,14 +40,9 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
sleep(1) sleep(1)
client: DockerClient = from_env() client: DockerClient = from_env()
container = client.containers.run( container = client.containers.run(
image="ghcr.io/beryju/oidc-test-client:v1", image="ghcr.io/beryju/oidc-test-client:1.3",
detach=True, detach=True,
network_mode="host", network_mode="host",
healthcheck=Healthcheck(
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
interval=5 * 100 * 1000000,
start_period=1 * 100 * 1000000,
),
environment={ environment={
"OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_ID": self.client_id,
"OIDC_CLIENT_SECRET": self.client_secret, "OIDC_CLIENT_SECRET": self.client_secret,

View File

@ -6,7 +6,6 @@ from unittest.case import skipUnless
from docker import DockerClient, from_env from docker import DockerClient, from_env
from docker.models.containers import Container from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support import expected_conditions as ec
@ -40,14 +39,9 @@ class TestProviderSAML(SeleniumTestCase):
if force_post: if force_post:
metadata_url += f"&force_binding={SAML_BINDING_POST}" metadata_url += f"&force_binding={SAML_BINDING_POST}"
container = client.containers.run( container = client.containers.run(
image="ghcr.io/beryju/saml-test-sp:latest", image="ghcr.io/beryju/saml-test-sp:1.1",
detach=True, detach=True,
network_mode="host", network_mode="host",
healthcheck=Healthcheck(
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
interval=5 * 100 * 1000000,
start_period=1 * 100 * 1000000,
),
environment={ environment={
"SP_ENTITY_ID": provider.issuer, "SP_ENTITY_ID": provider.issuer,
"SP_SSO_BINDING": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", "SP_SSO_BINDING": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",

View File

@ -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. 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. 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`. 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) ##### `pending_user_identifier` (string)