diff options
| author | James Elliott <james-d-elliott@users.noreply.github.com> | 2021-08-05 14:02:07 +1000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-05 14:02:07 +1000 | 
| commit | c5c6bda8b066f390b4c0863777dc3eba77fee792 (patch) | |
| tree | de3013cb6f45fd96fe5a822a0cdfe13a66e15f31 | |
| parent | cbedf79f8611c57a5e98f90405c13f85905dbc75 (diff) | |
refactor: configuration agnostic healthcheck (#2231)
This makes the healthcheck simple and configured directly by Authelia's configuration on startup.
| -rw-r--r-- | .dockerignore | 3 | ||||
| -rw-r--r-- | .healthcheck.env | 5 | ||||
| -rw-r--r-- | Dockerfile | 3 | ||||
| -rw-r--r-- | Dockerfile.arm32v7 | 3 | ||||
| -rw-r--r-- | Dockerfile.arm64v8 | 3 | ||||
| -rw-r--r-- | Dockerfile.coverage | 3 | ||||
| -rw-r--r-- | config.template.yml | 4 | ||||
| -rw-r--r-- | docs/configuration/server.md | 18 | ||||
| -rwxr-xr-x | healthcheck.sh | 26 | ||||
| -rw-r--r-- | internal/configuration/config.template.yml | 4 | ||||
| -rw-r--r-- | internal/configuration/schema/server.go | 15 | ||||
| -rw-r--r-- | internal/configuration/validator/const.go | 1 | ||||
| -rw-r--r-- | internal/server/const.go | 8 | ||||
| -rw-r--r-- | internal/server/server.go | 8 | ||||
| -rw-r--r-- | internal/server/template.go | 33 | 
15 files changed, 112 insertions, 25 deletions
diff --git a/.dockerignore b/.dockerignore index 1a3b82626..c14a03acc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -21,3 +21,6 @@ examples  internal/server/public_html  authelia.service  bootstrap.sh + +# Overrides +!.healthcheck.env diff --git a/.healthcheck.env b/.healthcheck.env new file mode 100644 index 000000000..20df13dd0 --- /dev/null +++ b/.healthcheck.env @@ -0,0 +1,5 @@ +# Default Template +X_AUTHELIA_HEALTHCHECK_SCHEME=http +X_AUTHELIA_HEALTHCHECK_HOST=localhost +X_AUTHELIA_HEALTHCHECK_PORT=9091 +X_AUTHELIA_HEALTHCHECK_PATH= diff --git a/Dockerfile b/Dockerfile index ced510a5e..3274125f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,7 @@ ARG LDFLAGS_EXTRA  RUN \  mv public_html internal/server/public_html && \ +chmod 0666 /go/src/app/.healthcheck.env && \  echo ">> Starting go build..." && \  GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags netgo \  -ldflags "-s -w ${LDFLAGS_EXTRA}" -trimpath -o authelia ./cmd/authelia @@ -30,7 +31,7 @@ WORKDIR /app  RUN apk --no-cache add ca-certificates su-exec tzdata -COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./ +COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh /go/src/app/.healthcheck.env ./  EXPOSE 9091 diff --git a/Dockerfile.arm32v7 b/Dockerfile.arm32v7 index bfced427b..ec4724dc9 100644 --- a/Dockerfile.arm32v7 +++ b/Dockerfile.arm32v7 @@ -17,6 +17,7 @@ ARG LDFLAGS_EXTRA  RUN \  mv public_html internal/server/public_html && \ +chmod 0666 /go/src/app/.healthcheck.env && \  echo ">> Starting go build..." && \  GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -tags netgo \  -ldflags "-s -w ${LDFLAGS_EXTRA}" -trimpath -o authelia ./cmd/authelia @@ -31,7 +32,7 @@ WORKDIR /app  RUN \  apk --no-cache add ca-certificates su-exec tzdata -COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./ +COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh /go/src/app/.healthcheck.env ./  EXPOSE 9091 diff --git a/Dockerfile.arm64v8 b/Dockerfile.arm64v8 index 9d0985747..a645e19d7 100644 --- a/Dockerfile.arm64v8 +++ b/Dockerfile.arm64v8 @@ -17,6 +17,7 @@ ARG LDFLAGS_EXTRA  RUN \  mv public_html internal/server/public_html && \ +chmod 0666 /go/src/app/.healthcheck.env && \  echo ">> Starting go build..." && \  GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags netgo \  -ldflags "-s -w ${LDFLAGS_EXTRA}" -trimpath -o authelia ./cmd/authelia @@ -31,7 +32,7 @@ WORKDIR /app  RUN \  apk --no-cache add ca-certificates su-exec tzdata -COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./ +COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh /go/src/app/.healthcheck.env ./  EXPOSE 9091 diff --git a/Dockerfile.coverage b/Dockerfile.coverage index 225ed9a01..6c34d60d2 100644 --- a/Dockerfile.coverage +++ b/Dockerfile.coverage @@ -32,6 +32,7 @@ ARG LDFLAGS_EXTRA  RUN \  mv api internal/server/public_html/api && \  cd cmd/authelia && \ +chmod 0666 /go/src/app/.healthcheck.env && \  echo ">> Starting go build (coverage via go test)..." && \  CGO_ENABLED=0 go test -c --tags coverage -covermode=atomic \  -ldflags "${LDFLAGS_EXTRA}" -o authelia -coverpkg github.com/authelia/authelia/... @@ -45,7 +46,7 @@ RUN apk --no-cache add ca-certificates tzdata  WORKDIR /app -COPY --from=builder-backend /go/src/app/cmd/authelia/authelia /go/src/app/LICENSE /go/src/app/healthcheck.sh ./ +COPY --from=builder-backend /go/src/app/cmd/authelia/authelia /go/src/app/LICENSE /go/src/app/healthcheck.sh /go/src/app/.healthcheck.env ./  EXPOSE 9091 diff --git a/config.template.yml b/config.template.yml index c552a45af..356e909dd 100644 --- a/config.template.yml +++ b/config.template.yml @@ -53,6 +53,10 @@ server:    ## Enables the expvars endpoint.    enable_expvars: false +  ## Disables writing the health check vars to /app/.healthcheck.env which makes healthcheck.sh return exit code 0. +  ## This is disabled by default if either /app/.healthcheck.env or /app/healthcheck.sh do not exist. +  disable_healthcheck: false +    ## Authelia by default doesn't accept TLS communication on the server port. This section overrides this behaviour.    tls:      ## The path to the DER base64/PEM format private key. diff --git a/docs/configuration/server.md b/docs/configuration/server.md index 40172e93a..3acbb5095 100644 --- a/docs/configuration/server.md +++ b/docs/configuration/server.md @@ -20,6 +20,7 @@ server:    write_buffer_size: 4096    enable_pprof: false    enable_expvars: false +  disable_healthcheck: false    tls:      key: ""      certificate: "" @@ -134,6 +135,23 @@ required: no  Enables the go expvars endpoints. +### disable_healthcheck +<div markdown="1"> +type: boolean +{: .label .label-config .label-purple }  +default: false +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +</div> + +On startup Authelia checks for the existence of /app/healthcheck.sh and /app/.healthcheck.env and if both of these exist +it writes the configuration vars for the healthcheck to the /app/.healthcheck.env file. In instances where this is not +desirable it's possible to disable these interactions entirely. + +An example situation where this is the case is in Kubernetes when set security policies that prevent writing to the +ephemeral storage of a container or just don't want to enable the internal health check. +  ### tls  Authelia typically listens for plain unencrypted connections. This is by design as most environments allow to diff --git a/healthcheck.sh b/healthcheck.sh index 147e18d74..afd152fae 100755 --- a/healthcheck.sh +++ b/healthcheck.sh @@ -1,23 +1,21 @@  #!/bin/sh -AUTHELIA_CONFIG=$(pgrep -af authelia | awk '{print $NF}') -AUTHELIA_SCHEME=$(grep ^tls "${AUTHELIA_CONFIG}") -AUTHELIA_HOST=$(grep ^host "${AUTHELIA_CONFIG}" | sed -e 's/host: //' -e 's/\r//') -AUTHELIA_PORT=$(grep ^port "${AUTHELIA_CONFIG}" | sed -e 's/port: //' -e 's/\r//') -AUTHELIA_PATH=$(grep ^\ \ path "${AUTHELIA_CONFIG}" | sed -e 's/  path: //' -e 's/\r//' -e 's/^/\//') +if [ -z "${X_AUTHELIA_HEALTHCHECK}" ]; then +  exit 0 +fi + +source /app/.healthcheck.env -if [ -z "${AUTHELIA_SCHEME}" ]; then -  AUTHELIA_SCHEME=http -else -  AUTHELIA_SCHEME=https +if [ -z "${X_AUTHELIA_HEALTHCHECK_SCHEME}" ]; then +  X_AUTHELIA_HEALTHCHECK_SCHEME=http  fi -if [ -z "${AUTHELIA_HOST}" ] || [ "${AUTHELIA_HOST}" = "0.0.0.0" ]; then -  AUTHELIA_HOST=localhost +if [ -z "${X_AUTHELIA_HEALTHCHECK_HOST}" ]; then +  X_AUTHELIA_HEALTHCHECK_HOST=localhost  fi -if [ -z "${AUTHELIA_PORT}" ]; then -  AUTHELIA_PORT=9091 +if [ -z "${X_AUTHELIA_HEALTHCHECK_PORT}" ]; then +  X_AUTHELIA_HEALTHCHECK_PORT=9091  fi -wget --quiet --no-check-certificate --tries=1 --spider "${AUTHELIA_SCHEME}://${AUTHELIA_HOST}:${AUTHELIA_PORT}${AUTHELIA_PATH}/api/health" || exit 1 +wget --quiet --no-check-certificate --tries=1 --spider "${X_AUTHELIA_HEALTHCHECK_SCHEME}://${X_AUTHELIA_HEALTHCHECK_HOST}:${X_AUTHELIA_HEALTHCHECK_PORT}${X_AUTHELIA_HEALTHCHECK_PATH}/api/health" || exit 1 diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml index c552a45af..356e909dd 100644 --- a/internal/configuration/config.template.yml +++ b/internal/configuration/config.template.yml @@ -53,6 +53,10 @@ server:    ## Enables the expvars endpoint.    enable_expvars: false +  ## Disables writing the health check vars to /app/.healthcheck.env which makes healthcheck.sh return exit code 0. +  ## This is disabled by default if either /app/.healthcheck.env or /app/healthcheck.sh do not exist. +  disable_healthcheck: false +    ## Authelia by default doesn't accept TLS communication on the server port. This section overrides this behaviour.    tls:      ## The path to the DER base64/PEM format private key. diff --git a/internal/configuration/schema/server.go b/internal/configuration/schema/server.go index 07169ad8a..d07165cb0 100644 --- a/internal/configuration/schema/server.go +++ b/internal/configuration/schema/server.go @@ -2,13 +2,14 @@ package schema  // ServerConfiguration represents the configuration of the http server.  type ServerConfiguration struct { -	Host            string `koanf:"host"` -	Port            int    `koanf:"port"` -	Path            string `koanf:"path"` -	ReadBufferSize  int    `koanf:"read_buffer_size"` -	WriteBufferSize int    `koanf:"write_buffer_size"` -	EnablePprof     bool   `koanf:"enable_endpoint_pprof"` -	EnableExpvars   bool   `koanf:"enable_endpoint_expvars"` +	Host               string `koanf:"host"` +	Port               int    `koanf:"port"` +	Path               string `koanf:"path"` +	ReadBufferSize     int    `koanf:"read_buffer_size"` +	WriteBufferSize    int    `koanf:"write_buffer_size"` +	EnablePprof        bool   `koanf:"enable_endpoint_pprof"` +	EnableExpvars      bool   `koanf:"enable_endpoint_expvars"` +	DisableHealthcheck bool   `koanf:"disable_healthcheck"`  	TLS ServerTLSConfiguration `koanf:"tls"`  } diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go index e15420db9..590d56c2c 100644 --- a/internal/configuration/validator/const.go +++ b/internal/configuration/validator/const.go @@ -139,6 +139,7 @@ var ValidKeys = []string{  	"server.path",  	"server.enable_pprof",  	"server.enable_expvars", +	"server.disable_healthcheck",  	"server.tls.key",  	"server.tls.certificate", diff --git a/internal/server/const.go b/internal/server/const.go index 6950d07f5..9251aa95e 100644 --- a/internal/server/const.go +++ b/internal/server/const.go @@ -6,3 +6,11 @@ const apiFile = "openapi.yml"  const indexFile = "index.html"  const dev = "dev" + +const healthCheckEnv = `# Written by Authelia Process +X_AUTHELIA_HEALTHCHECK=1 +X_AUTHELIA_HEALTHCHECK_SCHEME=%s +X_AUTHELIA_HEALTHCHECK_HOST=%s +X_AUTHELIA_HEALTHCHECK_PORT=%d +X_AUTHELIA_HEALTHCHECK_PATH=%s +` diff --git a/internal/server/server.go b/internal/server/server.go index ef5c2f6ce..a12eb850e 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -192,9 +192,17 @@ func Start(configuration schema.Configuration, providers middlewares.Providers)  	}  	if configuration.Server.TLS.Certificate != "" && configuration.Server.TLS.Key != "" { +		if err = writeHealthCheckEnv(configuration.Server.DisableHealthcheck, "https", configuration.Server.Host, configuration.Server.Path, configuration.Server.Port); err != nil { +			logger.Fatalf("Could not configure healthcheck: %v", err) +		} +  		logger.Infof("Listening for TLS connections on %s%s", addrPattern, configuration.Server.Path)  		logger.Fatal(server.ServeTLS(listener, configuration.Server.TLS.Certificate, configuration.Server.TLS.Key))  	} else { +		if err = writeHealthCheckEnv(configuration.Server.DisableHealthcheck, "http", configuration.Server.Host, configuration.Server.Path, configuration.Server.Port); err != nil { +			logger.Fatalf("Could not configure healthcheck: %v", err) +		} +  		logger.Infof("Listening for non-TLS connections on %s%s", addrPattern, configuration.Server.Path)  		logger.Fatal(server.Serve(listener))  	} diff --git a/internal/server/template.go b/internal/server/template.go index 1c65fb55f..70c327fd0 100644 --- a/internal/server/template.go +++ b/internal/server/template.go @@ -64,3 +64,36 @@ func ServeTemplatedFile(publicDir, file, base, rememberMe, resetPassword, sessio  		}  	}  } + +func writeHealthCheckEnv(disabled bool, scheme, host, path string, port int) (err error) { +	if disabled { +		return nil +	} + +	_, err = os.Stat("/app/healthcheck.sh") +	if err != nil { +		return nil +	} + +	_, err = os.Stat("/app/.healthcheck.env") +	if err != nil { +		return nil +	} + +	file, err := os.OpenFile("/app/.healthcheck.env", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) +	if err != nil { +		return err +	} + +	defer func() { +		_ = file.Close() +	}() + +	if host == "0.0.0.0" { +		host = "localhost" +	} + +	_, err = file.WriteString(fmt.Sprintf(healthCheckEnv, scheme, host, port, path)) + +	return err +}  | 
