Skip to content

fix(management): refuse access key import unless allow_credential_import is true - #840

Open
LeeroyHannigan wants to merge 2 commits into
mainfrom
fix/credential-import-off-by-default
Open

LeeroyHannigan wants to merge 2 commits into
mainfrom
fix/credential-import-off-by-default

Conversation

@LeeroyHannigan

Copy link
Copy Markdown
Collaborator

What

An access key import stores an access key ID and a secret that the caller chooses. After this change, the management API route POST /management/accounts/{id}/users/{name}/access-keys/import imports a key only when the runtime setting allow_credential_import is true. The extenddb manage import-access-key command calls this route.

  • When the catalog has no row for the setting, the server refuses the import with HTTP 403. Before this change, the server allowed the import when the row was missing. No release writes the row, so each deployment that did not set the value accepted imports. The console settings page already shows false as the default.
  • false and any other stored value also refuse the import. The settings CLI and the settings API accept only true or false for this key.
  • The refusal message does not change: Credential import is disabled (allow_credential_import = false). A store error still returns HTTP 500.
  • The setting does not affect keys that a deployment imported before the upgrade. A dev-mode server seeds its credentials through the store, not through this route, so the setting does not apply to them either.
  • The check moves into credential_import_gate, which takes the settings store, so a unit test can give it each case.

Test harness:

  • devtools/run-tests sets allow_credential_import to true with the other runtime settings. It does this one time, before any suite starts, so no test changes the setting while xdist workers run. CI runs the pytest, --comprehensive and Rust integration suites through this script on all four backends.
  • tests/cli/test-cli-comprehensive.sh, and the manual test workflows in AGENTS.md and the developer test guide, set the value before they import a key.

Docs: the settings tables in docs/differences-from-dynamodb.md and the admin guide, docs/getting-started.md, the deployment checklist and the troubleshooting guide give the new default. The upgrade manual has a v0.1.15 entry.

Why

Each deployment that never set the value accepted imported keys, with an ID and a secret that the caller chose. With import off by default, only a deployment that turns import on accepts them. The server default now also agrees with the console settings page.

Testing done

  • cargo test -p extenddb-server --lib management: 91 passed. This includes 5 new tests for the gate: no row, false, true, other values (TRUE, True, 1, yes, an empty string and true) and a store error.

  • cargo fmt --check and cargo clippy -p extenddb-server --all-targets -- -D warnings pass.

  • New tests/test_allow_credential_import_sqlite.py runs init --backend sqlite in a temporary directory and serves that deployment on a free port on 127.0.0.1. So it does not change the settings of the shared test server. On the new catalog, which has no row for the setting, it does these steps:

    • An import gets HTTP 403 with the message above, and the key does not list.
    • extenddb settings set allow_credential_import true runs in the deployment's directory while the server runs. The same import then gets HTTP 201, and the key lists.
    • After the value changes to false, a second import gets HTTP 403, and the first key still lists.

    It passed 6 times. The run-integration-sqlite job runs it, and the jobs that build other backends skip it.

  • Negative controls for the new test: I deleted the gate call, moved it below the store write, and let a missing row allow the import. Each time, the test failed.

  • devtools/run-tests --filter TestAccessKeys on a new SQLite catalog: with the harness from main, test_import_access_key fails with the 403. With the harness from this branch, all 5 tests pass.

  • Merged with fix(storage-mongodb): store each access key ID once #823, which adds 3 tests that import keys: the 8 tests in TestAccessKeys and TestAccessKeyIdIsStoredOnce pass.

  • I did not run tests/cli/test-cli-comprehensive.sh, because it needs PostgreSQL, the AWS CLI and jq. I ran its two new commands by hand.

Checklist

  • I have read CONTRIBUTING.md
  • All tests pass (cargo test --workspace)
  • Code is formatted (cargo fmt --check)
  • Clippy is clean (cargo clippy -- -W clippy::pedantic)
  • I have added or updated tests for new functionality
  • I have updated documentation if behavior changed
  • Breaking changes are noted below (if any)
  • If this changes the wire protocol, Storage trait, auth model, on-disk
    format, or public CLI surface, an RFC has been accepted or is linked
    below. Otherwise, an ADR captures the decision (link below).

ADR / RFC: n/a. A missing row for one runtime setting now means false, the default that the console already shows. The name of the setting, its values and the route do not change.

Breaking changes

A deployment that imports access keys and never set allow_credential_import gets HTTP 403 from each import after the upgrade. Before the upgrade, run extenddb settings --config extenddb.toml set allow_credential_import true on that deployment. The current release accepts the command, and the server reads the value on each import, so a restart is not necessary.


By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.

…ort is true

An access key import through the management API, and the
import-access-key command that calls it, now runs only when the runtime
setting allow_credential_import is true. When the catalog has no row
for the setting, the server refuses the import with 403, as it does
for false. Before this change the server allowed the import when the
row was missing. No release writes the row, so every deployment that
never set the setting accepted imports. The console settings page
already listed the default as false.

An import stores an access key ID and secret that the caller chooses.
With the feature off by default, only deployments that turn it on
accept caller-chosen keys. The setting does not affect keys imported
earlier, or the credentials a dev-mode server seeds at startup.

The check moves into credential_import_gate. Unit tests cover no row,
false, true, other values and a store error. A store error still
answers 500, and the refusal message does not change.

devtools/run-tests sets allow_credential_import to true with the other
runtime settings, before any suite starts. The integration jobs that
import keys keep passing, and no test changes the setting while xdist
workers run. tests/cli/test-cli-comprehensive.sh enables it before its
import step, and the manual test workflows in AGENTS.md and the
developer test guide set it before pytest runs.

The settings tables, getting-started.md, the admin and deployment
guides and the troubleshooting guide state the new default. The upgrade
manual tells a deployment that imports keys to run
extenddb settings --config extenddb.toml set allow_credential_import true
before it upgrades.

Signed-off-by: Lee Hannigan <29015211+LeeroyHannigan@users.noreply.github.com>
…port row refuses an access key import

The unit tests for credential_import_gate call the function directly,
and every integration suite runs with allow_credential_import set to
true, because devtools/run-tests stores it before the suites start.
Without this test, no test fails if import_access_key stops calling the
gate or calls it after the store write.

tests/test_allow_credential_import_sqlite.py runs
extenddb init --backend sqlite in a temporary directory and serves that
deployment on a free port on 127.0.0.1. Its catalog has no
allow_credential_import row. As the admin that init created, the test
creates an account and a user and posts an access key import for the
user. The server must answer 403 with the body "Credential import is
disabled (allow_credential_import = false)", and the user's key list
must not show the key. The test then runs
extenddb settings --config extenddb.toml set allow_credential_import true
while the server runs, posts the same import, and expects 201 and the
key in the list. After it sets the value to false, a second import gets
403 and the first key still lists.

The test uses its own deployment so that it does not change the shared
server's settings while other xdist workers import keys. It stops the
server and deletes the directory on teardown, also when an assertion
fails. init writes its TLS certificate and key under ~/.extenddb, so
the extenddb commands run with HOME set inside that directory.

The module skips unless extenddb version reports the SQLite backend. In
CI the run-integration-sqlite job runs it. The PostgreSQL, MongoDB and
Cassandra jobs build their binaries with other backends, so it skips
there.

Signed-off-by: Lee Hannigan <29015211+LeeroyHannigan@users.noreply.github.com>

This branch has not been deployed

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

Labels

v1 Needed for the 1.0 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant