modified: core/authelia/docker-compose.yml
modified: core/crowdsec/docker-compose.yml modified: core/error-pages/docker-compose.yml modified: monitoring/docker-exporter/docker-compose.yml modified: monitoring/docker-socket-proxy/docker-compose.yml deleted: monitoring/influxdb-service/docker-compose.yml modified: monitoring/node-exporter/docker-compose.yml modified: monitoring/pihole-exporter/docker-compose.yml modified: monitoring/telegraf/docker-compose.yml new file: service-access-policy.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
authelia:
|
authelia:
|
||||||
profiles: ["core","all","authelia"]
|
profiles: ["core","all","authelia", "traefik"]
|
||||||
image: authelia/authelia
|
image: authelia/authelia
|
||||||
restart: always
|
restart: always
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
crowdsec:
|
crowdsec:
|
||||||
profiles: ["core","all","crowdsec"]
|
profiles: ["core","all","crowdsec", "traefik"]
|
||||||
# image: crowdsecurity/crowdsec:latest
|
# image: crowdsecurity/crowdsec:latest
|
||||||
build: ${PROJECT_ROOT}/core/crowdsec
|
build: ${PROJECT_ROOT}/core/crowdsec
|
||||||
container_name: crowdsec
|
container_name: crowdsec
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
error-pages:
|
error-pages:
|
||||||
profiles: ["core","all","error-pages"]
|
profiles: ["core","all","error-pages", "traefik"]
|
||||||
image: tarampampam/error-pages:3
|
image: tarampampam/error-pages:3
|
||||||
restart: always
|
restart: always
|
||||||
container_name: error-pages
|
container_name: error-pages
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
docker-update-exporter:
|
docker-update-exporter:
|
||||||
profiles: ["monitoring","all","docker-exporter"]
|
profiles: ["monitoring","all","docker-exporter", "prometheus"]
|
||||||
build:
|
build:
|
||||||
context: ${PROJECT_ROOT}/monitoring/docker-exporter
|
context: ${PROJECT_ROOT}/monitoring/docker-exporter
|
||||||
container_name: docker-update-exporter
|
container_name: docker-update-exporter
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
docker-socket-proxy:
|
docker-socket-proxy:
|
||||||
profiles: ["monitoring","all","docker-socket-proxy"]
|
profiles: ["monitoring","all","docker-socket-proxy", "core", "traefik", "prometheus"]
|
||||||
image: tecnativa/docker-socket-proxy:latest
|
image: tecnativa/docker-socket-proxy:latest
|
||||||
container_name: docker-socket-proxy
|
container_name: docker-socket-proxy
|
||||||
hostname: docker-socket-proxy
|
hostname: docker-socket-proxy
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
services:
|
|
||||||
influxdb:
|
|
||||||
profiles: ["monitoring","all","influxdb-service"]
|
|
||||||
image: influxdb:2.7
|
|
||||||
container_name: influxdb
|
|
||||||
restart: unless-stopped
|
|
||||||
# env_file:
|
|
||||||
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
|
|
||||||
volumes:
|
|
||||||
- ${PROJECT_ROOT}/monitoring/influxdb:/var/lib/influxdb2
|
|
||||||
environment:
|
|
||||||
DOCKER_INFLUXDB_INIT_MODE: ${INFLUXDB_INIT_MODE}
|
|
||||||
DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_INIT_USERNAME}
|
|
||||||
DOCKER_INFLUXDB_INIT_PASSWORD_FILE: /run/secrets/influxdb_init_password
|
|
||||||
DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_INIT_ORG}
|
|
||||||
DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_INIT_BUCKET}
|
|
||||||
secrets:
|
|
||||||
- influxdb_init_password
|
|
||||||
networks:
|
|
||||||
# - edge
|
|
||||||
# - traefik_reverse_proxy
|
|
||||||
- traefik
|
|
||||||
- monitor
|
|
||||||
labels:
|
|
||||||
- "traefik.http.routers.influxdb.rule=Host(`influxdb.lan.ddnsgeek.com`)"
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.influxdb.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.influxdb.tls.certresolver=myresolver"
|
|
||||||
- "io.portainer.accesscontrol.public"
|
|
||||||
- "traefik.http.services.influxdb.loadbalancer.server.port=8086"
|
|
||||||
- "traefik.http.routers.influxdb.middlewares=authelia"
|
|
||||||
- "traefik.docker.network=core_traefik"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "curl -f http://localhost:8086/health || exit 1"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
start_period: 10s
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
influxdb_init_password:
|
|
||||||
file: ${PROJECT_ROOT}/secrets/influxdb_init_password.txt
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
node-exporter:
|
node-exporter:
|
||||||
profiles: ["monitoring","all","node-exporter"]
|
profiles: ["monitoring","all","node-exporter", "prometheus"]
|
||||||
image: prom/node-exporter:latest
|
image: prom/node-exporter:latest
|
||||||
container_name: node-exporter
|
container_name: node-exporter
|
||||||
pid: host
|
pid: host
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
pihole-exporter:
|
pihole-exporter:
|
||||||
profiles: ["monitoring","all","pihole-exporter"]
|
profiles: ["monitoring","all","pihole-exporter", "prometheus"]
|
||||||
image: ekofr/pihole-exporter:latest
|
image: ekofr/pihole-exporter:latest
|
||||||
container_name: pihole-exporter
|
container_name: pihole-exporter
|
||||||
# env_file:
|
# env_file:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
telegraf:
|
telegraf:
|
||||||
profiles: ["monitoring","all","telegraf"]
|
profiles: ["monitoring","all","telegraf", "prometheus"]
|
||||||
image: telegraf:latest
|
image: telegraf:latest
|
||||||
container_name: telegraf
|
container_name: telegraf
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# Service Access Policy and External Exposure Hardening
|
||||||
|
|
||||||
|
## 1) Service classification
|
||||||
|
|
||||||
|
| Service/Host | Classification | Rationale |
|
||||||
|
|---|---|---|
|
||||||
|
| `auth.lan.ddnsgeek.com` | `authenticated-public` | Public identity/login entrypoint; internet-accessible but requires user authentication. |
|
||||||
|
| `nextcloud.lan.ddnsgeek.com` | `authenticated-public` | Internet-facing collaboration app that must remain reachable to authenticated users. |
|
||||||
|
| `passbolt.lan.ddnsgeek.com` | `authenticated-public` | Public password-management portal with strong authentication controls. |
|
||||||
|
| `gitea.lan.ddnsgeek.com` | `authenticated-public` | Public developer endpoint with account-based access. |
|
||||||
|
| `searxng.lan.ddnsgeek.com` | `public` | Intended anonymous/search access endpoint. |
|
||||||
|
| `familytree.lan.ddnsgeek.com` | `authenticated-public` | End-user app; externally reachable but login-protected. |
|
||||||
|
| `shifts.lan.ddnsgeek.com` | `authenticated-public` | End-user app; externally reachable but login-protected. |
|
||||||
|
| `stockfill.lan.ddnsgeek.com` | `authenticated-public` | End-user app; externally reachable but login-protected. |
|
||||||
|
| `gotify.lan.ddnsgeek.com` | `private-admin` | Admin/ops notification backend; should not be internet reachable. |
|
||||||
|
| `grafana.lan.ddnsgeek.com` | `private-admin` | Infrastructure admin/observability console. |
|
||||||
|
| `prometheus.lan.ddnsgeek.com` | `private-admin` | Monitoring datastore/query interface. |
|
||||||
|
| `node-red.lan.ddnsgeek.com` | `private-admin` | Automation runtime and flow editor. |
|
||||||
|
| `traefik.lan.ddnsgeek.com` | `private-admin` | Reverse-proxy admin/dashboard surface. |
|
||||||
|
| `portainer.lan.ddnsgeek.com` | `private-admin` | Container management plane. |
|
||||||
|
| `influxdb.lan.ddnsgeek.com` | `private-admin` | Metrics datastore admin/API surface. |
|
||||||
|
| `kuma.lan.ddnsgeek.com` | `private-admin` | Monitoring admin surface. |
|
||||||
|
| `monitor-kuma.lan.ddnsgeek.com` | `private-admin` | Monitoring admin surface. |
|
||||||
|
| `edge.lan.ddnsgeek.com` | `private-admin` | Edge/network administration plane. |
|
||||||
|
|
||||||
|
## 2) Required controls for `private-admin`
|
||||||
|
|
||||||
|
Apply **at least one** trusted-path control (preferably layered):
|
||||||
|
|
||||||
|
- Private network only (no public DNS / no internet route).
|
||||||
|
- WireGuard/Tailscale/OpenVPN access gate.
|
||||||
|
- mTLS client certificate requirement at reverse proxy.
|
||||||
|
- Source IP allowlist at firewall and reverse proxy.
|
||||||
|
|
||||||
|
Minimum target state for all `private-admin` hosts:
|
||||||
|
|
||||||
|
- Public internet: connection refused/timeout, or immediate `403` for untrusted source.
|
||||||
|
- Trusted path (VPN/mTLS/allowlisted IP): normal authenticated access.
|
||||||
|
|
||||||
|
## 3) Gateway auth hardening
|
||||||
|
|
||||||
|
For all `public` and `authenticated-public` services:
|
||||||
|
|
||||||
|
- Keep SSO and MFA enforcement at the identity gateway.
|
||||||
|
- Enforce lockout/backoff on `/login`, `/oauth/*`, `/auth/*`, `/api/auth/*`.
|
||||||
|
- Rate-limit by source IP + account identifier to deter credential stuffing.
|
||||||
|
|
||||||
|
Suggested baseline:
|
||||||
|
|
||||||
|
- Soft limit: `10 req/min` per IP for auth endpoints.
|
||||||
|
- Burst: `20`.
|
||||||
|
- Temporary block: `15 min` after repeated failures.
|
||||||
|
- Account lockout: `5-10` consecutive failed attempts (with secure unlock flow).
|
||||||
|
|
||||||
|
## 4) WAF / reverse-proxy protections
|
||||||
|
|
||||||
|
Deploy one of:
|
||||||
|
|
||||||
|
- WAF managed rules for bot/credential-stuffing signatures.
|
||||||
|
- Reverse-proxy failed-auth throttling and tarpit/delay policy.
|
||||||
|
|
||||||
|
Implement logging + alerting thresholds:
|
||||||
|
|
||||||
|
- High failed-auth rate from one IP/CIDR.
|
||||||
|
- Password spray pattern across many usernames.
|
||||||
|
- Geo/ASN anomalies for sensitive apps.
|
||||||
|
|
||||||
|
## 5) External re-test procedure
|
||||||
|
|
||||||
|
Re-test from a non-trusted external network and record outcomes.
|
||||||
|
|
||||||
|
Success criteria:
|
||||||
|
|
||||||
|
- Every `private-admin` host is inaccessible without VPN/mTLS/allowlisted source.
|
||||||
|
- `public` and `authenticated-public` hosts remain reachable.
|
||||||
|
- Auth endpoints trigger rate-limit/lockout controls under failed-attempt simulation.
|
||||||
|
|
||||||
|
Use `./scripts/retest-external-access.sh` for a repeatable external validation pass.
|
||||||
Reference in New Issue
Block a user