84 lines
4.8 KiB
Markdown
84 lines
4.8 KiB
Markdown
# 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.
|