forked from Nixius/authelia
Bake git commit into Go binary for version traceability
- Add internal/version package with ldflags-injected Commit/BuildTime - Dockerfile accepts BUILD_COMMIT/BUILD_TIME args, passes via -ldflags - Log version on startup, expose GET /version endpoint - Show commit hash badge in bottom-right of landing + dashboard pages - Deploy scripts gate on clean git tree and pass commit to build - Remove staging files, misc config updates Made-with: Cursor
This commit is contained in:
parent
c3097bd8fe
commit
6fcdd1262d
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Authelia – stable/done; keep out of context for ss-atlas and other work
|
||||||
|
docker/authelia/
|
||||||
|
authelia-dev-config.yml
|
||||||
|
docker/mariadb/
|
||||||
|
docker/redis/
|
||||||
103
.woodpecker.yml
103
.woodpecker.yml
|
|
@ -19,109 +19,6 @@ steps:
|
||||||
when:
|
when:
|
||||||
event: push
|
event: push
|
||||||
|
|
||||||
# Build and Push for Staging
|
|
||||||
build-push-staging:
|
|
||||||
name: build-push-staging
|
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
|
||||||
environment:
|
|
||||||
REGISTRY_USER:
|
|
||||||
from_secret: REGISTRY_USER
|
|
||||||
REGISTRY_PASSWORD:
|
|
||||||
from_secret: REGISTRY_PASSWORD
|
|
||||||
DOCKER_REGISTRY_USER:
|
|
||||||
from_secret: DOCKER_REGISTRY_USER
|
|
||||||
DOCKER_REGISTRY_PASSWORD:
|
|
||||||
from_secret: DOCKER_REGISTRY_PASSWORD
|
|
||||||
# Authelia Core Secrets
|
|
||||||
AUTHENTICATION_BACKEND_LDAP_PASSWORD:
|
|
||||||
from_secret: AUTHENTICATION_BACKEND_LDAP_PASSWORD
|
|
||||||
IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET:
|
|
||||||
from_secret: IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET
|
|
||||||
STORAGE_ENCRYPTION_KEY:
|
|
||||||
from_secret: STORAGE_ENCRYPTION_KEY
|
|
||||||
SESSION_SECRET:
|
|
||||||
from_secret: SESSION_SECRET
|
|
||||||
NOTIFIER_SMTP_PASSWORD:
|
|
||||||
from_secret: NOTIFIER_SMTP_PASSWORD
|
|
||||||
# OIDC Secrets
|
|
||||||
IDENTITY_PROVIDERS_OIDC_HMAC_SECRET:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_HMAC_SECRET
|
|
||||||
IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY
|
|
||||||
IDENTITY_PROVIDERS_OIDC_JWKS_KEY:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_JWKS_KEY
|
|
||||||
# OAuth Client Secrets removed - handled by Docker Swarm secrets at runtime
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
commands:
|
|
||||||
- echo "Logging into registries"
|
|
||||||
- echo "$${DOCKER_REGISTRY_PASSWORD}" | docker login -u "$${DOCKER_REGISTRY_USER}" --password-stdin
|
|
||||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
|
||||||
- echo "Building and pushing application for staging"
|
|
||||||
- docker compose -f docker-compose.staging.yml build --no-cache
|
|
||||||
- docker compose -f docker-compose.staging.yml push
|
|
||||||
when:
|
|
||||||
branch: main
|
|
||||||
event: push
|
|
||||||
|
|
||||||
# Deploy Staging
|
|
||||||
deploy-staging:
|
|
||||||
name: deploy-staging
|
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
|
||||||
environment:
|
|
||||||
REGISTRY_USER:
|
|
||||||
from_secret: REGISTRY_USER
|
|
||||||
REGISTRY_PASSWORD:
|
|
||||||
from_secret: REGISTRY_PASSWORD
|
|
||||||
# Authelia Core Secrets
|
|
||||||
AUTHENTICATION_BACKEND_LDAP_PASSWORD:
|
|
||||||
from_secret: AUTHENTICATION_BACKEND_LDAP_PASSWORD
|
|
||||||
IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET:
|
|
||||||
from_secret: IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET
|
|
||||||
STORAGE_ENCRYPTION_KEY:
|
|
||||||
from_secret: STORAGE_ENCRYPTION_KEY
|
|
||||||
SESSION_SECRET:
|
|
||||||
from_secret: SESSION_SECRET
|
|
||||||
NOTIFIER_SMTP_PASSWORD:
|
|
||||||
from_secret: NOTIFIER_SMTP_PASSWORD
|
|
||||||
# OIDC Secrets
|
|
||||||
IDENTITY_PROVIDERS_OIDC_HMAC_SECRET:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_HMAC_SECRET
|
|
||||||
IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY
|
|
||||||
IDENTITY_PROVIDERS_OIDC_JWKS_KEY:
|
|
||||||
from_secret: IDENTITY_PROVIDERS_OIDC_JWKS_KEY
|
|
||||||
# OAuth Client Secrets removed - handled by Docker Swarm secrets at runtime
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
commands:
|
|
||||||
- echo "Deploying to staging environment"
|
|
||||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
|
||||||
- docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging
|
|
||||||
when:
|
|
||||||
branch: main
|
|
||||||
event: push
|
|
||||||
|
|
||||||
# Cleanup Staging
|
|
||||||
cleanup-staging:
|
|
||||||
name: cleanup-staging
|
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
|
||||||
environment:
|
|
||||||
REGISTRY_USER:
|
|
||||||
from_secret: REGISTRY_USER
|
|
||||||
REGISTRY_PASSWORD:
|
|
||||||
from_secret: REGISTRY_PASSWORD
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
commands:
|
|
||||||
- echo "Cleaning up staging environment"
|
|
||||||
- for i in {1..5}; do docker stack rm ${CI_REPO_NAME}-staging && break || sleep 10; done
|
|
||||||
- docker compose -f docker-compose.staging.yml down
|
|
||||||
- docker compose -f docker-compose.staging.yml rm -f
|
|
||||||
when:
|
|
||||||
branch: main
|
|
||||||
event: push
|
|
||||||
|
|
||||||
# Build and Push for Production
|
# Build and Push for Production
|
||||||
build-push-production:
|
build-push-production:
|
||||||
name: build-push-production
|
name: build-push-production
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,9 @@ services:
|
||||||
build:
|
build:
|
||||||
context: ./docker/ss-atlas/
|
context: ./docker/ss-atlas/
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
BUILD_COMMIT: ${BUILD_COMMIT:-unknown}
|
||||||
|
BUILD_TIME: ${BUILD_TIME:-unknown}
|
||||||
container_name: atlas_ss_app
|
container_name: atlas_ss_app
|
||||||
environment:
|
environment:
|
||||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-sk_test_placeholder}
|
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-sk_test_placeholder}
|
||||||
|
|
@ -211,6 +214,7 @@ services:
|
||||||
- AUTHELIA_URL=http://login.bc.a250.ca
|
- AUTHELIA_URL=http://login.bc.a250.ca
|
||||||
- TRAEFIK_DOMAIN=bc.a250.ca
|
- TRAEFIK_DOMAIN=bc.a250.ca
|
||||||
- TRAEFIK_NETWORK=authelia_dev
|
- TRAEFIK_NETWORK=authelia_dev
|
||||||
|
- CUSTOMER_DOMAIN=app.a250.ca
|
||||||
- TEMPLATE_PATH=/app/templates
|
- TEMPLATE_PATH=/app/templates
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
mariadb:
|
|
||||||
build:
|
|
||||||
context: ./docker/mariadb/
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
image: git.nixc.us/a250/authelia:staging-mariadb
|
|
||||||
redis:
|
|
||||||
build:
|
|
||||||
context: ./docker/redis/
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
image: git.nixc.us/a250/authelia:staging-redis
|
|
||||||
authelia:
|
|
||||||
build:
|
|
||||||
context: ./docker/authelia/
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
image: git.nixc.us/a250/authelia:staging-authelia
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Override for local swarm: overlay network so customer stacks attach to Traefik.
|
||||||
|
# Traefik stays in container mode (swarmMode=false) so it sees both compose and stack containers.
|
||||||
|
#
|
||||||
|
# Usage: ./scripts/deploy-stack-dev.sh
|
||||||
|
# Customer stacks get clientname.app.a250.ca. Run scripts/local-dns-setup.sh for DNS.
|
||||||
|
|
||||||
|
services:
|
||||||
|
ss-atlas:
|
||||||
|
environment:
|
||||||
|
- CUSTOMER_DOMAIN=app.a250.ca
|
||||||
|
|
||||||
|
networks:
|
||||||
|
authelia_dev:
|
||||||
|
external: true
|
||||||
|
|
@ -1 +1,11 @@
|
||||||
FROM git.nixc.us/a250/authelia:staging-authelia
|
FROM authelia/authelia:4
|
||||||
|
|
||||||
|
COPY config/ /config/
|
||||||
|
|
||||||
|
RUN mkdir -p /config/assets
|
||||||
|
|
||||||
|
CMD ["authelia", \
|
||||||
|
"--config=/config/configuration.server.yml", \
|
||||||
|
"--config=/config/configuration.ldap.yml", \
|
||||||
|
"--config=/config/configuration.acl.yml", \
|
||||||
|
"--config=/config/configuration.notifier.yml"]
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,12 @@ access_control:
|
||||||
- "group:customers"
|
- "group:customers"
|
||||||
policy: one_factor
|
policy: one_factor
|
||||||
|
|
||||||
|
# Customer demo subdomains (e.g. clientname.app.a250.ca)
|
||||||
|
- domain_regex: '^[a-z0-9-]+\.app\.a250\.ca$'
|
||||||
|
subject:
|
||||||
|
- "group:customers"
|
||||||
|
policy: one_factor
|
||||||
|
|
||||||
# ss-atlas app public routes (landing, webhook)
|
# ss-atlas app public routes (landing, webhook)
|
||||||
- domain: 'app.{{ env "TRAEFIK_DOMAIN" }}'
|
- domain: 'app.{{ env "TRAEFIK_DOMAIN" }}'
|
||||||
policy: bypass
|
policy: bypass
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ authentication_backend:
|
||||||
refresh_interval: 5m
|
refresh_interval: 5m
|
||||||
ldap:
|
ldap:
|
||||||
implementation: custom
|
implementation: custom
|
||||||
address: ldap://lldap_lldap:3890
|
address: ldap://lldap:3890
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
start_tls: false
|
start_tls: false
|
||||||
tls:
|
tls:
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ storage:
|
||||||
# local:
|
# local:
|
||||||
# path: /config/db.sqlite3
|
# path: /config/db.sqlite3
|
||||||
mysql:
|
mysql:
|
||||||
address: 'tcp://authelia_mariadb:3306'
|
address: 'tcp://mariadb:3306'
|
||||||
database: authelia
|
database: authelia
|
||||||
username: authelia
|
username: authelia
|
||||||
## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
## Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
||||||
|
|
@ -66,7 +66,7 @@ session:
|
||||||
remember_me: '1d'
|
remember_me: '1d'
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
host: 'authelia_redis'
|
host: 'redis'
|
||||||
port: 6379
|
port: 6379
|
||||||
database_index: 0
|
database_index: 0
|
||||||
maximum_active_connections: 8
|
maximum_active_connections: 8
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
FROM git.nixc.us/a250/authelia:staging-mariadb
|
FROM mariadb:latest
|
||||||
|
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
FROM git.nixc.us/a250/authelia:staging-redis
|
FROM redis:latest
|
||||||
|
|
||||||
|
CMD ["redis-server", "--appendonly", "yes"]
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
FROM golang:1.23-alpine AS builder
|
FROM golang:1.23-alpine AS builder
|
||||||
|
|
||||||
|
ARG BUILD_COMMIT=unknown
|
||||||
|
ARG BUILD_TIME=unknown
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /ss-atlas ./cmd/
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
|
-ldflags "-X git.nixc.us/a250/ss-atlas/internal/version.Commit=${BUILD_COMMIT} -X git.nixc.us/a250/ss-atlas/internal/version.BuildTime=${BUILD_TIME}" \
|
||||||
|
-o /ss-atlas ./cmd/
|
||||||
|
|
||||||
FROM alpine:3.21
|
FROM alpine:3.21
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates docker-cli
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /ss-atlas /app/ss-atlas
|
COPY --from=builder /ss-atlas /app/ss-atlas
|
||||||
COPY templates/ /app/templates/
|
COPY templates/ /app/templates/
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,11 @@ import (
|
||||||
"git.nixc.us/a250/ss-atlas/internal/ldap"
|
"git.nixc.us/a250/ss-atlas/internal/ldap"
|
||||||
ssstripe "git.nixc.us/a250/ss-atlas/internal/stripe"
|
ssstripe "git.nixc.us/a250/ss-atlas/internal/stripe"
|
||||||
"git.nixc.us/a250/ss-atlas/internal/swarm"
|
"git.nixc.us/a250/ss-atlas/internal/swarm"
|
||||||
|
"git.nixc.us/a250/ss-atlas/internal/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
log.Printf("ss-atlas %s", version.String())
|
||||||
cfg := config.Load()
|
cfg := config.Load()
|
||||||
|
|
||||||
stripeClient := ssstripe.New(cfg)
|
stripeClient := ssstripe.New(cfg)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ type Config struct {
|
||||||
TraefikDomain string
|
TraefikDomain string
|
||||||
TraefikNetwork string
|
TraefikNetwork string
|
||||||
TemplatePath string
|
TemplatePath string
|
||||||
|
CustomerDomain string // e.g. app.a250.ca for clientname.app.a250.ca
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load() *Config {
|
func Load() *Config {
|
||||||
|
|
@ -35,6 +36,7 @@ func Load() *Config {
|
||||||
TraefikDomain: envOrDefault("TRAEFIK_DOMAIN", "bc.a250.ca"),
|
TraefikDomain: envOrDefault("TRAEFIK_DOMAIN", "bc.a250.ca"),
|
||||||
TraefikNetwork: envOrDefault("TRAEFIK_NETWORK", "authelia_dev"),
|
TraefikNetwork: envOrDefault("TRAEFIK_NETWORK", "authelia_dev"),
|
||||||
TemplatePath: envOrDefault("TEMPLATE_PATH", "/app/templates"),
|
TemplatePath: envOrDefault("TEMPLATE_PATH", "/app/templates"),
|
||||||
|
CustomerDomain: envOrDefault("CUSTOMER_DOMAIN", "app.a250.ca"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func TestLoadDefaults(t *testing.T) {
|
||||||
"PORT", "APP_URL", "AUTHELIA_URL", "STRIPE_SECRET_KEY",
|
"PORT", "APP_URL", "AUTHELIA_URL", "STRIPE_SECRET_KEY",
|
||||||
"STRIPE_WEBHOOK_SECRET", "STRIPE_PRICE_ID", "LLDAP_URL",
|
"STRIPE_WEBHOOK_SECRET", "STRIPE_PRICE_ID", "LLDAP_URL",
|
||||||
"LLDAP_ADMIN_DN", "LLDAP_ADMIN_PASSWORD", "LLDAP_BASE_DN",
|
"LLDAP_ADMIN_DN", "LLDAP_ADMIN_PASSWORD", "LLDAP_BASE_DN",
|
||||||
"DOCKER_HOST", "TRAEFIK_DOMAIN", "TRAEFIK_NETWORK", "TEMPLATE_PATH",
|
"DOCKER_HOST", "TRAEFIK_DOMAIN", "TRAEFIK_NETWORK", "TEMPLATE_PATH", "CUSTOMER_DOMAIN",
|
||||||
}
|
}
|
||||||
for _, k := range envKeys {
|
for _, k := range envKeys {
|
||||||
os.Unsetenv(k)
|
os.Unsetenv(k)
|
||||||
|
|
@ -54,9 +54,10 @@ func TestLoadDefaults(t *testing.T) {
|
||||||
{"LDAPAdminDN", cfg.LDAPAdminDN, "uid=admin,ou=people,dc=a250,dc=ca"},
|
{"LDAPAdminDN", cfg.LDAPAdminDN, "uid=admin,ou=people,dc=a250,dc=ca"},
|
||||||
{"LDAPBaseDN", cfg.LDAPBaseDN, "dc=a250,dc=ca"},
|
{"LDAPBaseDN", cfg.LDAPBaseDN, "dc=a250,dc=ca"},
|
||||||
{"DockerHost", cfg.DockerHost, "unix:///var/run/docker.sock"},
|
{"DockerHost", cfg.DockerHost, "unix:///var/run/docker.sock"},
|
||||||
{"TraefikDomain", cfg.TraefikDomain, "bc.a250.ca"},
|
{ "TraefikDomain", cfg.TraefikDomain, "bc.a250.ca"},
|
||||||
{"TraefikNetwork", cfg.TraefikNetwork, "authelia_dev"},
|
{"TraefikNetwork", cfg.TraefikNetwork, "authelia_dev"},
|
||||||
{"TemplatePath", cfg.TemplatePath, "/app/templates"},
|
{"TemplatePath", cfg.TemplatePath, "/app/templates"},
|
||||||
|
{"CustomerDomain", cfg.CustomerDomain, "app.a250.ca"},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
if tt.got != tt.want {
|
if tt.got != tt.want {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ func (a *App) handleActivatePost(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stackName := fmt.Sprintf("customer-%s", remoteUser)
|
stackName := fmt.Sprintf("customer-%s", remoteUser)
|
||||||
if err := a.swarm.DeployStack(stackName, remoteUser, a.cfg.TraefikDomain); err != nil {
|
if err := a.swarm.DeployStack(stackName, remoteUser, a.cfg.CustomerDomain); err != nil {
|
||||||
log.Printf("activate: stack deploy failed for %s: %v", remoteUser, err)
|
log.Printf("activate: stack deploy failed for %s: %v", remoteUser, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package handlers
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.nixc.us/a250/ss-atlas/internal/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -18,6 +20,8 @@ func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
"Groups": remoteGroups,
|
"Groups": remoteGroups,
|
||||||
"Domain": a.cfg.TraefikDomain,
|
"Domain": a.cfg.TraefikDomain,
|
||||||
"IsSubscribed": remoteGroups != "" && contains(remoteGroups, "customers"),
|
"IsSubscribed": remoteGroups != "" && contains(remoteGroups, "customers"),
|
||||||
|
"Commit": version.Commit,
|
||||||
|
"BuildTime": version.BuildTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.tmpl.ExecuteTemplate(w, "dashboard.html", data); err != nil {
|
if err := a.tmpl.ExecuteTemplate(w, "dashboard.html", data); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -9,6 +10,7 @@ import (
|
||||||
"git.nixc.us/a250/ss-atlas/internal/ldap"
|
"git.nixc.us/a250/ss-atlas/internal/ldap"
|
||||||
ssstripe "git.nixc.us/a250/ss-atlas/internal/stripe"
|
ssstripe "git.nixc.us/a250/ss-atlas/internal/stripe"
|
||||||
"git.nixc.us/a250/ss-atlas/internal/swarm"
|
"git.nixc.us/a250/ss-atlas/internal/swarm"
|
||||||
|
"git.nixc.us/a250/ss-atlas/internal/version"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
)
|
)
|
||||||
|
|
@ -50,6 +52,13 @@ func NewRouter(cfg *config.Config, sc *ssstripe.Client, lc *ldap.Client, sw *swa
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte("ok"))
|
w.Write([]byte("ok"))
|
||||||
})
|
})
|
||||||
|
r.Get("/version", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{
|
||||||
|
"commit": version.Commit,
|
||||||
|
"build_time": version.BuildTime,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,15 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.nixc.us/a250/ss-atlas/internal/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) handleLanding(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleLanding(w http.ResponseWriter, r *http.Request) {
|
||||||
data := map[string]any{
|
data := map[string]any{
|
||||||
"AppURL": a.cfg.AppURL,
|
"AppURL": a.cfg.AppURL,
|
||||||
|
"Commit": version.Commit,
|
||||||
|
"BuildTime": version.BuildTime,
|
||||||
}
|
}
|
||||||
if err := a.tmpl.ExecuteTemplate(w, "landing.html", data); err != nil {
|
if err := a.tmpl.ExecuteTemplate(w, "landing.html", data); err != nil {
|
||||||
log.Printf("template error: %v", err)
|
log.Printf("template error: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package version
|
||||||
|
|
||||||
|
var (
|
||||||
|
Commit = "unknown"
|
||||||
|
BuildTime = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
func String() string {
|
||||||
|
return Commit + " (built " + BuildTime + ")"
|
||||||
|
}
|
||||||
|
|
@ -101,6 +101,17 @@
|
||||||
.actions { display: flex; gap: 0.75rem; margin-top: 1rem; flex-wrap: wrap; }
|
.actions { display: flex; gap: 0.75rem; margin-top: 1rem; flex-wrap: wrap; }
|
||||||
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--muted); }
|
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--muted); }
|
||||||
.empty-state p { margin-bottom: 1.5rem; }
|
.empty-state p { margin-bottom: 1.5rem; }
|
||||||
|
.version-badge {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--muted);
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: all;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -157,5 +168,6 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="version-badge">{{.Commit}}</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,17 @@
|
||||||
button:hover { background: var(--accent-hover); }
|
button:hover { background: var(--accent-hover); }
|
||||||
.footer { margin-top: 2rem; color: var(--muted); font-size: 0.8rem; text-align: center; }
|
.footer { margin-top: 2rem; color: var(--muted); font-size: 0.8rem; text-align: center; }
|
||||||
.footer a { color: var(--accent); text-decoration: none; }
|
.footer a { color: var(--accent); text-decoration: none; }
|
||||||
|
.version-badge {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--muted);
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: all;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -102,5 +113,6 @@
|
||||||
Already subscribed? <a href="/dashboard">Go to Dashboard</a>
|
Already subscribed? <a href="/dashboard">Go to Dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="version-badge">{{.Commit}}</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Deploy ss-atlas + infra in local swarm mode for testing subscribe → deploy → teardown.
|
||||||
|
# Customer stacks get clientname.app.a250.ca. Run scripts/local-dns-setup.sh first for DNS.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo "ERROR: Working tree is dirty. Commit your changes before deploying." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUILD_COMMIT="$(git rev-parse --short HEAD)"
|
||||||
|
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
echo "=== Building commit $BUILD_COMMIT ==="
|
||||||
|
|
||||||
|
echo "=== Ensuring swarm mode ==="
|
||||||
|
docker info --format '{{.Swarm.LocalNodeState}}' | grep -q "active" || docker swarm init
|
||||||
|
|
||||||
|
echo "=== Creating overlay network for customer stacks ==="
|
||||||
|
docker network inspect authelia_dev >/dev/null 2>&1 || \
|
||||||
|
docker network create -d overlay --attachable authelia_dev
|
||||||
|
|
||||||
|
echo "=== Building ss-atlas ==="
|
||||||
|
docker compose -f docker-compose.dev.yml build \
|
||||||
|
--build-arg BUILD_COMMIT="$BUILD_COMMIT" \
|
||||||
|
--build-arg BUILD_TIME="$BUILD_TIME" \
|
||||||
|
ss-atlas
|
||||||
|
|
||||||
|
echo "=== Deploying with swarm overlay ==="
|
||||||
|
docker compose -f docker-compose.dev.yml -f docker-compose.swarm-dev.yml up -d
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Ready. Test flow: ==="
|
||||||
|
echo " 1. Add /etc/hosts or dnsmasq: *.app.a250.ca, app.bc.a250.ca, login.bc.a250.ca -> 127.0.0.1"
|
||||||
|
echo " 2. Visit http://app.bc.a250.ca, subscribe (Stripe test), activate"
|
||||||
|
echo " 3. After activate, customer stack deploys -> http://<username>.app.a250.ca"
|
||||||
|
echo " 4. Cancel subscription -> webhook tears down stack"
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Local DNS setup so *.app.a250.ca and *.bc.a250.ca resolve to 127.0.0.1
|
||||||
|
# For full wildcard support use dnsmasq. For quick test, use /etc/hosts (limited).
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Option 1: dnsmasq (recommended - true wildcard)"
|
||||||
|
echo " Add to /etc/dnsmasq.conf or /usr/local/etc/dnsmasq.conf:"
|
||||||
|
echo " address=/.app.a250.ca/127.0.0.1"
|
||||||
|
echo " address=/.bc.a250.ca/127.0.0.1"
|
||||||
|
echo " Then: brew services restart dnsmasq"
|
||||||
|
echo " And point your Mac to use 127.0.0.1 for DNS, or add to /etc/resolvers/app.a250.ca"
|
||||||
|
echo ""
|
||||||
|
echo "Option 2: /etc/hosts (manual per-subdomain)"
|
||||||
|
echo " Add lines for each host you need:"
|
||||||
|
echo " 127.0.0.1 app.bc.a250.ca login.bc.a250.ca"
|
||||||
|
echo " 127.0.0.1 testuser.app.a250.ca"
|
||||||
|
echo " /etc/hosts does NOT support wildcards."
|
||||||
|
echo ""
|
||||||
|
echo "Option 3: resolvers file for *.app.a250.ca only"
|
||||||
|
echo " mkdir -p /etc/resolver"
|
||||||
|
echo " echo 'nameserver 127.0.0.1' | sudo tee /etc/resolver/app.a250.ca"
|
||||||
|
echo " (requires dnsmasq listening on 127.0.0.1 with address=/.app.a250.ca/127.0.0.1)"
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Static workflow: clean (stack rm + prune) → rebuild (on deploy context) → redeploy. No push; uses local images.
|
||||||
|
# Set DOCKER_DEPLOY_CONTEXT for stack target (default: default).
|
||||||
|
# Requires: swarm mode, secrets/networks on deploy node.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
STACK_NAME="${STACK_NAME:-authelia}"
|
||||||
|
DEPLOY_CTX="${DOCKER_DEPLOY_CONTEXT:-orbstack}"
|
||||||
|
STACK_RM_WAIT=15
|
||||||
|
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo "ERROR: Working tree is dirty. Commit your changes before deploying." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUILD_COMMIT="$(git rev-parse --short HEAD)"
|
||||||
|
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
echo "=== Building commit $BUILD_COMMIT ==="
|
||||||
|
|
||||||
|
clean_on_deploy_context() {
|
||||||
|
docker context use "$DEPLOY_CTX"
|
||||||
|
docker stack rm "$STACK_NAME" 2>/dev/null || true
|
||||||
|
sleep "$STACK_RM_WAIT"
|
||||||
|
docker image prune -a -f 2>/dev/null || true
|
||||||
|
for vol in authelia_authelia_config authelia_authelia_assets authelia_authelia_redis_data authelia_authelia_mariadb_data authelia_lldap_data; do
|
||||||
|
docker volume rm "$vol" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
for name in AUTHENTICATION_BACKEND_LDAP_PASSWORD IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET NOTIFIER_SMTP_PASSWORD SESSION_SECRET STORAGE_ENCRYPTION_KEY; do
|
||||||
|
docker secret rm "$name" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
build_on_deploy_context() {
|
||||||
|
docker context use "$DEPLOY_CTX"
|
||||||
|
docker compose -f docker-compose.production.yml build --no-cache \
|
||||||
|
--build-arg BUILD_COMMIT="$BUILD_COMMIT" \
|
||||||
|
--build-arg BUILD_TIME="$BUILD_TIME"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_external_networks() {
|
||||||
|
for net in traefik ad; do
|
||||||
|
docker network inspect "$net" --format '{{.Name}}' 2>/dev/null | grep -q . || docker network create "$net" --driver overlay --attachable
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_secrets() {
|
||||||
|
LDAP_PW="/ETAToLiZPWo6QK171abAUqsa3WDpd9IgneZnTA4zU0="
|
||||||
|
echo "$LDAP_PW" | docker secret create AUTHENTICATION_BACKEND_LDAP_PASSWORD - 2>/dev/null || true
|
||||||
|
openssl rand -base64 32 | docker secret create IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET - 2>/dev/null || true
|
||||||
|
echo "not-configured" | docker secret create NOTIFIER_SMTP_PASSWORD - 2>/dev/null || true
|
||||||
|
openssl rand -base64 32 | docker secret create SESSION_SECRET - 2>/dev/null || true
|
||||||
|
openssl rand -base64 32 | docker secret create STORAGE_ENCRYPTION_KEY - 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_on_deploy_context() {
|
||||||
|
docker context use "$DEPLOY_CTX"
|
||||||
|
docker info --format '{{.Swarm.LocalNodeState}}' | grep -q active || docker swarm init
|
||||||
|
ensure_external_networks
|
||||||
|
ensure_secrets
|
||||||
|
docker stack deploy --with-registry-auth -c ./stack.production.yml "$STACK_NAME"
|
||||||
|
docker stack ps "$STACK_NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Clean (stack rm + prune) on context: $DEPLOY_CTX ==="
|
||||||
|
clean_on_deploy_context
|
||||||
|
|
||||||
|
echo "=== Rebuild (on $DEPLOY_CTX, local images) ==="
|
||||||
|
build_on_deploy_context
|
||||||
|
|
||||||
|
echo "=== Redeploy on context: $DEPLOY_CTX ==="
|
||||||
|
deploy_on_deploy_context
|
||||||
|
|
||||||
|
echo "=== Done ==="
|
||||||
|
|
@ -3,7 +3,7 @@ x-authelia-env: &authelia-env
|
||||||
X_AUTHELIA_SITE_NAME: ATLAS
|
X_AUTHELIA_SITE_NAME: ATLAS
|
||||||
X_AUTHELIA_CONFIG_FILTERS: template
|
X_AUTHELIA_CONFIG_FILTERS: template
|
||||||
X_AUTHELIA_LDAP_DOMAIN: dc=a250,dc=ca
|
X_AUTHELIA_LDAP_DOMAIN: dc=a250,dc=ca
|
||||||
TRAEFIK_DOMAIN: a250.ca
|
TRAEFIK_DOMAIN: bc.a250.ca
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
AUTHENTICATION_BACKEND_LDAP_PASSWORD:
|
AUTHENTICATION_BACKEND_LDAP_PASSWORD:
|
||||||
|
|
@ -51,6 +51,8 @@ volumes:
|
||||||
driver: local
|
driver: local
|
||||||
authelia_mariadb_data:
|
authelia_mariadb_data:
|
||||||
driver: local
|
driver: local
|
||||||
|
lldap_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
services:
|
services:
|
||||||
authelia:
|
authelia:
|
||||||
|
|
@ -60,6 +62,7 @@ services:
|
||||||
- --config=/config/configuration.server.yml
|
- --config=/config/configuration.server.yml
|
||||||
- --config=/config/configuration.ldap.yml
|
- --config=/config/configuration.ldap.yml
|
||||||
- --config=/config/configuration.acl.yml
|
- --config=/config/configuration.acl.yml
|
||||||
|
- --config=/config/configuration.notifier.yml
|
||||||
secrets:
|
secrets:
|
||||||
- AUTHENTICATION_BACKEND_LDAP_PASSWORD
|
- AUTHENTICATION_BACKEND_LDAP_PASSWORD
|
||||||
- IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET
|
- IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET
|
||||||
|
|
@ -91,24 +94,19 @@ services:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
replicas: 1
|
replicas: 1
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
labels:
|
||||||
us.a250.autodeploy: "true"
|
us.a250.autodeploy: "true"
|
||||||
homepage.group: Infrastructure
|
homepage.group: Infrastructure
|
||||||
homepage.name: Authelia
|
homepage.name: Authelia
|
||||||
homepage.href: https://login.a250.ca
|
homepage.href: https://login.bc.a250.ca
|
||||||
homepage.description: ATLAS
|
homepage.description: ATLAS
|
||||||
traefik.enable: "true"
|
traefik.enable: "true"
|
||||||
traefik.docker.network: traefik
|
traefik.docker.network: traefik
|
||||||
traefik.http.routers.authelia_authelia.rule: Host(`login.a250.ca`)
|
traefik.http.routers.authelia_authelia.rule: Host(`login.bc.a250.ca`)
|
||||||
traefik.http.routers.authelia_authelia.entrypoints: websecure
|
traefik.http.routers.authelia_authelia.entrypoints: web
|
||||||
traefik.http.routers.authelia_authelia.tls: "true"
|
|
||||||
traefik.http.routers.authelia_authelia.tls.certresolver: letsencryptresolver
|
|
||||||
traefik.http.routers.authelia_authelia.service: authelia_authelia
|
traefik.http.routers.authelia_authelia.service: authelia_authelia
|
||||||
traefik.http.services.authelia_authelia.loadbalancer.server.port: 9091
|
traefik.http.services.authelia_authelia.loadbalancer.server.port: 9091
|
||||||
traefik.http.middlewares.authelia_authelia.forwardauth.address: http://authelia_authelia:9091/api/verify?rd=https://login.a250.ca/
|
traefik.http.middlewares.authelia_authelia.forwardauth.address: http://authelia_authelia:9091/api/verify?rd=https://login.bc.a250.ca/
|
||||||
traefik.http.middlewares.authelia_authelia.forwardauth.trustForwardHeader: "true"
|
traefik.http.middlewares.authelia_authelia.forwardauth.trustForwardHeader: "true"
|
||||||
traefik.http.middlewares.authelia_authelia.forwardauth.authResponseHeaders: Remote-User,Remote-Groups,Remote-Name,Remote-Email
|
traefik.http.middlewares.authelia_authelia.forwardauth.authResponseHeaders: Remote-User,Remote-Groups,Remote-Name,Remote-Email
|
||||||
traefik.http.middlewares.authelia-basic.forwardauth.address: http://authelia_authelia:9091/api/verify?auth=basic
|
traefik.http.middlewares.authelia-basic.forwardauth.address: http://authelia_authelia:9091/api/verify?auth=basic
|
||||||
|
|
@ -141,9 +139,6 @@ services:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
replicas: 1
|
replicas: 1
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
labels:
|
||||||
us.a250.autodeploy: "true"
|
us.a250.autodeploy: "true"
|
||||||
traefik.enable: "false"
|
traefik.enable: "false"
|
||||||
|
|
@ -159,6 +154,26 @@ services:
|
||||||
max-size: 10m
|
max-size: 10m
|
||||||
max-file: "3"
|
max-file: "3"
|
||||||
|
|
||||||
|
lldap:
|
||||||
|
image: nitnelave/lldap:latest
|
||||||
|
volumes:
|
||||||
|
- lldap_data:/data
|
||||||
|
environment:
|
||||||
|
LLDAP_JWT_SECRET: I2sNvGvhzZlTJWPfNL9MBPFGhyG/gWU5wHz6wFsIC3I=
|
||||||
|
LLDAP_LDAP_USER_PASS: /ETAToLiZPWo6QK171abAUqsa3WDpd9IgneZnTA4zU0=
|
||||||
|
LLDAP_LDAP_BASE_DN: dc=a250,dc=ca
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
replicas: 1
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: 10m
|
||||||
|
max-file: "3"
|
||||||
|
|
||||||
mariadb:
|
mariadb:
|
||||||
image: git.nixc.us/a250/authelia:production-mariadb
|
image: git.nixc.us/a250/authelia:production-mariadb
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -178,9 +193,6 @@ services:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
replicas: 1
|
replicas: 1
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
labels:
|
||||||
us.a250.autodeploy: "true"
|
us.a250.autodeploy: "true"
|
||||||
traefik.enable: "false"
|
traefik.enable: "false"
|
||||||
|
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
x-authelia-env: &authelia-env
|
|
||||||
X_AUTHELIA_EMAIL: authelia@a250.ca
|
|
||||||
X_AUTHELIA_SITE_NAME: ATLAS
|
|
||||||
X_AUTHELIA_CONFIG_FILTERS: template
|
|
||||||
X_AUTHELIA_LDAP_DOMAIN: dc=a250,dc=ca
|
|
||||||
TRAEFIK_DOMAIN: a250.ca
|
|
||||||
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
driver: overlay
|
|
||||||
traefik:
|
|
||||||
external: true
|
|
||||||
ad:
|
|
||||||
external: true
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
authelia_staging_config:
|
|
||||||
driver: local
|
|
||||||
authelia_staging_redis_data:
|
|
||||||
driver: local
|
|
||||||
authelia_staging_mariadb_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
services:
|
|
||||||
authelia:
|
|
||||||
image: git.nixc.us/a250/authelia:staging-authelia
|
|
||||||
command:
|
|
||||||
- authelia
|
|
||||||
- --config=/config/configuration.server.yml
|
|
||||||
- --config=/config/configuration.ldap.yml
|
|
||||||
- --config=/config/configuration.acl.yml
|
|
||||||
- --config=/config/configuration.identity.providers.yml
|
|
||||||
- --config=/config/configuration.oidc.clients.yml
|
|
||||||
environment: *authelia-env
|
|
||||||
volumes:
|
|
||||||
- authelia_staging_config:/config:rw
|
|
||||||
networks:
|
|
||||||
- traefik
|
|
||||||
- default
|
|
||||||
- ad
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
order: start-first
|
|
||||||
failure_action: rollback
|
|
||||||
parallelism: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
|
||||||
us.a250.autodeploy: "true"
|
|
||||||
traefik.enable: "true"
|
|
||||||
traefik.docker.network: traefik
|
|
||||||
traefik.http.routers.staging-authelia_authelia.rule: Host(`staging.login.a250.ca`)
|
|
||||||
traefik.http.routers.staging-authelia_authelia.entrypoints: websecure
|
|
||||||
traefik.http.routers.staging-authelia_authelia.tls: "true"
|
|
||||||
traefik.http.routers.staging-authelia_authelia.tls.certresolver: letsencryptresolver
|
|
||||||
traefik.http.routers.staging-authelia_authelia.service: authelia_authelia
|
|
||||||
traefik.http.services.staging-authelia_authelia.loadbalancer.server.port: 9091
|
|
||||||
traefik.http.middlewares.staging-authelia_authelia.forwardauth.address: http://authelia_authelia:9091/api/verify?rd=https://login.a250.ca/
|
|
||||||
traefik.http.middlewares.staging-authelia_authelia.forwardauth.trustForwardHeader: "true"
|
|
||||||
traefik.http.middlewares.staging-authelia_authelia.forwardauth.authResponseHeaders: Remote-User,Remote-Groups,Remote-Name,Remote-Email
|
|
||||||
traefik.http.middlewares.staging-authelia-basic.forwardauth.address: http://authelia_authelia:9091/api/verify?auth=basic
|
|
||||||
traefik.http.middlewares.staging-authelia-basic.forwardauth.trustForwardHeader: "true"
|
|
||||||
traefik.http.middlewares.staging-authelia-basic.forwardauth.authResponseHeaders: Remote-User,Remote-Groups,Remote-Name,Remote-Email
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: 10m
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: git.nixc.us/a250/authelia:staging-redis
|
|
||||||
command: redis-server --appendonly yes
|
|
||||||
volumes:
|
|
||||||
- authelia_staging_redis_data:/data:rw
|
|
||||||
networks:
|
|
||||||
- default
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
order: start-first
|
|
||||||
failure_action: rollback
|
|
||||||
parallelism: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
|
||||||
us.a250.autodeploy: "true"
|
|
||||||
traefik.enable: "false"
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: 10m
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
mariadb:
|
|
||||||
image: git.nixc.us/a250/authelia:staging-mariadb
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: authelia
|
|
||||||
MYSQL_DATABASE: authelia
|
|
||||||
MYSQL_USER: authelia
|
|
||||||
MYSQL_PASSWORD: authelia
|
|
||||||
volumes:
|
|
||||||
- authelia_staging_mariadb_data:/var/lib/mysql:rw
|
|
||||||
networks:
|
|
||||||
- default
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
order: start-first
|
|
||||||
failure_action: rollback
|
|
||||||
parallelism: 1
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
replicas: 1
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == ingress.a250.ca
|
|
||||||
labels:
|
|
||||||
us.a250.autodeploy: "true"
|
|
||||||
traefik.enable: "false"
|
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: 10m
|
|
||||||
max-file: "3"
|
|
||||||
Loading…
Reference in New Issue