Skip to content

Fix broken secrets-file restore on failed credential rotation#4202

Open
tas50 wants to merge 1 commit into
chef:mainfrom
tas50:fix-csc-rotate-credentials-restore
Open

Fix broken secrets-file restore on failed credential rotation#4202
tas50 wants to merge 1 commit into
chef:mainfrom
tas50:fix-csc-rotate-credentials-restore

Conversation

@tas50

@tas50 tas50 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Problem

restore_secrets_file in src/chef-server-ctl/plugins/rotate_credentials.rb copies in the wrong direction:

def restore_secrets_file(backup_file)
  log("Restoring #{backup_file} to #{secrets_file_path}...")
  FileUtils.cp(secrets_file_path, backup_file)   # live -> backup (wrong)
end

This is the rollback path invoked by rotate-credentials, rotate-all-credentials, and rotate-shared-secrets when credential rotation raises (see the rescue blocks that call restore_secrets_file(backup_file)).

Because the copy goes live secrets file → backup (the same direction as backup_secrets_file), a failed rotation:

  1. Does not roll back — the partially-rotated / broken secrets file is left in place as the live private-chef-secrets.json.
  2. Destroys the only good backup — the pre-rotation copy is overwritten with the broken current secrets, so there is no artifact to recover from either.

The net effect is that a failed credential rotation can leave the Chef Server with unusable credentials and no automated way to recover, which is the opposite of what this rescue path is intended to guarantee.

Fix

Copy backup → live secrets file so the rollback actually restores the pre-rotation state:

FileUtils.cp(backup_file, secrets_file_path)

Tests

The existing rotate_credentials_spec.rb stubbed restore_secrets_file out entirely and only asserted that it was called, so the copy direction was never exercised — which is how the bug went unnoticed. Added a focused regression test that calls the real method with FileUtils.cp mocked and asserts the argument order (backup_file, secrets_file_path).

Note: the chef-server-ctl gem bundle targets Ruby 3.1 and could not be installed in my local environment (Ruby 4.x), so I verified the changed files with ruby -c and am relying on CI to run the rspec suite.

@tas50 tas50 requested review from a team as code owners June 6, 2026 16:20
@netlify

netlify Bot commented Jun 6, 2026

Copy link
Copy Markdown

👷 Deploy Preview for chef-server processing.

Name Link
🔨 Latest commit fff371e
🔍 Latest deploy log https://app.netlify.com/projects/chef-server/deploys/6a244941edbe3d00084c4998

restore_secrets_file copied the live secrets file onto the backup
instead of copying the backup back onto the live secrets file. On a
failed rotation the rollback therefore did nothing useful and also
overwrote the only good backup with the (possibly broken) current
secrets, leaving the server with unusable credentials and no way to
recover them.

Copy backup -> live secrets file so a failed rotation can actually
roll back. Add a regression test; the existing tests stubbed this
method out entirely, so the direction bug was never exercised.

Signed-off-by: Tim Smith <tsmith84@proton.me>
@tas50 tas50 force-pushed the fix-csc-rotate-credentials-restore branch from bce8a71 to fff371e Compare June 6, 2026 16:22
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.

1 participant