> ## Documentation Index
> Fetch the complete documentation index at: https://cosmos-docs-security-release.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from TMKMS

> Move a validator from the deprecated TMKMS to Cosmos-KMS: translate the config, move or rotate the key, and cut over without double signing.

This guide moves a validator's signing from TMKMS, which is deprecated, to Cosmos-KMS, its successor. The migration has three parts: translate the config, get the key into a Cosmos-KMS backend, and cut over with exactly one signer alive at every moment. For what Cosmos-KMS is and why it replaces TMKMS, see [Cosmos-KMS and remote signing](/sdk/next/kms/remote-signing).

The validator node itself needs no changes: both signers speak the same privval protocol to the same `priv_validator_laddr` listener.

{/* TODO(ERIC): TMKMS's direct YubiHSM, Fortanix, and Ledger integrations do not map one-to-one onto cosmos-kms. A YubiHSM likely moves to the PKCS11 backend, but confirm the path for Ledger and Fortanix. This migration guide should give a path for each prior backend. */}

## Prerequisites

* A validator currently signing through TMKMS, with access to its `tmkms.toml` and state file.
* Cosmos-KMS installed and initialized with `kms init`. [Remote signing tutorial](/sdk/next/kms/tutorial-file-backend) covers installation, which needs [Go](https://go.dev/doc/install) 1.26 or later, [make](https://www.gnu.org/software/make/), and [git](https://git-scm.com/).

## Map the config

TMKMS configuration in `tmkms.toml` translates block for block into `kms.yaml`:

| tmkms.toml                         | kms.yaml                      | Notes                                                                             |
| ---------------------------------- | ----------------------------- | --------------------------------------------------------------------------------- |
| `[[chain]]` `id`                   | `chains[].id`                 | Same value.                                                                       |
| `[[chain]]` `state_file`           | `chains[].state_file`         | See the state migration section before reusing a path.                            |
| `[[chain]]` `key_format`           | none                          | Not needed; Cosmos-KMS has no per-chain serialization config.                     |
| `[[validator]]` `addr`             | `validators[].addr`           | Drop the `<node-id>@` prefix for `tcp://`; keep host and port.                    |
| `[[validator]]` `chain_id`         | `validators[].chain_id`       | Same value.                                                                       |
| `[[validator]]` `secret_key`       | `validators[].identity_key`   | Different format; use the `identity.json` from `kms init` rather than converting. |
| `[[validator]]` `protocol_version` | none                          | Not needed.                                                                       |
| `[[providers.softsign]]`           | `keys[]` with `backend: file` | See the key section.                                                              |
| `[[providers.yubihsm]]`            | no direct equivalent          | See the key section; Cosmos-KMS supports PKCS#11, not YubiHSM's native interface. |
| `[[providers.ledgertm]]`           | no equivalent                 | Ledger-held consensus keys have no Cosmos-KMS backend.                            |

## Move the key

The path depends on where TMKMS holds the key today.

### From softsign

The softsign backend keeps the key in a file, so this is a format question: whether the Cosmos-KMS file backend reads a tmkms softsign key directly, or the key needs conversion.

### From YubiHSM or another HSM

Keys generated inside an HSM are typically non-exportable, which is the point of an HSM. A key that cannot leave the device cannot be moved into AWS KMS or another token. For those keys, migrate by rotation instead: generate a new key in the target custodian and rotate the validator to it on chain, which retires the TMKMS-held key entirely. See [Rotate a consensus key, Staking](/sdk/next/keys/rotate-validator-key).

## Migrate the double-sign state

TMKMS and Cosmos-KMS both track the last signed height, round, and step per chain, and the protection only works if the new signer starts at or above the old signer's high-water mark.

## Cut over

1. Stop TMKMS and confirm the process is gone. The validator misses blocks from this moment; that is expected and safe.
2. Start Cosmos-KMS with the completed `kms.yaml`. It dials the validator and resumes signing.
3. Confirm signing resumed: the chain includes the validator's signatures again and the new signer's state file advances.

<Danger>Never run TMKMS and Cosmos-KMS at the same time against the same validator key. Each keeps its own last-signed state, so together they can sign the same height, which is a double sign. Stop one fully before starting the other, in both directions, including any rollback.</Danger>

## What can go wrong

* Both signers briefly alive: the double-sign risk above. Cut over with the old process confirmed dead, not just signaled.
* The validator stays dark after cutover: the new signer is not reaching the listener. Check the `validators[].addr` translation and the firewall between the hosts.
* The signer rejects the key file: the softsign format question above. Do not guess at conversions with a production key.

## Next steps

* Harden the new setup. See [Remote signing best practices](/sdk/next/kms/best-practices).
* Full field reference for the translated config. See the [configuration reference](/sdk/next/kms/configuration-reference).
