webui (1)
This commit is contained in:
+6
-8
@@ -15,14 +15,12 @@ WEB_ENABLED=true
|
|||||||
WEB_HOSTNAME=files.example.com
|
WEB_HOSTNAME=files.example.com
|
||||||
WEB_HTTPS_PORT=443
|
WEB_HTTPS_PORT=443
|
||||||
WEB_JWT_SECRET=ReplaceWithAtLeast32RandomBytes
|
WEB_JWT_SECRET=ReplaceWithAtLeast32RandomBytes
|
||||||
WEB_TLS_MODE=step
|
WEB_TLS_MODE=acme
|
||||||
STEP_CA_URL=https://ca.example.com:9000
|
ACME_CA_SERVER=https://ca.internal/acme/acme/directory
|
||||||
STEP_CA_FINGERPRINT=ReplaceWithStepRootFingerprint
|
ACME_CA_CERTIFICATES=/state/tls/acme-ca-certificates.pem
|
||||||
STEP_CA_PROVISIONER=fileserver
|
ACME_HTTP_LISTEN=:80
|
||||||
STEP_CA_PROVISIONER_PASSWORD=ReplaceWithProvisionerPassword
|
ACME_HTTP_PORT=80
|
||||||
# STEP_CA_TOKEN=single-use-bootstrap-token
|
# ACME_RENEW_CHECK_SECONDS=900
|
||||||
# STEP_CA_PROVISIONER_PASSWORD_FILE=/run/secrets/step-ca-provisioner-password
|
|
||||||
# STEP_CA_REBOOTSTRAP=false
|
|
||||||
# WEB_TLS_CERT_FILE=/state/tls/web.crt
|
# WEB_TLS_CERT_FILE=/state/tls/web.crt
|
||||||
# WEB_TLS_KEY_FILE=/state/tls/web.key
|
# WEB_TLS_KEY_FILE=/state/tls/web.key
|
||||||
# WEB_JWT_TTL_SECONDS=28800
|
# WEB_JWT_TTL_SECONDS=28800
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ Run a complete disposable environment with Docker or Podman:
|
|||||||
The launcher builds the current application and starts an isolated, run-scoped network containing:
|
The launcher builds the current application and starts an isolated, run-scoped network containing:
|
||||||
|
|
||||||
- a real Samba AD DC for `DEV.TEST`, seeded with users, nested groups, and three `FS_*` groups;
|
- a real Samba AD DC for `DEV.TEST`, seeded with users, nested groups, and three `FS_*` groups;
|
||||||
- a real Smallstep CA that issues the web UI certificate for `localhost`;
|
- a real Smallstep CA whose ACME provisioner issues the web UI certificate for `files.localhost`;
|
||||||
- an authenticated rsync daemon used by the normal backup implementation;
|
- an authenticated rsync daemon used by the normal backup implementation;
|
||||||
- the actual file-server image, joined to the dummy domain;
|
- the actual file-server image, joined to the dummy domain;
|
||||||
- a continuous SMB client that reads, writes, and lists files as several domain users.
|
- a continuous SMB client that reads, writes, and lists files as several domain users.
|
||||||
@@ -126,7 +126,7 @@ The launcher builds the current application and starts an isolated, run-scoped n
|
|||||||
The preview starts with group, Private, FSLogix, and historical audit data. The client keeps current-day audit activity moving, while a real backup runs immediately and repeats in the background. Open the URL and use the credentials printed by the launcher. Defaults are:
|
The preview starts with group, Private, FSLogix, and historical audit data. The client keeps current-day audit activity moving, while a real backup runs immediately and repeats in the background. Open the URL and use the credentials printed by the launcher. Defaults are:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
URL: https://localhost:8443
|
URL: https://files.localhost:8443
|
||||||
Username: DEV\previewadmin
|
Username: DEV\previewadmin
|
||||||
Password: PreviewAdmin123!
|
Password: PreviewAdmin123!
|
||||||
```
|
```
|
||||||
@@ -140,8 +140,9 @@ Useful overrides:
|
|||||||
| Variable | Default | Purpose |
|
| Variable | Default | Purpose |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `DEV_HTTPS_PORT` | `8443` | HTTPS port bound to host loopback |
|
| `DEV_HTTPS_PORT` | `8443` | HTTPS port bound to host loopback |
|
||||||
|
| `DEV_WEB_HOSTNAME` | `files.localhost` | HTTPS name validated by the disposable ACME CA |
|
||||||
| `DEV_SKIP_BUILD` | `0` | Set to `1` to reuse already-built local images |
|
| `DEV_SKIP_BUILD` | `0` | Set to `1` to reuse already-built local images |
|
||||||
| `DEV_STEP_CA_IMAGE` | `docker.io/smallstep/step-ca:latest` | CA image; pin a tag or digest for reproducible CI |
|
| `DEV_CA_IMAGE` | `docker.io/smallstep/step-ca:latest` | CA image; pin a tag or digest for reproducible CI |
|
||||||
| `DEV_SERVER_IMAGE` | `ad-ds-simple-file-server-dev:latest` | Local file-server image name |
|
| `DEV_SERVER_IMAGE` | `ad-ds-simple-file-server-dev:latest` | Local file-server image name |
|
||||||
| `DEV_AD_IMAGE` | `ad-ds-simple-file-server-ad-dev:latest` | Local AD/client image name |
|
| `DEV_AD_IMAGE` | `ad-ds-simple-file-server-ad-dev:latest` | Local AD/client image name |
|
||||||
| `DEV_BACKUP_IMAGE` | `ad-ds-simple-file-server-backup-dev:latest` | Local rsync target image name |
|
| `DEV_BACKUP_IMAGE` | `ad-ds-simple-file-server-backup-dev:latest` | Local rsync target image name |
|
||||||
@@ -209,12 +210,11 @@ The runner returns non-zero on the first failed assertion, prints bounded logs f
|
|||||||
- optional `BACKUP_PROGRESS_INTERVAL_SECONDS` (default `10`)
|
- optional `BACKUP_PROGRESS_INTERVAL_SECONDS` (default `10`)
|
||||||
- `WEB_HOSTNAME` (the DNS name in the HTTPS certificate)
|
- `WEB_HOSTNAME` (the DNS name in the HTTPS certificate)
|
||||||
- optional `WEB_HTTPS_PORT` (host port, default `443`)
|
- optional `WEB_HTTPS_PORT` (host port, default `443`)
|
||||||
- `STEP_CA_URL`
|
- `ACME_CA_SERVER` (ACME directory URL)
|
||||||
- `STEP_CA_FINGERPRINT`
|
- ACME CA root bundle (a host PEM file imported into the persistent state volume)
|
||||||
- `STEP_CA_PROVISIONER`
|
- optional `ACME_HTTP_PORT` (HTTP-01 host port, default `80`)
|
||||||
- `STEP_CA_PROVISIONER_PASSWORD`
|
|
||||||
|
|
||||||
Setup generates a random `WEB_JWT_SECRET`. A one-time `STEP_CA_TOKEN` or a provisioner password file can be configured manually instead of keeping a provisioner password in `.env`.
|
Setup generates a random `WEB_JWT_SECRET`, stores only the generic ACME settings, and imports the public CA root as `/state/tls/acme-ca-certificates.pem`.
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
- `SAMBA_HOSTNAME` (defaults to `adsambafsrv`)
|
- `SAMBA_HOSTNAME` (defaults to `adsambafsrv`)
|
||||||
@@ -301,25 +301,50 @@ The web API has no mutation endpoint other than session login/logout. Files, gro
|
|||||||
- Login attempts are rate-limited per client address.
|
- Login attempts are rate-limited per client address.
|
||||||
- Responses set HSTS, a restrictive Content Security Policy, clickjacking protection, MIME sniffing protection, and no-store caching.
|
- Responses set HSTS, a restrictive Content Security Policy, clickjacking protection, MIME sniffing protection, and no-store caching.
|
||||||
|
|
||||||
### TLS with a local Smallstep CA
|
### TLS with an internal ACME CA
|
||||||
|
|
||||||
Default enrollment uses `WEB_TLS_MODE=step`:
|
The default uses standard ACME HTTP-01 enrollment. The names deliberately describe the protocol and inputs rather than a particular CA product:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
WEB_ENABLED=true
|
WEB_ENABLED=true
|
||||||
WEB_HOSTNAME=files.example.com
|
WEB_HOSTNAME=files.example.com
|
||||||
WEB_HTTPS_PORT=443
|
WEB_HTTPS_PORT=443
|
||||||
WEB_JWT_SECRET=<at-least-32-random-bytes>
|
WEB_JWT_SECRET=<at-least-32-random-bytes>
|
||||||
WEB_TLS_MODE=step
|
WEB_TLS_MODE=acme
|
||||||
STEP_CA_URL=https://ca.example.com:9000
|
ACME_CA_SERVER=https://ca.internal/acme/acme/directory
|
||||||
STEP_CA_FINGERPRINT=<root-certificate-fingerprint>
|
ACME_CA_CERTIFICATES=/state/tls/acme-ca-certificates.pem
|
||||||
STEP_CA_PROVISIONER=fileserver
|
ACME_HTTP_LISTEN=:80
|
||||||
STEP_CA_PROVISIONER_PASSWORD=<provisioner-password>
|
ACME_HTTP_PORT=80
|
||||||
```
|
```
|
||||||
|
|
||||||
At first startup the container bootstraps the CA root, requests a certificate for `WEB_HOSTNAME`, and stores its certificate, key, and Step client state on the persistent `state_data` volume. The `step ca renew --daemon` process renews the certificate; the HTTPS listener notices the certificate file change and reloads it.
|
`ACME_CA_CERTIFICATES` is a path inside the file-server container. The setup script imports the selected host PEM bundle at the path above; manual deployments must copy or mount the bundle there. The CA must be able to resolve `WEB_HOSTNAME` and reach `http://WEB_HOSTNAME/.well-known/acme-challenge/...` on port 80. `ACME_HTTP_LISTEN` controls the in-container standalone challenge listener and `ACME_HTTP_PORT` controls the Compose host-port mapping.
|
||||||
|
|
||||||
For secret-file based enrollment, set `STEP_CA_PROVISIONER_PASSWORD_FILE` to a mounted file. A single-use `STEP_CA_TOKEN` is also supported. To use externally managed files instead:
|
The equivalent Traefik settings translate as follows:
|
||||||
|
|
||||||
|
| Traefik setting | File-server setting |
|
||||||
|
| --- | --- |
|
||||||
|
| `acme.httpchallenge=true` | `WEB_TLS_MODE=acme` |
|
||||||
|
| `acme.httpchallenge.entrypoint=http` | `ACME_HTTP_LISTEN=:80` and `ACME_HTTP_PORT=80` |
|
||||||
|
| `acme.caserver=https://ca.internal/acme/acme/directory` | `ACME_CA_SERVER=https://ca.internal/acme/acme/directory` |
|
||||||
|
| `acme.cacertificates=/traefik/stepca/roots.pem` | `ACME_CA_CERTIFICATES=<the mounted PEM path inside this container>` |
|
||||||
|
|
||||||
|
The client uses [`step ca certificate --acme --root --standalone`](https://smallstep.com/docs/step-cli/reference/ca/certificate/) and periodically checks whether the certificate needs renewal. Renewal is a fresh ACME order, so this mode is not coupled to a proprietary renewal endpoint. The HTTPS listener reloads the replaced certificate files.
|
||||||
|
|
||||||
|
A generic direct-CA/JWK or token enrollment mode remains available when ACME HTTP-01 cannot be routed:
|
||||||
|
|
||||||
|
```env
|
||||||
|
WEB_TLS_MODE=ca
|
||||||
|
TLS_CA_URL=https://ca.internal:9000
|
||||||
|
TLS_CA_FINGERPRINT=<root-certificate-fingerprint>
|
||||||
|
TLS_CA_PROVISIONER=fileserver
|
||||||
|
TLS_CA_PROVISIONER_PASSWORD=<provisioner-password>
|
||||||
|
# TLS_CA_PROVISIONER_PASSWORD_FILE=/run/secrets/ca-provisioner-password
|
||||||
|
# TLS_CA_TOKEN=<single-use-bootstrap-token>
|
||||||
|
# TLS_CA_REBOOTSTRAP=false
|
||||||
|
# TLS_CA_STATE_DIR=/state/tls-client
|
||||||
|
```
|
||||||
|
|
||||||
|
Externally managed certificate files can be used instead:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
WEB_TLS_MODE=files
|
WEB_TLS_MODE=files
|
||||||
@@ -327,12 +352,12 @@ WEB_TLS_CERT_FILE=/state/tls/web.crt
|
|||||||
WEB_TLS_KEY_FILE=/state/tls/web.key
|
WEB_TLS_KEY_FILE=/state/tls/web.key
|
||||||
```
|
```
|
||||||
|
|
||||||
Smallstep trust configuration is reused from the state volume on normal restarts, so a temporary CA outage does not stop Samba or an already-certificate-equipped web service. Set `STEP_CA_REBOOTSTRAP=true` only when intentionally replacing the configured CA trust.
|
|
||||||
|
|
||||||
Useful optional settings:
|
Useful optional settings:
|
||||||
|
|
||||||
| Variable | Default | Purpose |
|
| Variable | Default | Purpose |
|
||||||
| --- | ---: | --- |
|
| --- | ---: | --- |
|
||||||
|
| `WEB_TLS_AUTORENEW` | `true` | Renew managed certificates automatically |
|
||||||
|
| `ACME_RENEW_CHECK_SECONDS` | `900` | Interval for ACME renewal checks; minimum 60 seconds |
|
||||||
| `WEB_JWT_TTL_SECONDS` | `28800` | Session lifetime, 5 minutes to 7 days |
|
| `WEB_JWT_TTL_SECONDS` | `28800` | Session lifetime, 5 minutes to 7 days |
|
||||||
| `WEB_LOGIN_ATTEMPTS_PER_5_MIN` | `10` | Per-address login attempt limit |
|
| `WEB_LOGIN_ATTEMPTS_PER_5_MIN` | `10` | Per-address login attempt limit |
|
||||||
| `WEB_USAGE_SCAN_INTERVAL_SECONDS` | `900` | Recursive storage scan interval |
|
| `WEB_USAGE_SCAN_INTERVAL_SECONDS` | `900` | Recursive storage scan interval |
|
||||||
|
|||||||
+101
-29
@@ -303,7 +303,8 @@ web_should_start() {
|
|||||||
env_is_true "$WEB_ENABLED"
|
env_is_true "$WEB_ENABLED"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [[ -n "${STEP_CA_URL:-}" ]] || \
|
if [[ -n "${ACME_CA_SERVER:-}" ]] || \
|
||||||
|
[[ -n "${TLS_CA_URL:-}" ]] || \
|
||||||
[[ -s "${WEB_TLS_CERT_FILE:-/state/tls/web.crt}" ]]; then
|
[[ -s "${WEB_TLS_CERT_FILE:-/state/tls/web.crt}" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -328,17 +329,57 @@ ensure_web_jwt_secret() {
|
|||||||
log 'WEB_JWT_SECRET was not provided; using a persistent generated secret.'
|
log 'WEB_JWT_SECRET was not provided; using a persistent generated secret.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selected_tls_mode() {
|
||||||
|
case "${WEB_TLS_MODE:-}" in
|
||||||
|
'')
|
||||||
|
if [[ -n "${ACME_CA_SERVER:-}" ]]; then
|
||||||
|
printf 'acme'
|
||||||
|
else
|
||||||
|
printf 'ca'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
acme|ca|files) printf '%s' "$WEB_TLS_MODE" ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
request_acme_certificate() {
|
||||||
|
local cert_tmp="${WEB_TLS_CERT_FILE}.acme.tmp"
|
||||||
|
local key_tmp="${WEB_TLS_KEY_FILE}.acme.tmp"
|
||||||
|
|
||||||
|
rm -f "$cert_tmp" "$key_tmp"
|
||||||
|
log "Requesting ACME HTTPS certificate for ${WEB_HOSTNAME}"
|
||||||
|
if ! step ca certificate "$WEB_HOSTNAME" "$cert_tmp" "$key_tmp" \
|
||||||
|
--acme "$ACME_CA_SERVER" \
|
||||||
|
--root "$ACME_CA_CERTIFICATES" \
|
||||||
|
--standalone \
|
||||||
|
--http-listen "${ACME_HTTP_LISTEN:-:80}" \
|
||||||
|
--force; then
|
||||||
|
rm -f "$cert_tmp" "$key_tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0600 "$key_tmp"
|
||||||
|
chmod 0644 "$cert_tmp"
|
||||||
|
mv -f "$key_tmp" "$WEB_TLS_KEY_FILE"
|
||||||
|
mv -f "$cert_tmp" "$WEB_TLS_CERT_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
configure_web_tls() {
|
configure_web_tls() {
|
||||||
local tls_mode="${WEB_TLS_MODE:-step}"
|
local tls_mode=""
|
||||||
local tls_dir=""
|
|
||||||
local provisioner_password_file=""
|
local provisioner_password_file=""
|
||||||
|
|
||||||
|
if ! tls_mode="$(selected_tls_mode)"; then
|
||||||
|
printf '[init] ERROR: WEB_TLS_MODE must be acme, ca, or files\n' >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
export ACTIVE_WEB_TLS_MODE="$tls_mode"
|
||||||
export WEB_HOSTNAME="${WEB_HOSTNAME:-${AD_DNS_NAME}}"
|
export WEB_HOSTNAME="${WEB_HOSTNAME:-${AD_DNS_NAME}}"
|
||||||
export WEB_BIND_PORT="${WEB_BIND_PORT:-8443}"
|
export WEB_BIND_PORT="${WEB_BIND_PORT:-8443}"
|
||||||
export WEB_TLS_CERT_FILE="${WEB_TLS_CERT_FILE:-/state/tls/web.crt}"
|
export WEB_TLS_CERT_FILE="${WEB_TLS_CERT_FILE:-/state/tls/web.crt}"
|
||||||
export WEB_TLS_KEY_FILE="${WEB_TLS_KEY_FILE:-/state/tls/web.key}"
|
export WEB_TLS_KEY_FILE="${WEB_TLS_KEY_FILE:-/state/tls/web.key}"
|
||||||
tls_dir="$(dirname "$WEB_TLS_CERT_FILE")"
|
export STEPPATH="${TLS_CA_STATE_DIR:-/state/tls-client}"
|
||||||
mkdir -p "$tls_dir" "$(dirname "$WEB_TLS_KEY_FILE")"
|
mkdir -p "$(dirname "$WEB_TLS_CERT_FILE")" "$(dirname "$WEB_TLS_KEY_FILE")" "$STEPPATH"
|
||||||
|
|
||||||
if [[ "$tls_mode" == "files" ]]; then
|
if [[ "$tls_mode" == "files" ]]; then
|
||||||
if [[ ! -s "$WEB_TLS_CERT_FILE" || ! -s "$WEB_TLS_KEY_FILE" ]]; then
|
if [[ ! -s "$WEB_TLS_CERT_FILE" || ! -s "$WEB_TLS_KEY_FILE" ]]; then
|
||||||
@@ -347,41 +388,49 @@ configure_web_tls() {
|
|||||||
fi
|
fi
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [[ "$tls_mode" != "step" ]]; then
|
|
||||||
printf '[init] ERROR: WEB_TLS_MODE must be step or files\n' >&2
|
if [[ "$tls_mode" == "acme" ]]; then
|
||||||
return 1
|
require_env ACME_CA_SERVER
|
||||||
|
require_env ACME_CA_CERTIFICATES
|
||||||
|
if [[ ! -s "$ACME_CA_CERTIFICATES" ]]; then
|
||||||
|
printf '[init] ERROR: ACME_CA_CERTIFICATES is not a readable PEM bundle: %s\n' "$ACME_CA_CERTIFICATES" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ! -s "$WEB_TLS_CERT_FILE" || ! -s "$WEB_TLS_KEY_FILE" ]]; then
|
||||||
|
request_acme_certificate
|
||||||
|
fi
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export STEPPATH="${STEP_PATH:-/state/step}"
|
|
||||||
if [[ ! -s "$STEPPATH/config/defaults.json" ]] || \
|
if [[ ! -s "$STEPPATH/config/defaults.json" ]] || \
|
||||||
env_is_true "${STEP_CA_REBOOTSTRAP:-false}"; then
|
env_is_true "${TLS_CA_REBOOTSTRAP:-false}"; then
|
||||||
require_env STEP_CA_URL
|
require_env TLS_CA_URL
|
||||||
require_env STEP_CA_FINGERPRINT
|
require_env TLS_CA_FINGERPRINT
|
||||||
log "Bootstrapping Smallstep trust for ${STEP_CA_URL}"
|
log "Bootstrapping CA trust for ${TLS_CA_URL}"
|
||||||
step ca bootstrap --force --ca-url "$STEP_CA_URL" --fingerprint "$STEP_CA_FINGERPRINT"
|
step ca bootstrap --force --ca-url "$TLS_CA_URL" --fingerprint "$TLS_CA_FINGERPRINT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -s "$WEB_TLS_CERT_FILE" || ! -s "$WEB_TLS_KEY_FILE" ]]; then
|
if [[ ! -s "$WEB_TLS_CERT_FILE" || ! -s "$WEB_TLS_KEY_FILE" ]]; then
|
||||||
log "Requesting HTTPS certificate for ${WEB_HOSTNAME}"
|
log "Requesting HTTPS certificate for ${WEB_HOSTNAME}"
|
||||||
if [[ -n "${STEP_CA_TOKEN:-}" ]]; then
|
if [[ -n "${TLS_CA_TOKEN:-}" ]]; then
|
||||||
step ca certificate "$WEB_HOSTNAME" "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" --token "$STEP_CA_TOKEN" --force
|
step ca certificate "$WEB_HOSTNAME" "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" --token "$TLS_CA_TOKEN" --force
|
||||||
else
|
else
|
||||||
require_env STEP_CA_PROVISIONER
|
require_env TLS_CA_PROVISIONER
|
||||||
if [[ -n "${STEP_CA_PROVISIONER_PASSWORD_FILE:-}" ]]; then
|
if [[ -n "${TLS_CA_PROVISIONER_PASSWORD_FILE:-}" ]]; then
|
||||||
provisioner_password_file="$STEP_CA_PROVISIONER_PASSWORD_FILE"
|
provisioner_password_file="$TLS_CA_PROVISIONER_PASSWORD_FILE"
|
||||||
elif [[ -n "${STEP_CA_PROVISIONER_PASSWORD:-}" ]]; then
|
elif [[ -n "${TLS_CA_PROVISIONER_PASSWORD:-}" ]]; then
|
||||||
provisioner_password_file="/run/step-provisioner-password"
|
provisioner_password_file="/run/tls-ca-provisioner-password"
|
||||||
umask 077
|
umask 077
|
||||||
printf '%s\n' "$STEP_CA_PROVISIONER_PASSWORD" > "$provisioner_password_file"
|
printf '%s\n' "$TLS_CA_PROVISIONER_PASSWORD" > "$provisioner_password_file"
|
||||||
else
|
else
|
||||||
printf '[init] ERROR: STEP_CA_TOKEN, STEP_CA_PROVISIONER_PASSWORD_FILE, or STEP_CA_PROVISIONER_PASSWORD is required for initial TLS setup\n' >&2
|
printf '[init] ERROR: TLS_CA_TOKEN, TLS_CA_PROVISIONER_PASSWORD_FILE, or TLS_CA_PROVISIONER_PASSWORD is required for initial TLS setup\n' >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
step ca certificate "$WEB_HOSTNAME" "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" \
|
step ca certificate "$WEB_HOSTNAME" "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" \
|
||||||
--provisioner "$STEP_CA_PROVISIONER" \
|
--provisioner "$TLS_CA_PROVISIONER" \
|
||||||
--provisioner-password-file "$provisioner_password_file" \
|
--provisioner-password-file "$provisioner_password_file" \
|
||||||
--force
|
--force
|
||||||
if [[ "$provisioner_password_file" == "/run/step-provisioner-password" ]]; then
|
if [[ "$provisioner_password_file" == "/run/tls-ca-provisioner-password" ]]; then
|
||||||
rm -f "$provisioner_password_file"
|
rm -f "$provisioner_password_file"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -390,6 +439,24 @@ configure_web_tls() {
|
|||||||
chmod 0644 "$WEB_TLS_CERT_FILE"
|
chmod 0644 "$WEB_TLS_CERT_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_acme_renewal_daemon() {
|
||||||
|
local interval="${ACME_RENEW_CHECK_SECONDS:-900}"
|
||||||
|
if [[ ! "$interval" =~ ^[0-9]+$ ]] || (( interval < 60 )); then
|
||||||
|
log "Invalid ACME_RENEW_CHECK_SECONDS=${interval}; using 900"
|
||||||
|
interval=900
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Starting ACME certificate renewal check every ${interval} seconds"
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
sleep "$interval"
|
||||||
|
if step certificate needs-renewal "$WEB_TLS_CERT_FILE" >/dev/null 2>&1; then
|
||||||
|
request_acme_certificate || log 'ACME certificate renewal failed; retrying at the next interval.'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
}
|
||||||
|
|
||||||
start_observability_services() {
|
start_observability_services() {
|
||||||
log 'Starting Samba audit collector'
|
log 'Starting Samba audit collector'
|
||||||
python3 /app/audit_collector.py &
|
python3 /app/audit_collector.py &
|
||||||
@@ -397,10 +464,15 @@ start_observability_services() {
|
|||||||
if web_should_start; then
|
if web_should_start; then
|
||||||
ensure_web_jwt_secret
|
ensure_web_jwt_secret
|
||||||
configure_web_tls
|
configure_web_tls
|
||||||
unset STEP_CA_PROVISIONER_PASSWORD STEP_CA_TOKEN
|
unset TLS_CA_PROVISIONER_PASSWORD TLS_CA_TOKEN
|
||||||
if [[ "${WEB_TLS_MODE:-step}" == "step" ]] && env_is_true "${WEB_TLS_AUTORENEW:-true}"; then
|
if env_is_true "${WEB_TLS_AUTORENEW:-true}"; then
|
||||||
log 'Starting Smallstep certificate renewal daemon'
|
case "$ACTIVE_WEB_TLS_MODE" in
|
||||||
step ca renew --daemon --force "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" &
|
acme) start_acme_renewal_daemon ;;
|
||||||
|
ca)
|
||||||
|
log 'Starting CA certificate renewal daemon'
|
||||||
|
step ca renew --daemon --force "$WEB_TLS_CERT_FILE" "$WEB_TLS_KEY_FILE" &
|
||||||
|
;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
log "Starting read-only web UI for https://${WEB_HOSTNAME}"
|
log "Starting read-only web UI for https://${WEB_HOSTNAME}"
|
||||||
python3 /app/web_ui.py &
|
python3 /app/web_ui.py &
|
||||||
|
|||||||
+19
-6
@@ -30,8 +30,23 @@ DOMAIN_SID = os.environ["PREVIEW_DOMAIN_SID"]
|
|||||||
ADMIN_USER = os.environ["PREVIEW_ADMIN_USER"]
|
ADMIN_USER = os.environ["PREVIEW_ADMIN_USER"]
|
||||||
ADMIN_PASSWORD = os.environ["PREVIEW_ADMIN_PASSWORD"]
|
ADMIN_PASSWORD = os.environ["PREVIEW_ADMIN_PASSWORD"]
|
||||||
USER_PASSWORD = os.environ["PREVIEW_USER_PASSWORD"]
|
USER_PASSWORD = os.environ["PREVIEW_USER_PASSWORD"]
|
||||||
BASE_URL = f"https://localhost:{HTTPS_PORT}"
|
HTTPS_HOST = os.environ["PREVIEW_HTTPS_HOST"]
|
||||||
|
BASE_URL = f"https://{HTTPS_HOST}:{HTTPS_PORT}"
|
||||||
|
_ORIGINAL_GETADDRINFO = socket.getaddrinfo
|
||||||
|
|
||||||
|
|
||||||
|
def preview_getaddrinfo(host, port, *args, **kwargs):
|
||||||
|
if host == HTTPS_HOST:
|
||||||
|
host = "127.0.0.1"
|
||||||
|
return _ORIGINAL_GETADDRINFO(host, port, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
socket.getaddrinfo = preview_getaddrinfo
|
||||||
TLS_CONTEXT = ssl.create_default_context(cafile=CA_ROOT)
|
TLS_CONTEXT = ssl.create_default_context(cafile=CA_ROOT)
|
||||||
|
HTTP_OPENER = urllib.request.build_opener(
|
||||||
|
urllib.request.ProxyHandler({}),
|
||||||
|
urllib.request.HTTPSHandler(context=TLS_CONTEXT),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -85,9 +100,7 @@ def http(
|
|||||||
f"{BASE_URL}{path}", data=body, headers=headers, method=method
|
f"{BASE_URL}{path}", data=body, headers=headers, method=method
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(
|
with HTTP_OPENER.open(request, timeout=30) as response:
|
||||||
request, context=TLS_CONTEXT, timeout=30
|
|
||||||
) as response:
|
|
||||||
return Response(response.status, response.headers, response.read())
|
return Response(response.status, response.headers, response.read())
|
||||||
except urllib.error.HTTPError as exc:
|
except urllib.error.HTTPError as exc:
|
||||||
return Response(exc.code, exc.headers, exc.read())
|
return Response(exc.code, exc.headers, exc.read())
|
||||||
@@ -152,10 +165,10 @@ def main() -> int:
|
|||||||
check("max-age=" in index.headers.get("Strict-Transport-Security", ""), "HSTS missing")
|
check("max-age=" in index.headers.get("Strict-Transport-Security", ""), "HSTS missing")
|
||||||
check("default-src 'self'" in index.headers.get("Content-Security-Policy", ""), "CSP missing")
|
check("default-src 'self'" in index.headers.get("Content-Security-Policy", ""), "CSP missing")
|
||||||
with socket.create_connection(("localhost", HTTPS_PORT), timeout=10) as raw:
|
with socket.create_connection(("localhost", HTTPS_PORT), timeout=10) as raw:
|
||||||
with TLS_CONTEXT.wrap_socket(raw, server_hostname="localhost") as secured:
|
with TLS_CONTEXT.wrap_socket(raw, server_hostname=HTTPS_HOST) as secured:
|
||||||
certificate = secured.getpeercert()
|
certificate = secured.getpeercert()
|
||||||
sans = {value for kind, value in certificate.get("subjectAltName", ()) if kind == "DNS"}
|
sans = {value for kind, value in certificate.get("subjectAltName", ()) if kind == "DNS"}
|
||||||
check("localhost" in sans, "issued certificate does not cover localhost")
|
check(HTTPS_HOST in sans, f"issued certificate does not cover {HTTPS_HOST}")
|
||||||
check(certificate.get("issuer") != certificate.get("subject"), "web certificate is self-signed instead of CA-issued")
|
check(certificate.get("issuer") != certificate.get("subject"), "web certificate is self-signed instead of CA-issued")
|
||||||
|
|
||||||
announce("JWT boundary, real Kerberos credentials, and Domain Admin authorization")
|
announce("JWT boundary, real Kerberos credentials, and Domain Admin authorization")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "445:445"
|
- "445:445"
|
||||||
- "139:139"
|
- "139:139"
|
||||||
|
- "${ACME_HTTP_PORT:-80}:80"
|
||||||
- "${WEB_HTTPS_PORT:-443}:${WEB_BIND_PORT:-8443}"
|
- "${WEB_HTTPS_PORT:-443}:${WEB_BIND_PORT:-8443}"
|
||||||
volumes:
|
volumes:
|
||||||
- private_data:/data/private
|
- private_data:/data/private
|
||||||
|
|||||||
+19
-12
@@ -34,6 +34,7 @@ dev_realm=${DEV_REALM:-DEV.TEST}
|
|||||||
dev_workgroup=${DEV_WORKGROUP:-DEV}
|
dev_workgroup=${DEV_WORKGROUP:-DEV}
|
||||||
dev_dns_domain=${DEV_DNS_DOMAIN:-dev.test}
|
dev_dns_domain=${DEV_DNS_DOMAIN:-dev.test}
|
||||||
dev_base_dn=${DEV_BASE_DN:-DC=dev,DC=test}
|
dev_base_dn=${DEV_BASE_DN:-DC=dev,DC=test}
|
||||||
|
dev_web_hostname=${DEV_WEB_HOSTNAME:-files.localhost}
|
||||||
dev_dc_password=${DEV_DC_PASSWORD:-PreviewDc123!}
|
dev_dc_password=${DEV_DC_PASSWORD:-PreviewDc123!}
|
||||||
dev_user_password=${DEV_USER_PASSWORD:-PreviewUser123!}
|
dev_user_password=${DEV_USER_PASSWORD:-PreviewUser123!}
|
||||||
dev_admin_user=${DEV_ADMIN_USER:-previewadmin}
|
dev_admin_user=${DEV_ADMIN_USER:-previewadmin}
|
||||||
@@ -49,7 +50,7 @@ dev_backup_interval=${DEV_BACKUP_INTERVAL_SECONDS:-120}
|
|||||||
server_image=${DEV_SERVER_IMAGE:-ad-ds-simple-file-server-dev:latest}
|
server_image=${DEV_SERVER_IMAGE:-ad-ds-simple-file-server-dev:latest}
|
||||||
ad_image=${DEV_AD_IMAGE:-ad-ds-simple-file-server-ad-dev:latest}
|
ad_image=${DEV_AD_IMAGE:-ad-ds-simple-file-server-ad-dev:latest}
|
||||||
backup_image=${DEV_BACKUP_IMAGE:-ad-ds-simple-file-server-backup-dev:latest}
|
backup_image=${DEV_BACKUP_IMAGE:-ad-ds-simple-file-server-backup-dev:latest}
|
||||||
step_ca_image=${DEV_STEP_CA_IMAGE:-docker.io/smallstep/step-ca:latest}
|
ca_image=${DEV_CA_IMAGE:-docker.io/smallstep/step-ca:latest}
|
||||||
|
|
||||||
run_id="ad-file-server-dev-$$-$RANDOM"
|
run_id="ad-file-server-dev-$$-$RANDOM"
|
||||||
network_name="$run_id-net"
|
network_name="$run_id-net"
|
||||||
@@ -216,18 +217,20 @@ for volume in "${volumes[@]}"; do
|
|||||||
"$engine" volume create "$volume" >/dev/null
|
"$engine" volume create "$volume" >/dev/null
|
||||||
done
|
done
|
||||||
|
|
||||||
printf 'starting local CA: %s\n' "$step_ca_image"
|
printf 'starting local CA: %s\n' "$ca_image"
|
||||||
"$engine" run -d \
|
"$engine" run -d \
|
||||||
--name "$ca_container" \
|
--name "$ca_container" \
|
||||||
--hostname "ca.${dev_dns_domain}" \
|
--hostname "ca.${dev_dns_domain}" \
|
||||||
--network "$network_name" \
|
--network "$network_name" \
|
||||||
--ip "$ca_ip" \
|
--ip "$ca_ip" \
|
||||||
|
--add-host "${dev_web_hostname}:${files_ip}" \
|
||||||
-e "DOCKER_STEPCA_INIT_NAME=AD file server preview CA" \
|
-e "DOCKER_STEPCA_INIT_NAME=AD file server preview CA" \
|
||||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=ca.${dev_dns_domain},localhost,127.0.0.1" \
|
-e "DOCKER_STEPCA_INIT_DNS_NAMES=ca.${dev_dns_domain},localhost,127.0.0.1" \
|
||||||
-e "DOCKER_STEPCA_INIT_PROVISIONER_NAME=${dev_ca_provisioner}" \
|
-e "DOCKER_STEPCA_INIT_PROVISIONER_NAME=${dev_ca_provisioner}" \
|
||||||
-e "DOCKER_STEPCA_INIT_PASSWORD=${dev_ca_password}" \
|
-e "DOCKER_STEPCA_INIT_PASSWORD=${dev_ca_password}" \
|
||||||
|
-e "DOCKER_STEPCA_INIT_ACME=true" \
|
||||||
-v "$ca_volume:/home/step" \
|
-v "$ca_volume:/home/step" \
|
||||||
"$step_ca_image" >/dev/null
|
"$ca_image" >/dev/null
|
||||||
|
|
||||||
if ! wait_for_exec "$ca_container" 120 step ca health \
|
if ! wait_for_exec "$ca_container" 120 step ca health \
|
||||||
--ca-url=https://localhost:9000 \
|
--ca-url=https://localhost:9000 \
|
||||||
@@ -235,11 +238,15 @@ if ! wait_for_exec "$ca_container" 120 step ca health \
|
|||||||
show_logs
|
show_logs
|
||||||
die 'local CA did not become healthy'
|
die 'local CA did not become healthy'
|
||||||
fi
|
fi
|
||||||
ca_fingerprint=$("$engine" exec "$ca_container" step certificate fingerprint \
|
|
||||||
/home/step/certs/root_ca.crt)
|
|
||||||
preview_tmp_root=${TMPDIR:-/tmp}
|
preview_tmp_root=${TMPDIR:-/tmp}
|
||||||
ca_root_file="${preview_tmp_root%/}/${run_id}-root-ca.crt"
|
ca_root_file="${preview_tmp_root%/}/${run_id}-root-ca.crt"
|
||||||
"$engine" exec "$ca_container" cat /home/step/certs/root_ca.crt > "$ca_root_file"
|
"$engine" exec "$ca_container" cat /home/step/certs/root_ca.crt > "$ca_root_file"
|
||||||
|
"$engine" run --rm -i \
|
||||||
|
-v "$state_volume:/state" \
|
||||||
|
--entrypoint /bin/bash \
|
||||||
|
"$server_image" -lc \
|
||||||
|
'install -d -m 0755 /state/tls && dd of=/state/tls/acme-ca-certificates.pem status=none && chmod 0644 /state/tls/acme-ca-certificates.pem' \
|
||||||
|
< "$ca_root_file"
|
||||||
|
|
||||||
printf 'starting disposable rsync backup target\n'
|
printf 'starting disposable rsync backup target\n'
|
||||||
"$engine" run -d \
|
"$engine" run -d \
|
||||||
@@ -312,14 +319,13 @@ printf 'starting actual file server and HTTPS web UI\n'
|
|||||||
-e "NETBIOS_NAME=FILES" \
|
-e "NETBIOS_NAME=FILES" \
|
||||||
-e "AD_DNS_NAME=files.${dev_dns_domain}" \
|
-e "AD_DNS_NAME=files.${dev_dns_domain}" \
|
||||||
-e "WEB_ENABLED=true" \
|
-e "WEB_ENABLED=true" \
|
||||||
-e "WEB_HOSTNAME=localhost" \
|
-e "WEB_HOSTNAME=${dev_web_hostname}" \
|
||||||
-e "WEB_BIND_PORT=8443" \
|
-e "WEB_BIND_PORT=8443" \
|
||||||
-e "WEB_JWT_SECRET=preview-only-jwt-secret-with-at-least-32-bytes" \
|
-e "WEB_JWT_SECRET=preview-only-jwt-secret-with-at-least-32-bytes" \
|
||||||
-e "WEB_TLS_MODE=step" \
|
-e "WEB_TLS_MODE=acme" \
|
||||||
-e "STEP_CA_URL=https://ca.${dev_dns_domain}:9000" \
|
-e "ACME_CA_SERVER=https://ca.${dev_dns_domain}:9000/acme/acme/directory" \
|
||||||
-e "STEP_CA_FINGERPRINT=${ca_fingerprint}" \
|
-e "ACME_CA_CERTIFICATES=/state/tls/acme-ca-certificates.pem" \
|
||||||
-e "STEP_CA_PROVISIONER=${dev_ca_provisioner}" \
|
-e "ACME_HTTP_LISTEN=:80" \
|
||||||
-e "STEP_CA_PROVISIONER_PASSWORD=${dev_ca_password}" \
|
|
||||||
-e "WEB_USAGE_SCAN_INTERVAL_SECONDS=60" \
|
-e "WEB_USAGE_SCAN_INTERVAL_SECONDS=60" \
|
||||||
-e "WEB_DIRECTORY_CACHE_SECONDS=30" \
|
-e "WEB_DIRECTORY_CACHE_SECONDS=30" \
|
||||||
-e "AUDIT_POLL_SECONDS=0.25" \
|
-e "AUDIT_POLL_SECONDS=0.25" \
|
||||||
@@ -387,6 +393,7 @@ if [[ $run_e2e == 1 ]]; then
|
|||||||
PREVIEW_BACKUP_CONTAINER="$backup_container" \
|
PREVIEW_BACKUP_CONTAINER="$backup_container" \
|
||||||
PREVIEW_CA_ROOT="$ca_root_file" \
|
PREVIEW_CA_ROOT="$ca_root_file" \
|
||||||
PREVIEW_HTTPS_PORT="$dev_https_port" \
|
PREVIEW_HTTPS_PORT="$dev_https_port" \
|
||||||
|
PREVIEW_HTTPS_HOST="$dev_web_hostname" \
|
||||||
PREVIEW_REALM="$dev_realm" \
|
PREVIEW_REALM="$dev_realm" \
|
||||||
PREVIEW_WORKGROUP="$dev_workgroup" \
|
PREVIEW_WORKGROUP="$dev_workgroup" \
|
||||||
PREVIEW_DNS_DOMAIN="$dev_dns_domain" \
|
PREVIEW_DNS_DOMAIN="$dev_dns_domain" \
|
||||||
@@ -402,7 +409,7 @@ if [[ $run_e2e == 1 ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
printf '\nPreview ready\n'
|
printf '\nPreview ready\n'
|
||||||
printf ' URL: https://localhost:%s\n' "$dev_https_port"
|
printf ' URL: https://%s:%s\n' "$dev_web_hostname" "$dev_https_port"
|
||||||
printf ' Username: %s\\%s\n' "$dev_workgroup" "$dev_admin_user"
|
printf ' Username: %s\\%s\n' "$dev_workgroup" "$dev_admin_user"
|
||||||
printf ' Password: %s\n' "$dev_admin_password"
|
printf ' Password: %s\n' "$dev_admin_password"
|
||||||
printf ' CA root: %s\n' "$ca_root_file"
|
printf ' CA root: %s\n' "$ca_root_file"
|
||||||
|
|||||||
@@ -138,10 +138,11 @@ write_env_file() {
|
|||||||
local web_hostname=""
|
local web_hostname=""
|
||||||
local web_https_port="443"
|
local web_https_port="443"
|
||||||
local web_jwt_secret=""
|
local web_jwt_secret=""
|
||||||
local step_ca_url=""
|
local acme_ca_server=""
|
||||||
local step_ca_fingerprint=""
|
local acme_ca_certificates_source=""
|
||||||
local step_ca_provisioner=""
|
local acme_ca_certificates_source_dir=""
|
||||||
local step_ca_provisioner_password=""
|
local acme_http_port="80"
|
||||||
|
local acme_http_port_input=""
|
||||||
local web_hostname_input=""
|
local web_hostname_input=""
|
||||||
local service_account_sam=""
|
local service_account_sam=""
|
||||||
local fslogix_group_prompt=""
|
local fslogix_group_prompt=""
|
||||||
@@ -217,10 +218,16 @@ write_env_file() {
|
|||||||
web_hostname="${web_hostname_input:-$web_hostname}"
|
web_hostname="${web_hostname_input:-$web_hostname}"
|
||||||
read -r -p "WEB_HTTPS_PORT [443]: " web_https_port
|
read -r -p "WEB_HTTPS_PORT [443]: " web_https_port
|
||||||
web_https_port="${web_https_port:-443}"
|
web_https_port="${web_https_port:-443}"
|
||||||
prompt_value step_ca_url "STEP_CA_URL (e.g. https://ca.example.com:9000)"
|
prompt_value acme_ca_server "ACME_CA_SERVER (e.g. https://ca.internal/acme/acme/directory)"
|
||||||
prompt_value step_ca_fingerprint "STEP_CA_FINGERPRINT"
|
prompt_value acme_ca_certificates_source "ACME CA root bundle (PEM file on this host)"
|
||||||
prompt_value step_ca_provisioner "STEP_CA_PROVISIONER (JWK provisioner name)"
|
if [[ ! -s "$acme_ca_certificates_source" ]]; then
|
||||||
prompt_value step_ca_provisioner_password "STEP_CA_PROVISIONER_PASSWORD" true
|
printf "ACME CA root bundle is not a readable file: %s\n" "$acme_ca_certificates_source" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
acme_ca_certificates_source_dir="$(cd "$(dirname "$acme_ca_certificates_source")" && pwd)"
|
||||||
|
acme_ca_certificates_source="${acme_ca_certificates_source_dir}/$(basename "$acme_ca_certificates_source")"
|
||||||
|
read -r -p "ACME_HTTP_PORT (HTTP-01 host port) [80]: " acme_http_port_input
|
||||||
|
acme_http_port="${acme_http_port_input:-80}"
|
||||||
|
|
||||||
web_jwt_secret="$(python3 - <<'PY'
|
web_jwt_secret="$(python3 - <<'PY'
|
||||||
import secrets
|
import secrets
|
||||||
@@ -279,11 +286,11 @@ WEB_ENABLED=true
|
|||||||
WEB_HOSTNAME=${web_hostname}
|
WEB_HOSTNAME=${web_hostname}
|
||||||
WEB_HTTPS_PORT=${web_https_port}
|
WEB_HTTPS_PORT=${web_https_port}
|
||||||
WEB_JWT_SECRET=${web_jwt_secret}
|
WEB_JWT_SECRET=${web_jwt_secret}
|
||||||
WEB_TLS_MODE=step
|
WEB_TLS_MODE=acme
|
||||||
STEP_CA_URL=${step_ca_url}
|
ACME_CA_SERVER=${acme_ca_server}
|
||||||
STEP_CA_FINGERPRINT=${step_ca_fingerprint}
|
ACME_CA_CERTIFICATES=/state/tls/acme-ca-certificates.pem
|
||||||
STEP_CA_PROVISIONER=${step_ca_provisioner}
|
ACME_HTTP_LISTEN=:80
|
||||||
STEP_CA_PROVISIONER_PASSWORD=${step_ca_provisioner_password}
|
ACME_HTTP_PORT=${acme_http_port}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cp "$BOOTSTRAP_ENV_FILE" "$ENV_FILE"
|
cp "$BOOTSTRAP_ENV_FILE" "$ENV_FILE"
|
||||||
@@ -293,6 +300,12 @@ EOF
|
|||||||
printf "Building image...\n"
|
printf "Building image...\n"
|
||||||
docker compose build samba
|
docker compose build samba
|
||||||
|
|
||||||
|
printf "Importing ACME CA root bundle...\n"
|
||||||
|
docker compose run --rm --no-deps -T \
|
||||||
|
--entrypoint /bin/bash samba -lc \
|
||||||
|
'install -d -m 0755 "$(dirname "$ACME_CA_CERTIFICATES")" && dd of="$ACME_CA_CERTIFICATES" status=none && chmod 0644 "$ACME_CA_CERTIFICATES"' \
|
||||||
|
< "$acme_ca_certificates_source"
|
||||||
|
|
||||||
printf "Provisioning service account %s...\n" "$SERVICE_ACCOUNT_NAME"
|
printf "Provisioning service account %s...\n" "$SERVICE_ACCOUNT_NAME"
|
||||||
docker compose run --rm --entrypoint /bin/bash samba -lc '
|
docker compose run --rm --entrypoint /bin/bash samba -lc '
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -348,11 +361,11 @@ WEB_ENABLED=true
|
|||||||
WEB_HOSTNAME=${web_hostname}
|
WEB_HOSTNAME=${web_hostname}
|
||||||
WEB_HTTPS_PORT=${web_https_port}
|
WEB_HTTPS_PORT=${web_https_port}
|
||||||
WEB_JWT_SECRET=${web_jwt_secret}
|
WEB_JWT_SECRET=${web_jwt_secret}
|
||||||
WEB_TLS_MODE=step
|
WEB_TLS_MODE=acme
|
||||||
STEP_CA_URL=${step_ca_url}
|
ACME_CA_SERVER=${acme_ca_server}
|
||||||
STEP_CA_FINGERPRINT=${step_ca_fingerprint}
|
ACME_CA_CERTIFICATES=/state/tls/acme-ca-certificates.pem
|
||||||
STEP_CA_PROVISIONER=${step_ca_provisioner}
|
ACME_HTTP_LISTEN=:80
|
||||||
STEP_CA_PROVISIONER_PASSWORD=${step_ca_provisioner_password}
|
ACME_HTTP_PORT=${acme_http_port}
|
||||||
# Optional overrides:
|
# Optional overrides:
|
||||||
# LDAP_URI=ldaps://${domain}
|
# LDAP_URI=ldaps://${domain}
|
||||||
# LDAP_BASE_DN=DC=example,DC=com
|
# LDAP_BASE_DN=DC=example,DC=com
|
||||||
@@ -375,7 +388,7 @@ STEP_CA_PROVISIONER_PASSWORD=${step_ca_provisioner_password}
|
|||||||
# WEB_DIRECTORY_CACHE_SECONDS=300
|
# WEB_DIRECTORY_CACHE_SECONDS=300
|
||||||
# AUDIT_COMPRESS_AFTER_HOURS=24
|
# AUDIT_COMPRESS_AFTER_HOURS=24
|
||||||
# AUDIT_QUERY_MAX_DAYS=31
|
# AUDIT_QUERY_MAX_DAYS=31
|
||||||
# STEP_CA_PROVISIONER_PASSWORD_FILE=/run/secrets/step-ca-provisioner-password
|
# ACME_RENEW_CHECK_SECONDS=900
|
||||||
# WEB_TLS_CERT_FILE=/state/tls/web.crt
|
# WEB_TLS_CERT_FILE=/state/tls/web.crt
|
||||||
# WEB_TLS_KEY_FILE=/state/tls/web.key
|
# WEB_TLS_KEY_FILE=/state/tls/web.key
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
Reference in New Issue
Block a user