Add first-run admin setup and independent password and API token rotation

This commit is contained in:
Mikei386
2026-09-28 15:02:41 +02:00
parent e86e540ae4
commit 9f3a13e45f
20 changed files with 651 additions and 76 deletions
+12 -2
View File
@@ -17,6 +17,7 @@ import time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from auth import normalize, validate_record
from network.config import parse_config, wireguard_text
from network.policy import Policy
@@ -87,7 +88,7 @@ class Proxy(BaseHTTPRequestHandler):
if not 0 <= length <= 32768 or len(self.path)>2048:
raise ValueError()
body = self.rfile.read(length) if length else None
headers = {name: self.headers[name] for name in ('Host', 'Origin', 'Content-Type', 'Cookie', 'X-Athena-Deck') if name in self.headers}
headers = {name: self.headers[name] for name in ('Host', 'Origin', 'Content-Type', 'Cookie', 'Authorization', 'X-Athena-Deck') if name in self.headers}
headers.update({'X-Deck-Proxy': PROXY_TOKEN, 'X-Deck-Ingress': self.server.ingress})
conn = http.client.HTTPConnection('127.0.0.1', 8108, timeout=30)
try:
@@ -188,6 +189,15 @@ class Agent:
# Ingress may only be asserted by the web child using the private proxy token.
if not secrets.compare_digest(str(data.get('proxy_token', '')), PROXY_TOKEN):
ingress = 'management'
if action == 'credentials-read':
return {'credentials': validate_record(normalize(json.loads((DATA/'auth.json').read_text())))}
if action == 'credentials-write':
current = validate_record(normalize(json.loads((DATA/'auth.json').read_text())))
if current['revision'] != data.get('expected_revision'):
raise ValueError('Zugangsdaten wurden inzwischen geändert. Bitte erneut anmelden.')
record = validate_record(data.get('credentials'))
save(DATA/'auth.json', record)
return {'saved':True}
if action == 'status':
return self.status(ingress)
if action == 'import':
@@ -260,7 +270,7 @@ def main():
if not auth.exists():
raise SystemExit('Authentication must be provisioned before container startup.')
env = os.environ.copy()
env.update(DECK_PROXY_TOKEN=PROXY_TOKEN, DECK_AUTH_JSON=auth.read_text(), DECK_NETWORK_SOCKET='1', DECK_LOCAL_HARDWARE='1')
env.update(DECK_PROXY_TOKEN=PROXY_TOKEN, DECK_AUTH_RPC='1', DECK_NETWORK_SOCKET='1', DECK_LOCAL_HARDWARE='1')
child = subprocess.Popen([sys.executable, '/app/server.py'], env=env, user=65534, group=65534, extra_groups=[], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
address = json.loads(command('ip', '-j', '-4', 'addr', 'show', 'dev', 'eth0'))[0]['addr_info'][0]['local']
lan = DeviceServer(address, 'eth0', 'lan')