Files
framebridge/source/docs/CREDENTIAL-BACKENDS.md
T

4.8 KiB

Protected connection credentials

The existing systemd 256+ backend uses owner-scoped encrypted credentials and systemd-creds decrypt --user. Existing installation records without a backend field retain that behavior. The systemd 255 backend preserves the same user service and uses a separately installed, privileged credential helper. Node startup without a ChatGPT connection does not need a runtime connection key.

Installation and authorization

The package supplies these root-owned files:

  • /usr/lib/framebridge-expanded/bin/framebridge-credential-helper
  • /usr/lib/framebridge-expanded/expanded/framebridge_expanded/credential_helper.py

The launcher executes the fixed system interpreter with -I -S; the helper uses only the standard library and absolute systemd-creds/visudo paths. Merely installing the package does not enable a connection or install a sudoers grant.

On systemd 255, connection setup requires ordinary administrative sudo authorization. It writes host-encrypted ciphertext and principal metadata under /var/lib/framebridge-expanded/credentials, owned by root with private access. It also installs one validated file in /etc/sudoers.d per credential version. That file permits exactly the recorded owner's literal helper decrypt command and fixed profile/cipher digest arguments, with NOSETENV. It does not permit arbitrary systemd-creds commands, paths, shell execution, account selection, provisioning, revocation or unrestricted root execution without authentication. This narrow permission is necessary for unattended reconnection after reboot.

The owner must review this permission change before production setup is activated. Building the package and running synthetic unit tests do not activate the helper, create a host encryption key, alter sudoers or enable a service.

Scope and recovery

The helper derives the caller from sudo's UID, username and primary group; it does not accept a caller-selected UID. Its records bind the UID, username, home identity, profile digest, ciphertext digest and randomized cryptographic name. Only fixed root-owned paths are opened. Symlinks, unexpected hardlinks, writable parents, broad metadata permissions and unrecognized arguments are rejected.

Provisioning keeps the old credential usable until the replacement connection commits. Retired versions remain listed until revocation succeeds. Directory fsync orders durable ciphertext registration before the decrypt grant, and grant revocation before ciphertext removal. Failed output delivery rolls back a new grant. After SIGKILL or power loss, administrative prune reconciles orphan versions even if the owner never received their ciphertext digest. New setup preserves known current versions while pruning orphans; explicit disable prunes all versions for its owner/profile, including when no manifest was committed. This reconciliation also runs after an upgrade to the systemd 256+ backend. Uninstall uses administrative purge-all after the user workers have stopped. Recognized root-owned staging files from interrupted publication are recovered.

Administrative interface (run the installed launcher, never a user checkout):

  • protect PROFILE_SHA256: read a bounded printable synthetic/runtime key from stdin and return only encrypted ciphertext on stdout.
  • decrypt PROFILE_SHA256 CIPHER_SHA256: return the registered owner's key on a pipe; this is the only operation granted passwordless sudo.
  • revoke PROFILE_SHA256 CIPHER_SHA256: idempotently revoke one owner version.
  • prune PROFILE_SHA256 KEEP_DIGESTS: remove other versions for this owner and profile; KEEP_DIGESTS is a comma-separated digest allowlist, or - for none.
  • purge-all: root administrative removal of all helper-owned records/grants.

Security limits

No plaintext key is intentionally stored in an environment variable, command argument, log or disk file. Plaintext exists in process and pipe memory while used; this is not a guarantee against memory inspection, swap, a compromised owner session or root. Both credential backends trust the owner Unix principal.

UID reuse with another username or home is rejected. Recreating exactly the same UID, username and home can recreate the same Unix principal; Linux does not supply an account-generation identity here. Administrators must revoke or purge the grants before deleting/recycling an account, and before changing its identity/home in a way that would prevent ordinary owner cleanup. A randomized credential name is not proof of an account's generation.

The helper backend is not a Wayland capture/input backend and does not remove Python ABI, architecture, libc, PAM, user-systemd, cgroup, sudo or X11 capability requirements. Synthetic tests validate interfaces and failure handling; a support claim additionally requires clean-system installation, real systemd credential operations, boot/lifecycle and feature-specific acceptance tests.