Skip to content

connections: folder default credentials for entries without their own - #269

Closed
jseifeddine wants to merge 1 commit into
sol1:mainfrom
jseifeddine:feat/folder-default-credentials
Closed

jseifeddine wants to merge 1 commit into
sol1:mainfrom
jseifeddine:feat/folder-default-credentials

Conversation

@jseifeddine

@jseifeddine jseifeddine commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Based on current main on its own: one commit, nothing from any other open PR. Rebased over #252's table wrap rules (adjacent CSS in connections.html, no functional change).

Part 2/3 of #253.

What it does

A folder can lend a username / password / private key / domain per session type to entries that have no password or private key of their own, so an entry created without secrets (a NetBox webhook, a bulk import) connects the moment it exists. The defaults live at <folder>/.defaults beside .config, are reserved like it (never listed as an entry, not a valid entry name) and are removed with the folder.

  • GET/PUT/DELETE /api/addressbook/folders/:scope/:folder/defaults (admin): secrets are write-only, changes are audited as update_folder_defaults / delete_folder_defaults.
  • The folder dialog in Connections gains a Default credentials section.
  • Listings report covered entries as has_credentials: true with inherited_credentials: true; the table shows a [folder] marker.
  • An entry's own credentials always win; an entry set to prompt_credentials still prompts.
  • Subfolders without their own .defaults take their nearest ancestor's, per type, bounded by inherit_from_parent (below).

Review changes

How each point of the review is handled:

  1. Inheritance stops at inherit_from_parent: false. The walk (resolve_effective_defaults in src/vault.rs) applies a folder's own .defaults, then continues to the parent only while the folder just visited has inherit_from_parent: true, the same rule resolve_folder_access uses. A key set on a parent never reaches a subfolder isolated with that flag, so it cannot be used in a subfolder shared with someone else through allowed_users; the isolated folder's own .defaults still apply to its entries. A folder with no .config, or one written before the flag existed, counts as not inheriting, exactly as the access check treats it. Tested in effective_defaults_stop_at_a_folder_that_does_not_inherit.
  2. vault-migrate copies .defaults. src/migrate.rs reads each folder's .defaults after its .config and writes it to the destination (the dry run lists it as [defaults] <folder>); the module doc and docs/migration.md say so. Talks to two live Vaults, so no unit test; it is the same shape as the .config copy beside it.
  3. /api/connect applies the defaults. Both connect paths now go through one helper, lend_folder_defaults in src/api.rs: ab_connect_entry (Connections page) and quick_connect (links). The helper is generic over the same DefaultsSource the walk uses, so lend_folder_defaults_fills_a_bare_entry_and_respects_the_boundary exercises it directly, including the isolated-subfolder case and the prompt case.
  4. Docs. New section Folder default credentials in docs/credential-variables.md: where .defaults lives, how it applies, the inheritance rule and the inherit_from_parent boundary, the migrate behaviour, and Web entries: the password is visible to the user, which says outright that a web entry using a default password has it typed into a page the user can read. Cross-references from docs/roles-and-access-control.md (Inheritance), docs/api.md (quick connect and the defaults endpoints) and docs/migration.md; the folder dialog hint says the same in one line.

And the PR is rebased onto main on its own, as asked.

Tests

  • folder_defaults_fill_only_entries_without_secrets (now also: an entry set to prompt takes nothing)
  • entry_info_marks_inherited_credentials
  • effective_defaults_merge_nearest_first_through_inheriting_folders
  • effective_defaults_stop_at_a_folder_that_does_not_inherit
  • effective_defaults_propagate_read_errors
  • lend_folder_defaults_fills_a_bare_entry_and_respects_the_boundary
  • lend_folder_defaults_leaves_the_entry_alone_when_vault_fails

Manual, earlier revision: set an SSH default on a tenant folder, create an entry with no password: it shows Connect immediately and connects with the folder's key; a subfolder entry inherits; GET never returns the secret.

@davekempe

Copy link
Copy Markdown
Member

I like the idea, a few things before it can go in:

  • Inheritance walks every ancestor, including through folders with inherit_from_parent: false. That flag is how a folder gets isolated for access, so a key set on a parent shouldn't flow past it. Otherwise it's usable in a subfolder shared with someone else, e.g. with allowed_users.
  • rustguac vault-migrate copies entries and .config but not .defaults, so a DR split silently drops them.
  • /api/connect (quick connect links) doesn't apply the defaults, so the same entry works from Connections but not from a link.
  • Worth a line in the docs: a web entry using a default password gets it typed into a page the user can see.

Also, since the PRs are stacked, could you rebase this onto main on its own so it can be taken separately?

@jseifeddine

Copy link
Copy Markdown
Contributor Author

Thanks Dave, all four addressed and the PR is now on its own on main (one commit, nothing from #268). The defaults walk now follows the same rule as the access check: it only continues past a folder whose config has inherit_from_parent: true, so a key set on a parent never reaches an isolated subfolder, while that folder's own .defaults still apply to its entries; there's a unit test for exactly that boundary. vault-migrate copies .defaults beside .config (the dry run lists them). Both connect paths, the Connections endpoint and /api/connect, now go through a single lend_folder_defaults helper, with a direct test on it. The docs have a new "Folder default credentials" section in credential-variables.md, including a plain warning that a web entry using a default password has it typed into a page the user can read.

The CI audit failure on this branch is the new quinn-proto advisories, not this change; #283 bumps the lockfile and the run goes green once that is in.

@jseifeddine
jseifeddine marked this pull request as ready for review October 13, 2026 03:16
@jseifeddine
jseifeddine force-pushed the feat/folder-default-credentials branch from 195e15c to 55b8497 Compare October 13, 2026 07:04
A folder can lend a username, password, private key and domain per session
type to entries that have no password or private key of their own, so an
entry created without secrets (a NetBox webhook, a bulk import) connects the
moment it exists. The defaults live at `<folder>/.defaults` beside
`.config`, are reserved like it (never listed, not a valid entry name) and
are removed with the folder. `GET/PUT/DELETE .../defaults` manage them
(secrets write-only, audited as update_folder_defaults /
delete_folder_defaults) and the folder dialog gains a Default credentials
section. Listings report such entries as `has_credentials: true` with
`inherited_credentials: true`. An entry's own credentials always win and an
entry set to prompt still prompts.

A subfolder without its own `.defaults` takes its nearest ancestor's, per
type, but the walk follows the access rule: it only continues past a folder
whose `.config` has `inherit_from_parent: true`. That flag is how a folder
is isolated for access, so a key set on a parent must not reach a subfolder
shared with someone else through `allowed_users`. The isolated folder's own
`.defaults` still apply to its entries. A folder with no `.config`, or one
written before the flag existed, counts as not inheriting, exactly as
`resolve_folder_access` treats it. The walk is `resolve_effective_defaults`
over a small `DefaultsSource` trait so it is tested without a Vault.

Both connect paths resolve defaults through one helper,
`lend_folder_defaults`: the Connections endpoint
(`POST .../entries/:entry/connect`) and `/api/connect` quick links, so an
entry that works from the page works from a link. `rustguac vault-migrate`
copies each folder's `.defaults` alongside its `.config`, so a DR split keeps
them (the dry run lists them as `[defaults]`).

Docs cover the storage layout, the inheritance rule and its boundary, the
migrate behaviour, and the warning that a web entry using a default
password has that password typed into a page the user can read.

Part 2/3 of sol1#253.
@jseifeddine
jseifeddine force-pushed the feat/folder-default-credentials branch from 55b8497 to cc01469 Compare October 16, 2026 11:29
@davekempe

Copy link
Copy Markdown
Member

Merged into main as ccd2bad thanks Jad. One thing still open from my first comment, fixed our side in b7596be: access is a union, so a subfolder that inherits but also has its own allowed_groups/allowed_users admits people the parent doesn't, and the walk only stopped at inherit_from_parent: false. A contractor added to corp/partner via allowed_users could connect with corp's key. Defaults now only flow into a subfolder that inherits and grants nobody of its own. Same commit: prompt entries no longer show as [folder], PUT defaults on a missing folder is a 404, RDP domain field in the dialog, and a docs line on $variables in defaults. Live tested on our canary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants