How to Configure TLS Mutual Authentication for Secure Communication Between Dragonboat Nodes
Enable mutual TLS in Dragonboat by setting NodeHostConfig.MutualTLS to true and providing the CAFile, CertFile, and KeyFile paths, which automatically encrypts all Raft traffic and authenticates nodes using the shared Certificate Authority.
Dragonboat is a high-performance Raft consensus library for Go that protects node-to-node communication through built-in mutual TLS (mTLS) support. When you configure TLS mutual authentication for secure communication between Dragonboat nodes, the transport layer automatically encrypts all Raft messages and snapshot streams while verifying that each peer presents a valid certificate signed by a shared Certificate Authority.
Understanding Dragonboat's Mutual TLS Architecture
Dragonboat implements mTLS at the transport layer, ensuring that both incoming and outgoing connections are authenticated and encrypted without requiring changes to your application logic.
How the Transport Layer Handles Encryption
In internal/transport/tcp.go, the TCP transport checks the NodeHostConfig.MutualTLS flag during initialization. When enabled, the transport sets an internal encrypted flag that triggers TLS wrapping for all connections.
The listener creation in tcp.Start calls NodeHostConfig.GetServerTLSConfig() to obtain a tls.Config configured with the node's certificate and the shared CA. For outbound connections, tcp.getConnection invokes GetClientTLSConfig(target), which builds a client-side TLS configuration that verifies the remote server's certificate against the same CA and sets the ServerName field for hostname verification.
Certificate Validation Flow
Each Dragonboat node requires three files: the CA certificate (CAFile), the node's own certificate (CertFile), and its private key (KeyFile). During the TLS handshake:
- The server presents its certificate to connecting clients.
- The client verifies the server certificate against the
CAFile. - In mutual TLS mode, the client also presents its certificate.
- The server verifies the client certificate against the same
CAFile.
This bidirectional verification ensures that only nodes with certificates signed by the shared CA can join the Raft cluster.
Prerequisites for TLS Configuration
Before configuring Dragonboat nodes, you must generate the required certificates. Each node needs a unique certificate/key pair, and all nodes must share the same CA certificate.
Generating Certificates and CA
Use OpenSSL or a similar tool to create the certificate infrastructure:
# Generate CA private key and certificate
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.pem \
-subj "/CN=Dragonboat-CA"
# Generate node certificate (repeat for each node)
openssl genrsa -out node1.key 4096
openssl req -new -key node1.key -out node1.csr \
-subj "/CN=dragonboat-node-1"
openssl x509 -req -days 365 -in node1.csr -CA ca.pem -CAkey ca.key \
-CAcreateserial -out node1.crt
Distribute ca.pem to all nodes. Each node receives its own nodeN.crt and nodeN.key files.
Configuring NodeHostConfig for Mutual TLS
The NodeHostConfig struct in config/config.go defines the fields required to enable TLS mutual authentication. Set MutualTLS to true and provide the paths to your certificate files.
import "github.com/lni/dragonboat/v4/config"
nhConfig := config.NodeHostConfig{
// Network address for Raft communication
RaftAddress: "10.0.0.1:63001",
// Enable mutual TLS
MutualTLS: true,
// Certificate paths - must be accessible to the process
CAFile: "/etc/dragonboat/certs/ca.pem", // Shared CA
CertFile: "/etc/dragonboat/certs/node1.crt", // This node's cert
KeyFile: "/etc/dragonboat/certs/node1.key", // This node's private key
// Optional: configure other NodeHost settings
MaxSendQueueSize: 1024 * 1024,
}
The CAFile must contain the certificate of the authority that signed all node certificates. The CertFile and KeyFile contain this specific node's identity.
Starting a NodeHost with TLS Enabled
Once configured, pass the NodeHostConfig to dragonboat.NewNodeHost. The transport layer automatically initializes TLS listeners and clients based on the configuration.
import (
"github.com/lni/dragonboat/v4"
"github.com/lni/dragonboat/v4/config"
"github.com/lni/dragonboat/v4/raftio"
)
func main() {
nhConfig := config.NodeHostConfig{
RaftAddress: "10.0.0.1:63001",
MutualTLS: true,
CAFile: "/etc/dragonboat/certs/ca.pem",
CertFile: "/etc/dragonboat/certs/node1.crt",
KeyFile: "/etc/dragonboat/certs/node1.key",
}
// Create the NodeHost - TLS is automatically enabled
nh, err := dragonboat.NewNodeHost(nhConfig, raftio.NewInMemLogDB, nil)
if err != nil {
panic(err)
}
defer nh.Close()
// Proceed with StartReplica or other operations
// All Raft traffic will now use mutual TLS
}
When MutualTLS is true, internal/transport/tcp.go invokes GetServerTLSConfig to create the TLS listener and GetClientTLSConfig for every outbound connection to peers.
Verifying TLS Communication
The Dragonboat repository includes tests in internal/transport/transport_test.go that verify mutual TLS functionality. These tests demonstrate that when MutualTLS is enabled, the transport correctly encrypts messages and validates certificates.
To verify your own deployment:
- Check that nodes can form a cluster and elect a leader.
- Monitor network traffic to confirm encryption (e.g., using
tcpdumpor Wireshark - traffic should be opaque). - Verify that nodes reject connections from clients presenting certificates signed by a different CA.
If a node attempts to connect with an invalid certificate, the TLS handshake will fail in tcp.getConnection before any Raft messages are exchanged, preventing unauthorized nodes from joining the cluster.
Summary
- Enable mTLS by setting
NodeHostConfig.MutualTLStotrueand providingCAFile,CertFile, andKeyFilepaths. - Certificate requirements include a shared CA certificate distributed to all nodes and unique certificate/key pairs for each node.
- Automatic encryption occurs in
internal/transport/tcp.go, which usesGetServerTLSConfigfor listeners andGetClientTLSConfigfor outbound connections. - No application changes are required beyond configuration; the transport layer handles all TLS handshakes and certificate validation transparently.
Frequently Asked Questions
What files are required to enable mutual TLS in Dragonboat?
You need three files: a CAFile containing the Certificate Authority certificate that signed all node certificates, a CertFile containing the specific node's certificate, and a KeyFile containing the node's private key. All nodes must use the same CA file, but each node requires its own unique certificate and key pair.
Does enabling MutualTLS affect application-level Raft code?
No. When you configure NodeHostConfig.MutualTLS, the encryption and authentication happen entirely within the transport layer in internal/transport/tcp.go. Your state machine implementation, Raft configuration, and business logic remain unchanged. The NewNodeHost function automatically initializes TLS listeners and clients based on the configuration.
How does Dragonboat verify peer certificates during cluster membership changes?
During cluster membership changes or regular heartbeat exchanges, when node A connects to node B, the transport layer in tcp.getConnection creates a TLS client using GetClientTLSConfig. This configuration requires the server (node B) to present a certificate signed by the shared CA. Conversely, node B's listener, created with GetServerTLSConfig, requires client certificates signed by the same CA. If verification fails, the connection is rejected before any Raft protocol messages are transmitted.
Can I use different CAs for different nodes in the same cluster?
No. Dragonboat's mutual TLS implementation requires a shared Certificate Authority across all nodes in the cluster. The CAFile specified in NodeHostConfig is used to verify both incoming and outgoing connections. If nodes use different CAs, TLS handshakes will fail because nodes cannot verify each other's certificate chains against their local CA file.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →