The module gains a runtime carrying only the fail2ban client with the daemon's socket shared in, serving status/banned/ban/unban and its own fail2ban_settings. It declares jailing, so the controller's composition lands in jail.d/mesh.conf and filter.d; mailu, route-proxy and gitea log to the journal and declare a jail reading it by container name. The base is strict: three in a day for a day, twice banned in two weeks for four; the mesh's range stays never banned.
207 lines
5.8 KiB
JSON
207 lines
5.8 KiB
JSON
{
|
|
"module": "route-proxy",
|
|
"version": "1",
|
|
"slug": "rproxy",
|
|
"capabilities": [
|
|
"container-runtime"
|
|
],
|
|
"provides": [
|
|
{
|
|
"name": "route",
|
|
"scope": "mesh"
|
|
}
|
|
],
|
|
"serves": {
|
|
"route": {}
|
|
},
|
|
"receives": {
|
|
"route": "${dir:routes-dir}/mesh.json"
|
|
},
|
|
"requires": [
|
|
"acme-ca",
|
|
"internal-acme-ca"
|
|
],
|
|
"binds": {
|
|
"acme-ca": "${dir:state}/acme-ca.json",
|
|
"internal-acme-ca": "${dir:state}/internal-acme-ca.json"
|
|
},
|
|
"own-secrets": {
|
|
"broker": "${dir:mesh-state}/broker"
|
|
},
|
|
"listens": [
|
|
{
|
|
"name": "http",
|
|
"port": 80,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "public HTTP, and the ACME HTTP-01 challenge answered at the name being certified"
|
|
},
|
|
{
|
|
"name": "https",
|
|
"port": 443,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "public HTTPS for every name the mesh routes here"
|
|
}
|
|
],
|
|
"resources": [
|
|
{
|
|
"id": "state",
|
|
"type": "directory",
|
|
"mode": "0700",
|
|
"place": "."
|
|
},
|
|
{
|
|
"id": "mesh-state",
|
|
"type": "directory",
|
|
"mode": "0700",
|
|
"place": "mesh"
|
|
},
|
|
{
|
|
"id": "routes-dir",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/routes",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "acme-cache",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/acme",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "ca-dir",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/ca",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "acme-env",
|
|
"type": "file",
|
|
"path": "${dir:state}/acme.env",
|
|
"mode": "0600",
|
|
"content": "ACME_DIRECTORY=https://${bound:acme-ca:at}:${bound:acme-ca:port}${bound:acme-ca:path}\nACME_ROOTS=https://${bound:acme-ca:at}:${bound:acme-ca:port}${bound:acme-ca:roots}\nACME_ROOTS_PATH=${bound:acme-ca:roots}\n"
|
|
},
|
|
{
|
|
"id": "internal-acme-env",
|
|
"type": "file",
|
|
"path": "${dir:state}/internal-acme.env",
|
|
"mode": "0600",
|
|
"content": "INTERNAL_ACME_DIRECTORY=https://${bound:internal-acme-ca:at}:${bound:internal-acme-ca:port}${bound:internal-acme-ca:path}\nINTERNAL_ACME_ROOTS=https://${bound:internal-acme-ca:at}:${bound:internal-acme-ca:port}${bound:internal-acme-ca:roots}\nINTERNAL_ACME_ROOTS_PATH=${bound:internal-acme-ca:roots}\n"
|
|
},
|
|
{
|
|
"id": "trust",
|
|
"type": "container",
|
|
"name": "route-proxy-trust",
|
|
"artifact": "trust",
|
|
"run-once": true,
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:ca-dir}:/ca"
|
|
],
|
|
"args": [
|
|
"sh",
|
|
"-c",
|
|
"if [ -z \"$ACME_ROOTS_PATH\" ]; then cp /etc/ssl/certs/ca-certificates.crt /ca/root.crt; exit 0; fi; for i in $(seq 1 60); do wget -q -T 10 --no-check-certificate -O /ca/root.crt \"$ACME_ROOTS\" && grep -q 'BEGIN CERTIFICATE' /ca/root.crt && exit 0; sleep 2; done; echo \"the authority at $ACME_ROOTS did not serve its roots within two minutes\" >&2; exit 1"
|
|
],
|
|
"restart-on": [
|
|
"acme-env"
|
|
]
|
|
},
|
|
{
|
|
"id": "internal-trust",
|
|
"type": "container",
|
|
"name": "route-proxy-internal-trust",
|
|
"artifact": "trust",
|
|
"run-once": true,
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/internal-acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:ca-dir}:/ca"
|
|
],
|
|
"args": [
|
|
"sh",
|
|
"-c",
|
|
"if [ -z \"$INTERNAL_ACME_ROOTS_PATH\" ]; then cp /etc/ssl/certs/ca-certificates.crt /ca/internal-root.crt; exit 0; fi; for i in $(seq 1 60); do wget -q -T 10 --no-check-certificate -O /ca/internal-root.crt \"$INTERNAL_ACME_ROOTS\" && grep -q 'BEGIN CERTIFICATE' /ca/internal-root.crt && exit 0; sleep 2; done; echo \"the authority at $INTERNAL_ACME_ROOTS did not serve its roots within two minutes\" >&2; exit 1"
|
|
],
|
|
"restart-on": [
|
|
"internal-acme-env"
|
|
]
|
|
},
|
|
{
|
|
"id": "server",
|
|
"type": "container",
|
|
"name": "route-proxy",
|
|
"artifact": "server",
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/acme.env",
|
|
"${dir:state}/internal-acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:routes-dir}:/routes:ro",
|
|
"${dir:acme-cache}:/acme",
|
|
"${dir:ca-dir}:/ca:ro",
|
|
"${dir:mesh-state}/broker:/run/secrets/broker:ro"
|
|
],
|
|
"env": {
|
|
"ROUTES": "/routes/mesh.json",
|
|
"LISTEN": ":80",
|
|
"TLS_LISTEN": ":443",
|
|
"ACME_CACHE": "/acme",
|
|
"ACME_CA_BUNDLE": "/ca/root.crt",
|
|
"INTERNAL_ACME_CA_BUNDLE": "/ca/internal-root.crt",
|
|
"MESH_BROKER_FILE": "/run/secrets/broker"
|
|
},
|
|
"restart-on": [
|
|
"trust",
|
|
"acme-env",
|
|
"internal-trust",
|
|
"internal-acme-env"
|
|
],
|
|
"logging": "journald"
|
|
}
|
|
],
|
|
"build": {
|
|
"artifacts": [
|
|
{
|
|
"name": "server",
|
|
"kind": "image",
|
|
"from": "Dockerfile",
|
|
"context": {
|
|
"seat": "git",
|
|
"repository": "novox/mesh-controller",
|
|
"ref": "main"
|
|
}
|
|
},
|
|
{
|
|
"name": "trust",
|
|
"kind": "upstream",
|
|
"from": "alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
|
|
}
|
|
],
|
|
"on": [
|
|
{
|
|
"arg": "GO_BASE",
|
|
"image": "golang@sha256:6c2a5538f964f1c82f97ad14988bf05de100d922d159d0e398b54c7b0ca0c6c9"
|
|
},
|
|
{
|
|
"arg": "ALPINE_BASE",
|
|
"image": "alpine@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc"
|
|
}
|
|
]
|
|
},
|
|
"jails": [
|
|
{
|
|
"name": "route-proxy",
|
|
"failregex": "^.*(?:TLS handshake error from <HOST>:\\d+: (?:no public route for|acme/autocert: missing server name)|refused: no route for .*, asked from <HOST>:\\d+)$",
|
|
"jail": "backend = systemd\njournalmatch = CONTAINER_NAME=route-proxy\nport = http,https\nmaxretry = 10\nfindtime = 1d\nbantime = 1d"
|
|
}
|
|
]
|
|
}
|