feat(configuration): env config file discovery (#4618)

This allows Authelia to discover config files and config options via environment variables.

Co-authored-by: Amir Zarrinkafsh <nightah@me.com>
pull/4632/head
James Elliott 2022-12-23 11:03:50 +11:00 committed by GitHub
parent 18032dd05d
commit 0130edb870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 94 additions and 47 deletions

View File

@ -11,15 +11,16 @@ WORKDIR /app
# Set environment variables
ENV PATH="/app:${PATH}" \
PUID=0 \
PGID=0
PGID=0 \
X_AUTHELIA_CONFIG="/config/configuration.yml"
RUN \
apk --no-cache add ca-certificates su-exec tzdata
apk --no-cache add ca-certificates su-exec tzdata
COPY LICENSE .healthcheck.env entrypoint.sh healthcheck.sh ./
RUN \
chmod 0666 /app/.healthcheck.env
chmod 0666 /app/.healthcheck.env
COPY authelia-${TARGETOS}-${TARGETARCH}-musl ./authelia
@ -28,5 +29,4 @@ EXPOSE 9091
VOLUME /config
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["--config", "/config/configuration.yml"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=1m CMD /app/healthcheck.sh

View File

@ -20,14 +20,14 @@ FROM golang:1.19.4-alpine AS builder-backend
WORKDIR /go/src/app
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
echo ">> Downloading go modules..." && \
go mod download
COPY / ./
@ -36,12 +36,12 @@ COPY --from=builder-frontend /node/src/internal/server/public_html internal/serv
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=1 CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong" CGO_LDFLAGS="-Wl,-z,relro,-z,now" go test -c --tags coverage -covermode=atomic \
-ldflags "${LDFLAGS_EXTRA}" -o authelia -coverpkg github.com/authelia/authelia/...
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=1 CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong" CGO_LDFLAGS="-Wl,-z,relro,-z,now" go test -c --tags coverage -covermode=atomic \
-ldflags "${LDFLAGS_EXTRA}" -o authelia -coverpkg github.com/authelia/authelia/...
# ===================================
# ===== Authelia official image =====
@ -58,7 +58,8 @@ EXPOSE 9091
VOLUME /config
ENV PATH="/app:${PATH}"
ENV PATH="/app:${PATH}" \
X_AUTHELIA_CONFIG="/config/configuration.yml"
CMD ["authelia", "-test.coverprofile=/authelia/coverage.txt", "COVERAGE", "--config", "/config/configuration.yml"]
CMD ["authelia", "-test.coverprofile=/authelia/coverage.txt", "COVERAGE"]
HEALTHCHECK --interval=30s --timeout=3s CMD /app/healthcheck.sh

View File

@ -18,14 +18,14 @@ FROM golang:1.19.4-alpine AS builder-backend
WORKDIR /go/src/app
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
echo ">> Downloading go modules..." && \
go mod download
COPY / ./
@ -34,11 +34,11 @@ COPY --from=builder-frontend /node/src/internal/server/public_html internal/serv
ARG LDFLAGS_EXTRA
RUN \
mv api internal/server/public_html/api && \
chmod 0666 /go/src/app/.healthcheck.env && \
echo ">> Starting go build..." && \
CGO_ENABLED=1 CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong" CGO_LDFLAGS="-Wl,-z,relro,-z,now" go build \
-ldflags "-linkmode=external -s -w ${LDFLAGS_EXTRA}" -trimpath -buildmode=pie -o authelia ./cmd/authelia
mv api internal/server/public_html/api && \
chmod 0666 /go/src/app/.healthcheck.env && \
echo ">> Starting go build..." && \
CGO_ENABLED=1 CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong" CGO_LDFLAGS="-Wl,-z,relro,-z,now" go build \
-ldflags "-linkmode=external -s -w ${LDFLAGS_EXTRA}" -trimpath -buildmode=pie -o authelia ./cmd/authelia
# ===================================
# ===== Authelia official image =====
@ -50,20 +50,20 @@ WORKDIR /app
# Set environment variables
ENV PATH="/app:${PATH}" \
PUID=0 \
PGID=0
PGID=0 \
X_AUTHELIA_CONFIG="/config/configuration.yml"
RUN \
apk --no-cache add ca-certificates su-exec tzdata
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 /go/src/app/.healthcheck.env ./
RUN \
chmod 0666 /app/.healthcheck.env
chmod 0666 /app/.healthcheck.env
EXPOSE 9091
VOLUME /config
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["--config", "/config/configuration.yml"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=1m CMD /app/healthcheck.sh

View File

@ -12,18 +12,23 @@ weight: 101200
toc: true
---
## Loading Behaviour
## Loading Behaviour and Discovery
There are several options which affect the loading of files:
| Name | Argument | Description |
|:-----------------:|:-------------------------------:|:----------------------------------------------------------------------------------:|
| Files/Directories | `--config`, `-c` | A list of file or directory (non-recursive) paths to load configuration files from |
| Filters | `--config.experimental.filters` | A list of filters applied to every file from the Files or Directories options |
| Name | Argument | Environment Variable | Description |
|:-----------------:|:-------------------------------:|:---------------------------:|:----------------------------------------------------------------------------------:|
| Files/Directories | `--config`, `-c` | `X_AUTHELIA_CONFIG` | A list of file or directory (non-recursive) paths to load configuration files from |
| Filters | `--config.experimental.filters` | `X_AUTHELIA_CONFIG_FILTERS` | A list of filters applied to every file from the Files or Directories options |
__*Note:* when specifying directories and files, the individual files specified must not be within any of the
directories specified.__
Configuration options can be discovered via either the Argument or Environment Variable, but not both at the same time.
If both are specified the Argument takes precedence and the Environment Variable is ignored. It is generally recommended
that if you're using a container that you use the Environment Variable as this will allow you to execute other commands
from the context of the container more easily.
## Formats
The only supported configuration file format is [YAML](#yaml).

View File

@ -537,9 +537,11 @@ const (
cmdConfigDefaultContainer = "/config/configuration.yml"
cmdConfigDefaultDaemon = "/etc/authelia/configuration.yml"
cmdFlagNameConfig = "config"
cmdFlagNameConfig = "config"
cmdFlagEnvNameConfig = "X_AUTHELIA_CONFIG"
cmdFlagNameConfigExpFilters = "config.experimental.filters"
cmdFlagEnvNameConfigFilters = "X_AUTHELIA_CONFIG_FILTERS"
cmdFlagNameCharSet = "charset"
cmdFlagValueCharSet = "alphanumeric"
@ -655,4 +657,42 @@ The following filters are available:
'expand-env' filter for example.
For a full list of functions see: https://www.authelia.com/configuration/methods/files/#functions`
helpTopicConfig = `Configuration can be specified in multiple layers where each layer is a different source from
the last. The layers are loaded in the order below where each layer potentially overrides the individual settings from
previous layers with the individual settings it provides (i.e. if the same setting is specified twice).
Layers:
- File/Directory Paths
- Environment Variables
- Secrets
File/Directory Paths:
File/Directory Paths can be specified either via the '--config' CLI argument or the 'X_AUTHELIA_CONFIG' environment
variable. If both the environment variable AND the CLI argument are specified the environment variable is completely
ignored. These values both take lists separated by commas.
Directories that are loaded via this method load all files with relevant extensions from the directory, this is not
recursive. This means all files with these extensions must be Authelia configuration files with valid syntax.
The paths specified are loaded in order, where individual settings specified by later files potentially overrides
individual settings by later files (i.e. if the same setting is specified twice). Files specified Files in
directories are loaded in lexicographic order.
The files loaded via this method can be interpolated or templated via the configuration filters. Read more about
this topic by running: authelia -h authelia filters
Environment Variables:
Most configuration options in Authelia can be specified via an environment variable. The available options and the
specific environment variable mapping can be found here: https://www.authelia.com/configuration/methods/environment/
Secrets:
Some configuration options in Authelia can be specified via an environment variable which refers to the location of
a file; also known as a secret. Every configuration key that ends with the following strings can be loaded in this
way: 'key', 'secret', 'password', 'token'.
The available options and the specific secret mapping can be found here: https://www.authelia.com/configuration/methods/secrets/`
)

View File

@ -277,7 +277,7 @@ func (ctx *CmdCtx) ConfigEnsureExistsRunE(cmd *cobra.Command, _ []string) (err e
result XEnvCLIResult
)
if configs, result, err = loadXEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfig); err != nil {
if configs, result, err = loadXEnvCLIStringSliceValue(cmd, cmdFlagEnvNameConfig, cmdFlagNameConfig); err != nil {
return err
}

View File

@ -45,9 +45,9 @@ func NewRootCmd() (cmd *cobra.Command) {
DisableAutoGenTag: true,
}
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", []string{"configuration.yml"}, "configuration files or directories to load")
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", []string{"configuration.yml"}, "configuration files or directories to load, for more information run 'authelia -h authelia config'")
cmd.PersistentFlags().StringSlice(cmdFlagNameConfigExpFilters, nil, "list of filters to apply to all configuration files, for more information: authelia --help authelia filters")
cmd.PersistentFlags().StringSlice(cmdFlagNameConfigExpFilters, nil, "list of filters to apply to all configuration files, for more information run 'authelia -h authelia filters'")
cmd.AddCommand(
newAccessControlCommand(ctx),
@ -56,7 +56,8 @@ func NewRootCmd() (cmd *cobra.Command) {
newStorageCmd(ctx),
newValidateConfigCmd(ctx),
newHelpTopic("filters", "Help for the config filters", helpTopicConfigFilters),
newHelpTopic("config", "Help for the config file/directory paths", helpTopicConfig),
newHelpTopic("filters", "help topic for the config filters", helpTopicConfigFilters),
)
return cmd

View File

@ -246,7 +246,7 @@ func loadXEnvCLIConfigValues(cmd *cobra.Command) (configs []string, filters []co
filterNames []string
)
if configs, _, err = loadXEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfig); err != nil {
if configs, _, err = loadXEnvCLIStringSliceValue(cmd, cmdFlagEnvNameConfig, cmdFlagNameConfig); err != nil {
return nil, nil, err
}
@ -254,7 +254,7 @@ func loadXEnvCLIConfigValues(cmd *cobra.Command) (configs []string, filters []co
return nil, nil, err
}
if filterNames, _, err = loadXEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfigExpFilters); err != nil {
if filterNames, _, err = loadXEnvCLIStringSliceValue(cmd, cmdFlagEnvNameConfigFilters, cmdFlagNameConfigExpFilters); err != nil {
return nil, nil, err
}

View File

@ -11,7 +11,8 @@ RUN mkdir -p /config && chown dev:dev /config
USER dev
ENV PATH="/app:${PATH}"
ENV PATH="/app:${PATH}" \
X_AUTHELIA_CONFIG="/config/configuration.yml"
VOLUME /config

View File

@ -4,7 +4,6 @@ ARG USER_ID
ARG GROUP_ID
RUN yarn global add pnpm && \
pnpm config set --global store-dir /tmp/.pnpm-store && \
deluser node && \
addgroup --gid ${GROUP_ID} dev && \
adduser --uid ${USER_ID} -G dev -D dev

View File

@ -14,7 +14,7 @@ services:
volumes:
- './example/compose/authelia/resources/:/resources'
- '../../web:/app'
- '~/.local/share/pnpm/store:/tmp/.pnpm-store'
- '~/.local/share/pnpm/store:/app/.pnpm-store'
labels:
# Traefik 1.x
- 'traefik.frontend.rule=Host:login.example.com'

View File

@ -4,6 +4,6 @@ set -e
while true;
do
AUTHELIA_SERVER_DISABLE_HEALTHCHECK=true CGO_ENABLED=1 dlv --listen 0.0.0.0:2345 --headless=true --output=./authelia --continue --accept-multiclient debug cmd/authelia/*.go -- --config /config/configuration.yml
AUTHELIA_SERVER_DISABLE_HEALTHCHECK=true CGO_ENABLED=1 dlv --listen 0.0.0.0:2345 --headless=true --output=./authelia --continue --accept-multiclient debug cmd/authelia/*.go
sleep 10
done

View File

@ -10,7 +10,7 @@ import (
"testing"
"github.com/stretchr/testify/suite"
yaml "gopkg.in/yaml.v3"
"gopkg.in/yaml.v3"
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/storage"
@ -73,7 +73,7 @@ func (s *CLISuite) TestShouldPrintVersion() {
}
func (s *CLISuite) TestShouldValidateConfig() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "validate-config", "--config=/config/configuration.yml"})
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "validate-config"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Configuration parsed and loaded successfully without errors.")
}