# How Fuel Core Manages the Consensus Key for Signing Blocks: A Complete Guide to SignMode

> Discover how Fuel Core manages the consensus key for signing blocks using SignMode, supporting local keys, KMS, or disabled signing. Learn about FuelBlockSigner and Proof-of-Authority.

- Repository: [Fuel Labs/fuel-core](https://github.com/FuelLabs/fuel-core)
- Tags: deep-dive
- Published: 2026-03-06

---

**Fuel Core manages the consensus key for signing blocks through the `SignMode` enum, which supports local secret keys, AWS KMS integration, or disabled signing, and abstracts the signing process via the `FuelBlockSigner` adapter that seals blocks with Proof-of-Authority signatures.**

The consensus key for signing blocks is a critical security component in Fuel Core, the Rust-based node implementation for the Fuel network maintained by FuelLabs. This key proves block authenticity through Proof-of-Authority (PoA) consensus and must be carefully managed to prevent unauthorized block production. Fuel Core provides a flexible, feature-gated architecture for consensus key management that accommodates both development environments and production deployments with hardware security modules.

## Understanding the SignMode Abstraction

At the heart of Fuel Core's consensus key management lies the **`SignMode`** enum defined in [`crates/types/src/signer.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/types/src/signer.rs). This abstraction unifies three distinct key storage strategies behind a common interface:

- **`Unavailable`** – Indicates no consensus key is configured, automatically disabling block production.
- **`Key(Secret<SecretKeyWrapper>)`** – Wraps a locally stored secret key provided via configuration files, environment variables, or CLI arguments.
- **`Kms { key_id, client, cached_public_key_bytes }`** – Integrates with AWS KMS for hardware-backed key management (requires the `aws-kms` feature flag).

The `SignMode` enum exposes uniform methods for cryptographic operations regardless of the underlying storage mechanism. The **`sign_message()`** and **`sign()`** methods produce signatures, while **`public_key()`**, **`verifying_key()`**, and **`address()`** expose the associated public identity. The **`is_available()`** helper quickly determines whether block production should proceed.

## Configuring the Consensus Key

Fuel Core supports both programmatic configuration and CLI-based setup for the consensus key, accommodating automated deployments and manual node operations.

### Programmatic Configuration

When constructing a node programmatically, the `Config` struct in [`crates/fuel-core/src/service/config.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/config.rs) accepts a `SignMode` directly through the **`consensus_signer`** field:

```rust
pub struct Config {
    // ... other configuration fields ...
    pub consensus_signer: SignMode,   // The consensus key configuration
    // ...
}

```

To configure a raw secret key programmatically:

```rust
use fuel_core::service::config::Config;
use fuel_core_types::signer::SignMode;
use fuel_core_types::secrecy::Secret;
use fuel_core_types::signer::SecretKeyWrapper;

// Load hex-encoded secret key from environment
let secret_key_hex = std::env::var("CONSENSUS_KEY")
    .expect("CONSENSUS_KEY must be set");

// Parse the secret key
let secret_key = SecretKeyWrapper::from_hex(&secret_key_hex)
    .expect("invalid secret key");

// Create the SignMode
let signer = SignMode::Key(Secret::new(secret_key));

// Build the node configuration
let config = Config {
    // ... other required fields ...
    consensus_signer: signer,
    ..Default::default()
};

```

### CLI-Based Configuration

The [`bin/fuel-core/src/cli/run.rs`](https://github.com/FuelLabs/fuel-core/blob/main/bin/fuel-core/src/cli/run.rs) file handles command-line argument parsing, converting flags into the appropriate `SignMode` variant:

```bash
fuel-core run \
  --consensus-key 0x0123456789abcdef... \
  --chain-config ./chain-config.json \
  --trigger manual

```

The CLI logic implements a priority-based fallback system:

1. **AWS KMS path** – If `--consensus-aws-kms <key_id>` is provided (requires `aws-kms` feature), constructs `SignMode::Kms`.
2. **Explicit secret key** – If `--consensus-key <hex>` is provided, parses it into `SignMode::Key`.
3. **Development fallback** – If `--debug` is set and no key is provided, uses a hard-coded dev key via `default_consensus_dev_key()`.
4. **Disabled production** – If no key is provided and `--debug` is not set, sets `SignMode::Unavailable`, disabling block production.

*If you run with `--debug` and omit `--consensus-key`, Fuel Core will fall back to the insecure dev key, emitting a warning.*

## The Block Signing Pipeline

Once configured, the consensus key integrates into the block production pipeline through the `FuelBlockSigner` adapter, which abstracts the signing operation from the block producer logic.

### FuelBlockSigner Implementation

Located in [`crates/fuel-core/src/service/adapters.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/adapters.rs), the **`FuelBlockSigner`** wraps the configured `SignMode` and implements the generic `BlockSigner` trait:

```rust
pub struct FuelBlockSigner {
    mode: SignMode,
}

impl FuelBlockSigner {
    pub fn new(mode: SignMode) -> Self {
        Self { mode }
    }
}

impl BlockSigner for FuelBlockSigner {
    async fn seal_block(&self, block: &Block) -> anyhow::Result<Consensus> {
        let block_hash = block.id();
        let message = block_hash.into_message();
        let signature = self.mode.sign_message(message).await?;
        Ok(Consensus::PoA(PoAConsensus::new(signature)))
    }
    
    fn is_available(&self) -> bool { 
        self.mode.is_available() 
    }
}

```

The block producer instantiates this signer in [`crates/fuel-core/src/service/sub_services.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/sub_services.rs):

```rust
let signer = FuelBlockSigner::new(config.consensus_signer.clone());

```

### Sealing Blocks with PoA Signatures

When the block producer generates a new block, it calls `seal_block`, which:

1. Computes the block hash via `block.id()`.
2. Converts the hash into a signing message.
3. Delegates to `SignMode::sign_message()` to produce the cryptographic signature.
4. Wraps the result in a `Consensus::PoA` variant containing the `PoAConsensus` structure.

This design ensures the block producer remains agnostic to whether the key resides in local memory, a secure enclave, or external KMS infrastructure.

## Security Considerations and Production Deployment

Managing the consensus key for signing blocks requires strict security practices, particularly for mainnet validators. Fuel Core provides several mechanisms to support secure deployments:

**Environment Variable Injection**: For local keys, pass the hex-encoded secret via environment variables rather than command-line arguments to prevent exposure in process lists.

**AWS KMS Integration**: Enable the `aws-kms` feature to leverage hardware security modules. The `SignMode::Kms` variant stores only the key ID and cached public key bytes locally, delegating all signing operations to the AWS KMS API. This ensures the private key never leaves the hardware security module boundary.

**Development Mode Isolation**: The hard-coded dev key fallback only activates with `--debug`. Never run production nodes with this flag, as the dev key is publicly known and completely insecure.

**Availability Checks**: The `is_available()` method on both `SignMode` and `FuelBlockSigner` ensures nodes without valid keys cannot accidentally attempt block production, preventing empty or invalid consensus attempts.

## Summary

Fuel Core manages the consensus key for signing blocks through a layered abstraction that separates configuration, CLI parsing, and cryptographic operations:

- The **`SignMode`** enum in [`crates/types/src/signer.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/types/src/signer.rs) unifies local secrets, AWS KMS, and disabled states behind a common interface with `sign_message()` and `is_available()` methods.
- The **`Config`** struct stores the selected `SignMode` in its `consensus_signer` field, populated either programmatically or via CLI flags in [`bin/fuel-core/src/cli/run.rs`](https://github.com/FuelLabs/fuel-core/blob/main/bin/fuel-core/src/cli/run.rs).
- The **`FuelBlockSigner`** adapter in [`crates/fuel-core/src/service/adapters.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/adapters.rs) implements the `BlockSigner` trait, delegating to `SignMode` to produce PoA signatures during block sealing.
- Security features include AWS KMS integration via the `aws-kms` feature flag, environment variable support for local keys, and automatic disabling of block production when no valid key is configured.

## Frequently Asked Questions

### What happens if no consensus key is configured?

If you start Fuel Core without providing a consensus key and without the `--debug` flag, the node sets `SignMode::Unavailable` and disables block production entirely. The node can still validate and sync blocks, but it cannot produce new ones. This prevents accidental attempts to seal blocks without proper signing credentials.

### How does AWS KMS integration work in Fuel Core?

Fuel Core supports AWS KMS through the optional `aws-kms` feature flag. When enabled, you can pass `--consensus-aws-kms <key_id>` to use a KMS-managed key. The `SignMode::Kms` variant stores only the key ID and a cached copy of the public key bytes locally, delegating all signing operations to the AWS KMS API. This ensures the private key never leaves the hardware security module boundary.

### Can I rotate the consensus key without restarting the node?

Currently, Fuel Core loads the consensus key once during initialization from the `Config` struct. To rotate keys, you must restart the node with the new key configuration. For high-availability deployments, operators typically deploy a new node instance with the updated key and perform a controlled failover rather than hot-swapping keys in a running process.

### Is the consensus key used for anything besides block signing?

In the current Fuel Core implementation, the consensus key is used exclusively for signing blocks to produce Proof-of-Authority consensus. It is not used for networking encryption, transaction signing, or other cryptographic operations within the node. The key's sole purpose is to authenticate the block producer's identity during the sealing process, ensuring only authorized validators can extend the chain.