The six media providers share their one credential with every consumer (ADR 0158)
nzbget, qbittorrent, jackett, sonarr, radarr and lidarr each hold one credential; the offer now names the provider's own secret as the provision's credential, that secret is taken at start, and a custom-cont-init script applies the file to the software on every start (nzbget: NZBGET_USER beside the password it already took as a start option; qbittorrent: the WebUI login's PBKDF2 hash; jackett: APIKey in ServerConfig.json; the arrs: <ApiKey> in config.xml). Nothing is accepted per consumer any more; rotating the provider's secret reaches everyone.
This commit is contained in:
@@ -4,7 +4,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "jackett-api",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"own": "api-key"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
@@ -52,6 +55,18 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "mesh-init",
|
||||
"type": "directory",
|
||||
"mode": "0755"
|
||||
},
|
||||
{
|
||||
"id": "api-key-init",
|
||||
"type": "file",
|
||||
"path": "${dir:mesh-init}/10-mesh-api-key.sh",
|
||||
"mode": "0755",
|
||||
"content": "#!/bin/bash\n# Written by the mesh (ADR 0158): this module's one credential is the vault's, shared with every\n# consumer; the file is applied here, before the service starts, on every start.\nset -euo pipefail\nCONF=/config/Jackett/ServerConfig.json\nKEY=$(cat /run/secrets/api-key)\nmkdir -p /config/Jackett\nif [ -s \"$CONF\" ]; then\n jq --arg k \"$KEY\" '.APIKey = $k' \"$CONF\" > \"$CONF.mesh\" && mv \"$CONF.mesh\" \"$CONF\"\nelse\n jq -n --arg k \"$KEY\" '{APIKey: $k}' > \"$CONF\"\nfi\necho \"[mesh] Jackett API key set from the vault's credential\"\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -64,13 +79,17 @@
|
||||
"9117"
|
||||
],
|
||||
"volumes": [
|
||||
"${dir:config}:/config"
|
||||
"${dir:config}:/config",
|
||||
"${dir:mesh-init}:/custom-cont-init.d:ro",
|
||||
"${dir:mesh-state}/api-key:/run/secrets/api-key:ro"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
],
|
||||
"restart-on": [
|
||||
"identity"
|
||||
"identity",
|
||||
"needs-api-key",
|
||||
"api-key-init"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -104,7 +123,11 @@
|
||||
}
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker"
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"api-key": {
|
||||
"path": "${dir:mesh-state}/api-key",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"requires": [
|
||||
"route"
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "lidarr-api",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"own": "api-key"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
@@ -23,7 +26,11 @@
|
||||
],
|
||||
"consumes": [],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker"
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"api-key": {
|
||||
"path": "${dir:mesh-state}/api-key",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
@@ -82,6 +89,13 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "api-key-init",
|
||||
"type": "file",
|
||||
"path": "${dir:custom-cont-init}/00-mesh-api-key.sh",
|
||||
"mode": "0755",
|
||||
"content": "#!/bin/bash\n# Written by the mesh (ADR 0158): this module's one credential is the vault's, shared with every\n# consumer; the file is applied here, before the service starts, on every start.\nset -euo pipefail\nCONF=/config/config.xml\nKEY=$(cat /run/secrets/api-key)\nif [ -s \"$CONF\" ] && grep -q '<ApiKey>' \"$CONF\"; then\n sed -i -E \"s#<ApiKey>[^<]*</ApiKey>#<ApiKey>$KEY</ApiKey>#\" \"$CONF\"\nelif [ -s \"$CONF\" ]; then\n sed -i -E \"s#</Config># <ApiKey>$KEY</ApiKey>\\n</Config>#\" \"$CONF\"\nelse\n printf '<Config>\\n <ApiKey>%s</ApiKey>\\n</Config>\\n' \"$KEY\" > \"$CONF\"\nfi\necho \"[mesh] API key set from the vault's credential\"\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -98,13 +112,16 @@
|
||||
"${dir:custom-cont-init}:/custom-cont-init.d",
|
||||
"${dir:custom-services}:/custom-services.d",
|
||||
"${access:music}:/music",
|
||||
"${access:downloads}:/downloads"
|
||||
"${access:downloads}:/downloads",
|
||||
"${dir:mesh-state}/api-key:/run/secrets/api-key:ro"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
],
|
||||
"restart-on": [
|
||||
"identity"
|
||||
"identity",
|
||||
"needs-api-key",
|
||||
"api-key-init"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
"consumes": [],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"password": "${dir:mesh-state}/password"
|
||||
"password": {
|
||||
"path": "${dir:mesh-state}/password",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
@@ -55,6 +58,13 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "server-env",
|
||||
"type": "file",
|
||||
"path": "${dir:state}/server.env",
|
||||
"mode": "0644",
|
||||
"content": "NZBGET_USER=${setting:username}\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -74,10 +84,12 @@
|
||||
],
|
||||
"restart-on": [
|
||||
"needs-password",
|
||||
"identity"
|
||||
"identity",
|
||||
"server-env"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
"${dir:state}/identity.env",
|
||||
"${dir:state}/server.env"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -114,7 +126,12 @@
|
||||
}
|
||||
],
|
||||
"provides": [
|
||||
"nzbget-api"
|
||||
{
|
||||
"name": "nzbget-api",
|
||||
"credential": {
|
||||
"own": "password"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
"nzbget-api": {
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
"consumes": [],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"password": "${dir:mesh-state}/password"
|
||||
"password": {
|
||||
"path": "${dir:mesh-state}/password",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
@@ -70,6 +73,18 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "mesh-init",
|
||||
"type": "directory",
|
||||
"mode": "0755"
|
||||
},
|
||||
{
|
||||
"id": "webui-login-init",
|
||||
"type": "file",
|
||||
"path": "${dir:mesh-init}/10-mesh-webui-login.sh",
|
||||
"mode": "0755",
|
||||
"content": "#!/bin/bash\n# Written by the mesh (ADR 0158): this module's one credential is the vault's, shared with every\n# consumer; the file is applied here, before the service starts, on every start.\nset -euo pipefail\nCONF=/config/qBittorrent/qBittorrent.conf\nUSER='${setting:username}'\nPASS=$(cat /run/secrets/password)\nmkdir -p /config/qBittorrent\nHASH=$(python3 - \"$PASS\" <<'PY'\nimport sys, os, base64, hashlib\npw = sys.argv[1].encode(); salt = os.urandom(16)\ndk = hashlib.pbkdf2_hmac(\"sha512\", pw, salt, 100000, dklen=64)\nprint(\"@ByteArray(\" + base64.b64encode(salt).decode() + \":\" + base64.b64encode(dk).decode() + \")\")\nPY\n)\ntouch \"$CONF\"\ngrep -q '^\\[Preferences\\]' \"$CONF\" || printf '\\n[Preferences]\\n' >> \"$CONF\"\nfor kv in \"WebUI\\\\Username=$USER\" \"WebUI\\\\Password_PBKDF2=\\\"$HASH\\\"\"; do\n key=${kv%%=*}\n if grep -q \"^${key//\\\\/\\\\\\\\}=\" \"$CONF\"; then\n awk -v kv=\"$kv\" -v key=\"$key\" 'BEGIN{FS=OFS=\"=\"} $1==key {print kv; next} {print}' \"$CONF\" > \"$CONF.mesh\" && mv \"$CONF.mesh\" \"$CONF\"\n else\n awk -v kv=\"$kv\" '{print} /^\\[Preferences\\]/ && !done {print kv; done=1}' \"$CONF\" > \"$CONF.mesh\" && mv \"$CONF.mesh\" \"$CONF\"\n fi\ndone\necho \"[mesh] qBittorrent WebUI login set for $USER from the vault's credential\"\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -82,14 +97,18 @@
|
||||
},
|
||||
"volumes": [
|
||||
"${dir:config}:/config",
|
||||
"${access:downloads}:/downloads"
|
||||
"${access:downloads}:/downloads",
|
||||
"${dir:mesh-init}:/custom-cont-init.d:ro",
|
||||
"${dir:mesh-state}/password:/run/secrets/password:ro"
|
||||
],
|
||||
"network": "host",
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
],
|
||||
"restart-on": [
|
||||
"identity"
|
||||
"identity",
|
||||
"needs-password",
|
||||
"webui-login-init"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -126,7 +145,12 @@
|
||||
}
|
||||
],
|
||||
"provides": [
|
||||
"qbittorrent-api"
|
||||
{
|
||||
"name": "qbittorrent-api",
|
||||
"credential": {
|
||||
"own": "password"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
"qbittorrent-api": {
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "radarr-api",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"own": "api-key"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
@@ -23,7 +26,11 @@
|
||||
],
|
||||
"consumes": [],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker"
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"api-key": {
|
||||
"path": "${dir:mesh-state}/api-key",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
@@ -72,6 +79,18 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "mesh-init",
|
||||
"type": "directory",
|
||||
"mode": "0755"
|
||||
},
|
||||
{
|
||||
"id": "api-key-init",
|
||||
"type": "file",
|
||||
"path": "${dir:mesh-init}/10-mesh-api-key.sh",
|
||||
"mode": "0755",
|
||||
"content": "#!/bin/bash\n# Written by the mesh (ADR 0158): this module's one credential is the vault's, shared with every\n# consumer; the file is applied here, before the service starts, on every start.\nset -euo pipefail\nCONF=/config/config.xml\nKEY=$(cat /run/secrets/api-key)\nif [ -s \"$CONF\" ] && grep -q '<ApiKey>' \"$CONF\"; then\n sed -i -E \"s#<ApiKey>[^<]*</ApiKey>#<ApiKey>$KEY</ApiKey>#\" \"$CONF\"\nelif [ -s \"$CONF\" ]; then\n sed -i -E \"s#</Config># <ApiKey>$KEY</ApiKey>\\n</Config>#\" \"$CONF\"\nelse\n printf '<Config>\\n <ApiKey>%s</ApiKey>\\n</Config>\\n' \"$KEY\" > \"$CONF\"\nfi\necho \"[mesh] API key set from the vault's credential\"\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -86,13 +105,17 @@
|
||||
"volumes": [
|
||||
"${dir:config}:/config",
|
||||
"${access:movies}:/movies",
|
||||
"${access:downloads}:/downloads"
|
||||
"${access:downloads}:/downloads",
|
||||
"${dir:mesh-init}:/custom-cont-init.d:ro",
|
||||
"${dir:mesh-state}/api-key:/run/secrets/api-key:ro"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
],
|
||||
"restart-on": [
|
||||
"identity"
|
||||
"identity",
|
||||
"needs-api-key",
|
||||
"api-key-init"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "sonarr-api",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"own": "api-key"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
@@ -23,7 +26,11 @@
|
||||
],
|
||||
"consumes": [],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker"
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"api-key": {
|
||||
"path": "${dir:mesh-state}/api-key",
|
||||
"taken": "at-start"
|
||||
}
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
@@ -77,6 +84,18 @@
|
||||
"mode": "0644",
|
||||
"content": "# The identity this module's process runs as on THIS machine: the owner of its\n# data here, which the definition may not know (novox/hq ADR 0112, issue 153). Set puid and\n# pgid on the assignment \u2014 the mesh-wide layer carries the image's default, a node's its own.\nPUID=${setting:puid}\nPGID=${setting:pgid}\n"
|
||||
},
|
||||
{
|
||||
"id": "mesh-init",
|
||||
"type": "directory",
|
||||
"mode": "0755"
|
||||
},
|
||||
{
|
||||
"id": "api-key-init",
|
||||
"type": "file",
|
||||
"path": "${dir:mesh-init}/10-mesh-api-key.sh",
|
||||
"mode": "0755",
|
||||
"content": "#!/bin/bash\n# Written by the mesh (ADR 0158): this module's one credential is the vault's, shared with every\n# consumer; the file is applied here, before the service starts, on every start.\nset -euo pipefail\nCONF=/config/config.xml\nKEY=$(cat /run/secrets/api-key)\nif [ -s \"$CONF\" ] && grep -q '<ApiKey>' \"$CONF\"; then\n sed -i -E \"s#<ApiKey>[^<]*</ApiKey>#<ApiKey>$KEY</ApiKey>#\" \"$CONF\"\nelif [ -s \"$CONF\" ]; then\n sed -i -E \"s#</Config># <ApiKey>$KEY</ApiKey>\\n</Config>#\" \"$CONF\"\nelse\n printf '<Config>\\n <ApiKey>%s</ApiKey>\\n</Config>\\n' \"$KEY\" > \"$CONF\"\nfi\necho \"[mesh] API key set from the vault's credential\"\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -92,13 +111,17 @@
|
||||
"${dir:config}:/config",
|
||||
"${access:series}:/series",
|
||||
"${access:anime}:/anime",
|
||||
"${access:downloads}:/downloads"
|
||||
"${access:downloads}:/downloads",
|
||||
"${dir:mesh-init}:/custom-cont-init.d:ro",
|
||||
"${dir:mesh-state}/api-key:/run/secrets/api-key:ro"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/identity.env"
|
||||
],
|
||||
"restart-on": [
|
||||
"identity"
|
||||
"identity",
|
||||
"needs-api-key",
|
||||
"api-key-init"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user