From 8d083f5fdc40f2c3bb4ffcfa2512213acf1e851e Mon Sep 17 00:00:00 2001 From: dimgigov Date: Fri, 31 Jul 2026 01:14:20 +0300 Subject: [PATCH] feat(raft): TLS config surface with fail-closed startup --- src/barabadb/core/config.nim | 15 +++++++++++++++ src/baradadb.nim | 6 ++++++ tests/bugfix_test.nim | 31 +++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/barabadb/core/config.nim b/src/barabadb/core/config.nim index 78e67ec..2bd5185 100644 --- a/src/barabadb/core/config.nim +++ b/src/barabadb/core/config.nim @@ -44,6 +44,11 @@ type raftPeerClientAddrs*: Table[string, tuple[host: string, port: int]] raftWriteTimeoutMs*: int raftLogMaxEntries*: int + raftTlsEnabled*: bool + raftTlsCertFile*: string + raftTlsKeyFile*: string + raftTlsCaFile*: string + raftTlsVerifyPeer*: bool CompactionStrategy* = enum csSizeTiered = "size_tiered" @@ -86,6 +91,11 @@ proc defaultConfig*(): BaraConfig = raftPeerClientAddrs: initTable[string, tuple[host: string, port: int]](), raftWriteTimeoutMs: 5_000, raftLogMaxEntries: 256, + raftTlsEnabled: false, + raftTlsCertFile: "", + raftTlsKeyFile: "", + raftTlsCaFile: "", + raftTlsVerifyPeer: false, ) # ---------------------------------------------------------------------- @@ -213,6 +223,11 @@ proc loadConfigFromEnv*(cfg: var BaraConfig) = cfg.raftNodeId = getEnv("BARADB_RAFT_NODE_ID", cfg.raftNodeId) cfg.raftWriteTimeoutMs = parseEnvInt(getEnv("BARADB_RAFT_WRITE_TIMEOUT_MS", ""), cfg.raftWriteTimeoutMs) cfg.raftLogMaxEntries = parseEnvInt(getEnv("BARADB_RAFT_LOG_MAX_ENTRIES", ""), cfg.raftLogMaxEntries) + cfg.raftTlsEnabled = parseEnvBool(getEnv("BARADB_RAFT_TLS_ENABLED", ""), cfg.raftTlsEnabled) + cfg.raftTlsCertFile = getEnv("BARADB_RAFT_TLS_CERT_FILE", cfg.raftTlsCertFile) + cfg.raftTlsKeyFile = getEnv("BARADB_RAFT_TLS_KEY_FILE", cfg.raftTlsKeyFile) + cfg.raftTlsCaFile = getEnv("BARADB_RAFT_TLS_CA_FILE", cfg.raftTlsCaFile) + cfg.raftTlsVerifyPeer = parseEnvBool(getEnv("BARADB_RAFT_TLS_VERIFY_PEER", ""), cfg.raftTlsVerifyPeer) # Optional: client (SQL) addresses for leader write forwarding. # Same id@host:port shape as BARADB_RAFT_PEERS, but ports are BARADB_PORT values. let clientPeersEnv = getEnv("BARADB_RAFT_CLIENT_PEERS", "") diff --git a/src/baradadb.nim b/src/baradadb.nim index 5131d4c..5dd302c 100644 --- a/src/baradadb.nim +++ b/src/baradadb.nim @@ -338,6 +338,12 @@ proc main() = var raftNet: RaftNetwork = nil if config.raftEnabled: info("Starting Raft node " & config.raftNodeId & " on port " & $config.raftPort) + if config.raftTlsEnabled: + if config.raftTlsCertFile.len == 0 or config.raftTlsKeyFile.len == 0 or + not fileExists(config.raftTlsCertFile) or not fileExists(config.raftTlsKeyFile): + raise newException(ValueError, + "BARADB_RAFT_TLS_ENABLED=true but cert/key missing " & + "(BARADB_RAFT_TLS_CERT_FILE / BARADB_RAFT_TLS_KEY_FILE)") let raftDataDir = config.dataDir / "raft" createDir(raftDataDir) # idempotent; loadState reads from it, saveState writes # Raft convention: `peers` excludes the node itself (majority math and diff --git a/tests/bugfix_test.nim b/tests/bugfix_test.nim index 3cfb2a0..0b12970 100644 --- a/tests/bugfix_test.nim +++ b/tests/bugfix_test.nim @@ -521,3 +521,34 @@ suite "Raft write classification": check not isRaftDdl(parse("CREATE DATABASE other").stmts[0]) check not isRaftDdl(parse("INSERT INTO t (id) VALUES (1)").stmts[0]) check not isRaftDdl(parse("SELECT 1").stmts[0]) + + +suite "Raft TLS config": + + test "default config has raft TLS disabled with empty paths": + let cfg = defaultConfig() + check cfg.raftTlsEnabled == false + check cfg.raftTlsCertFile == "" + check cfg.raftTlsKeyFile == "" + check cfg.raftTlsCaFile == "" + check cfg.raftTlsVerifyPeer == false + + test "env vars parse into raft TLS config": + putEnv("BARADB_RAFT_TLS_ENABLED", "true") + putEnv("BARADB_RAFT_TLS_CERT_FILE", "/tmp/raft.crt") + putEnv("BARADB_RAFT_TLS_KEY_FILE", "/tmp/raft.key") + putEnv("BARADB_RAFT_TLS_CA_FILE", "/tmp/raft-ca.crt") + putEnv("BARADB_RAFT_TLS_VERIFY_PEER", "1") + defer: + delEnv("BARADB_RAFT_TLS_ENABLED") + delEnv("BARADB_RAFT_TLS_CERT_FILE") + delEnv("BARADB_RAFT_TLS_KEY_FILE") + delEnv("BARADB_RAFT_TLS_CA_FILE") + delEnv("BARADB_RAFT_TLS_VERIFY_PEER") + var cfg = defaultConfig() + loadConfigFromEnv(cfg) + check cfg.raftTlsEnabled == true + check cfg.raftTlsCertFile == "/tmp/raft.crt" + check cfg.raftTlsKeyFile == "/tmp/raft.key" + check cfg.raftTlsCaFile == "/tmp/raft-ca.crt" + check cfg.raftTlsVerifyPeer == true