Backing Up Key Shares
This feature is currently only supported for Azure deployments, and will become available for other deployments in the future.
Every share generated and stored inside the Vertex can be exported and backed up for safekeeping. For added flexibility, at startup the Vertex can be configured to either export the shares "raw" or alternatively to encrypt them using a configured key.
Configuring Backup Settings for the Vertex
When deploying the Vertex using the provided Terraform module, you can configure the Vertex to encrypt all exported shares using a symmetric secret key. The same key will be used when importing an encrypted share back into the Vertex. Note that the key must be provided to the Vertex at startup, and is not stored in the Vertex DB itself.
For Azure, the key is stored in an Azure Key Vault as a Secret.
If you want to enable the encrypted backup feature, you need to provide the following Terraform variables:
server_share_backup_encryption_secret_name
- the name of the secret holding the encryption key for the server share backup.server_share_backup_encryption_secret_vault_name
- the name of the key vault where the encryption key secret exists in.server_share_backup_encryption_secret_rg_name
- the name of the resource group that the key vault is in.
Exporting a Key Share
Exporting a key share can be done using the export-key
endpoint:
curl -L -X GET 'https://<YOUR_VERTEX>/ecdsa/backup/export-key-share/<key_id>' \
-H 'Accept: application/json' \
-H 'Authorization <USER_API_KEY>'
This operation takes a key share (indicated by the key_id
parameter) and exports it, either in raw or encrypted form using the configured key.
Notice that the result will include the export_type
which will indicate if the export is encrypted or not, and will be needed during the import process.
For more information about generating keys you can look at the Generating Keys section.
Importing a Key Share
Importing a key share can be done using the import-key
endpoint:
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/backup/import-key-share' \
-H 'Content-Type: application/json' \
-H 'Authorization <USER_API_KEY>' \
-H 'Accept: application/json' \
--data-raw "<EXPORTED_KEY_SHARE>"
This operation takes a key share (in raw or encrypted form) and imports it into the Vertex. This will in turn create a new key_id for this share. If you want your user to start using the imported share after, make sure you are using the new key_id. This operation does not delete the old original share.
Importing a Key Share for Recovery
If you set up a backup mechanism through which you have access to an exported share and want to use it for recovery purposes, you can import the share using the same process as above. The following snippet assumes the following scenario:
- A client and a server, each holding a share.
- Every time a client generates a share, it also saves an encrypted exported backup of the server's share (using the
export-key
endpoint). - The potential disaster: the server and all of its data (shares included) are completely lost. A new server is instantiated, configured with the same encryption key as before, and communicating under the same domain.
Given this scenario, the client code below will seamlessly recover the share from the exported backup and continue to sign messages as before:
async function main(): Promise<EcdsaSignature> {
// Given we've already generated a key and have our exported share as `exported_share`.
try {
// Attempt to sign the message with the original key.
// `sign` is a function that signs a message using the given `key_id` and throws a native `Response` object in case of an error.
const signature = await sign({ key_id: user_key_id, message: msg });
return signature;
} catch (error: unknown) {
if (error instanceof Response) {
const error_body = await error.json();
// `key_id_not_exists` is a custom error type that indicates the key share is not found.
if (error_body.err_type === 'key_id_not_exists') {
// We will import the exported share and sign the message with the newly created key share.
const import_result = await import_key_share(exported_share);
const signature = await sign({
key_id: import_result.key_id,
message: msg,
});
return signature;
}
} else {
throw error;
}
}
}
In the example above we attempt to sign a message with the original key share. If the key share is not found, we import the exported share and sign the message with the newly created key share.
Note the special error the Vertex will throw when the key share is not found - key_id_not_exists
. In this case we can attempt to recover our exported share and reuse it.