Cannot rotate organization recovery private key with new domain

Hello again! I’m trying to rotate the organization’s recovery private key because it’s too old. Still, it gives me an error because I changed the server domain when I migrated from my previous source installation to a Docker instance.

I can generate a new recovery key using the Passbolt web interface, it downloads a copy and everything seems fine unless I try to save the changes. Then it asks me for my previous organization key and when I complete the form and send it, it gives me the following error:

How can I rotate the organization recovery private key with my new domain?

Hello @Termindiego25 !

During the rotation of the organisation key, as you noticed, we do a check of the domain for security reasons.
Unfortunately, there is no way to force the rotation in such case.

It depends on your constraints. What you could do is to remove the organisation recovery key save and recreate a new one.
However, doing so, every users who shared their key for the account recovery will need to resend their key again.

If there is a problem removing the ORK from the UI, you could log on your server and with the CLI you could run a command such as
./bin/cake passbolt truncate_account_recovery_tables
which clean everything related to the account recovery. It resets everything and your instance will behave like there wasn’t any account recovery configured. So you can set a new key but, it implies as well that users send back their private key.

If it’s not a suitable scenario for you, then you will need to do what the browser extension does by yourself and changing the domain name in the data. It’s quite tedious to do by hand honestly.

Hello @Steph and thank you for answering.
I understand the security check and it makes sense. As you mentioned, the easiest way is to delete the account recovery settings and set it up again.

But since this is a scenario that could happen again to someone in the future, would you agree to explain how to change the domain name in the data and keep it documented here to allow them to choose what to do?

Why not, in a nutshell, it means to:

  • make sure you have a gpg client you could use on a machine before proceeding
  • have access to the private ORK with its passphrase
  • read the database and get all open pgp message that are concerned
  • decrypt the PGP messages
  • read the result as JSON
  • change the domain in the JSON data
  • encrypt the message again
  • save the messages back on the database

It’s something that would be easier to run as a script somehow IMO.
Also, I’m thinking to create an internal ticket to propose to think about a solution for such a case. I don’t know what solution will be done and when.

If you can, I think creating the ticket would be a good solution for the future.
For now, as a sort of workaround, I would try to follow all those steps and finally rotate the key.
Any help will be appreciated hahahaha

I created the ticket PB-33626 for information. It’s an investigation ticket as we need first to define an approach for this issue before implementing any solution.

1 Like

Okay, I managed to get it to work. These are the steps to follow:

  1. Backup your database. VERY IMPORTANT
  2. Locate the table account_recovery_private_key_passwords
  3. Find the current row and copy the content of the filed data
  4. Save the content in a file (we we’ll call it recovery_data) and replace every \n with a new line
  5. Import your organization private key (we will call it org_private) with gpg --import org_private
  6. Decrypt recovery_data with gpg --output recovery_data-dec --decrypt recovery_data
  7. Open recovery_data-dec and change the domain in the field domain
  8. Encrypt again with gpg --output recovery_data-enc --encrypt --armor --recipient $email_of_the_org_private_key recovery_data-dec
  9. Replace every new line with \n
  10. Replace the content of the data field in the database where we extracted our recovery_data
  11. Try again to rotate your organization private key

This should work, if you have any problems just ask!

1 Like

Nice one ! GG on that, that was not straight forward to accomplish.

1 Like

I remembered a previous post where Remy gave some tips on how to decrypt PGP messages and following the URL provided with some examples, it was easier than expected
https://community.passbolt.com/t/pgp-key-decryption/6545

You can also find more examples here, just in case you want to learn more about PGP encrypting and decrypting:
https://pranabdas.github.io/linux/pgp/

Hey, we had a similar issue after migrating to a new domain name and updating to v5. I managed to get this working with @Termindiego25 's workflow.

I had to make this change on all the users that were created on the old domain rather than “the current row”. I am not well versed in linux, bash etc but with the help of ChatGPT managed to make a script to replace the domain on all the users which I will share below in case it helps anyone. The jist as @Termindiego25 says is to:

  1. get the ‘data’ column from account_recovery_private_key_passwords,
  2. format the data to replace \n with an actual line feed
  3. decrypt the data
  4. modify the json to update ‘domain’ to your new domain
  5. re-encrypt the data
  6. save the data back to the database

The script assumes you have imported your private key by running:
gpg --import private.key
have your key thumbprint found by:
gpg -k
ensure the certificate is trusted:
gpg --edit-key thumbprint
gpg > trust

it also assumes you have jq installed:
sudo apt install jq

Paste the thumbprint at the top of the script, and enter your new domain name. Please use with caution, I have modified the script to remove our sensitive information and I have not tested it since modifying so there may be some typos etc. We ran it on Passbolt Pro v5 on Ubuntu 24.04.2 LTS.

#!/bin/bash

# === Configuration ===
domain="YourNew.PassboltDomain.com"
thumbprint="ThumbPrintOfYourOrganisationalKey"

# Ensure required tools are available
command -v gpg >/dev/null || { echo "gpg is not installed"; exit 1; }
command -v jq >/dev/null || { echo "jq is not installed"; exit 1; }
command -v mysql >/dev/null || { echo "mysql is not installed"; exit 1; }

# Set the GPG_TTY for GPG to interact with the terminal
export GPG_TTY=$(tty)

# Prompt for GPG passphrase (used for decrypting)
read -s -p "Enter passphrase: " passphrase
echo

# Fetch and process data
sudo mysql -u root -e 'USE passboltdb; SELECT data, id FROM account_recovery_private_key_passwords;' --skip-column-names | \
while IFS=$'\t' read -r data id; do
    # Skip header if accidentally included
    [[ "$data" == "data" ]] && continue

    # Convert literal '\n' to real newlines
    formatted=$(echo -e "${data//\\n/$'\n'}")

    # Decrypt using GPG
    decrypt=$(echo "$formatted" | gpg --decrypt --batch --yes --no-tty --passphrase "$passphrase" 2>/dev/null)
    if [[ -z "$decrypt" ]]; then
        echo "Failed to decrypt data for ID $id"
        continue
    fi

    # Update the domain field
    updated_json=$(echo "$decrypt" | jq -c ".domain = \"$domain\"")

    # Re-encrypt the updated JSON
    encrypted=$(echo "$updated_json" | gpg --armor --encrypt --batch --yes --no-tty -r "$thumbprint" 2>/dev/null)
    if [[ -z "$encrypted" ]]; then
        echo "Encryption failed for ID $id"
        continue
    fi

    # Format encrypted data (replace line breaks with literal \n)
    encrypted_data=$(echo "$encrypted" | sed ':a;N;$!ba;s/\n/\\n/g')

    # Write back to database
    sudo mysql -u root -e "USE passboltdb; UPDATE account_recovery_private_key_passwords SET data='$encrypted_data' WHERE id='$id';"

    # Output result
    echo "Updated ID $id"
    echo "Updated Domain: $domain"
    echo "-----------------------------"
done
1 Like