drop restic repo encryption; rely on TLS + append-only + LUKS
User credentials now serve HTTP basic auth only. Repos init with --insecure-no-password. Removes: - RESTIC_PASSWORD env in client subprocess - Per-repo password coordination story - Multi-key restic setup (user key + operator-master key) - Two-password recovery edge cases Operator-side prune now runs over the filesystem path (-r /srv/.../<user>/) which bypasses rest-server's HTTP-layer append-only enforcement. No password needed at all. Protection model stays: - TLS in transit (reverse proxy) - HTTP basic per-user (htpasswd) for read/write authorization - --private-repos for per-user URL isolation - --append-only for client-side delete protection - LUKS / disk-level for at-rest encryption (operator's responsibility) Verified end-to-end on john: pull → push → restore round-trip works, DELETE on bogus snapshot still returns 403 (append-only intact), operator can read repo via filesystem path (prune-mode access works). 33 pytest still green.
This commit is contained in:
+20
-9
@@ -1,8 +1,17 @@
|
||||
"""pull + push entry points.
|
||||
|
||||
Both subprocess restic against ``rest:<scheme>://<id>:<password>@<host>/<id>/``
|
||||
where the same password is the HTTP basic credential and the repo
|
||||
encryption key. cloud-svc provisions one password covering both.
|
||||
where the password is HTTP basic auth ONLY. Restic repos are initialised with
|
||||
``--insecure-no-password`` so no encryption-at-rest password exists; protection
|
||||
relies on:
|
||||
|
||||
1. TLS in transit at the reverse proxy
|
||||
2. ``--private-repos`` + htpasswd per user at restic-rest-server
|
||||
3. ``--append-only`` to prevent client-side deletion
|
||||
4. Disk-level encryption (LUKS) on the host
|
||||
|
||||
Defense-in-depth via repo encryption was dropped because the threat model
|
||||
(homelab, operator-trusted) doesn't justify the password-coordination cost.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -25,12 +34,12 @@ def pull(args: Args) -> int:
|
||||
discord_id, password = read_credentials(args.token_file)
|
||||
binary = restic.resolve_binary(args)
|
||||
repo = _restic_repo(args.url, discord_id, password)
|
||||
env = _restic_env(password)
|
||||
env = _restic_env()
|
||||
|
||||
# Check whether any snapshots exist
|
||||
code, out = restic.run(
|
||||
binary,
|
||||
["-r", repo, "snapshots", "--json", "--latest", "1"],
|
||||
["-r", repo, "--insecure-no-password", "snapshots", "--json", "--latest", "1"],
|
||||
env=env,
|
||||
)
|
||||
if code != 0:
|
||||
@@ -53,7 +62,8 @@ def pull(args: Args) -> int:
|
||||
code, _ = restic.run(
|
||||
binary,
|
||||
[
|
||||
"-r", repo, "restore", "latest",
|
||||
"-r", repo, "--insecure-no-password",
|
||||
"restore", "latest",
|
||||
"--target", str(args.pack_folder),
|
||||
"--exclude-file", str(exclude_from),
|
||||
],
|
||||
@@ -71,7 +81,7 @@ def push(args: Args) -> int:
|
||||
discord_id, password = read_credentials(args.token_file)
|
||||
binary = restic.resolve_binary(args)
|
||||
repo = _restic_repo(args.url, discord_id, password)
|
||||
env = _restic_env(password)
|
||||
env = _restic_env()
|
||||
|
||||
scope = scopemod.load(args.pack_folder)
|
||||
files_from, exclude_from = scopemod.materialize_for_restic(args.pack_folder, scope)
|
||||
@@ -79,7 +89,8 @@ def push(args: Args) -> int:
|
||||
code, _ = restic.run(
|
||||
binary,
|
||||
[
|
||||
"-r", repo, "backup",
|
||||
"-r", repo, "--insecure-no-password",
|
||||
"backup",
|
||||
"--files-from", str(files_from),
|
||||
"--exclude-file", str(exclude_from),
|
||||
"--host", "cloud-sync",
|
||||
@@ -122,8 +133,8 @@ def _restic_repo(base_url: str, discord_id: str, password: str) -> str:
|
||||
return f"rest:{scheme}{u}:{p}@{host_and_path}/{discord_id}/"
|
||||
|
||||
|
||||
def _restic_env(password: str) -> dict[str, str]:
|
||||
def _restic_env() -> dict[str, str]:
|
||||
return {
|
||||
"RESTIC_PASSWORD": password,
|
||||
# No RESTIC_PASSWORD — repos use --insecure-no-password.
|
||||
"RESTIC_PROGRESS_FPS": "0",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user