Secure Cluster Communication with PSK and Node Identity Problem Statement #13
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Currently, KVS cluster membership and replication synchronization endpoints (/members/, /merkle_tree/, /kv_range) are not protected by the authentication middleware. This leaves internal cluster communication vulnerable to unauthorized access and manipulation, even when external client authentication (auth_enabled: true) is active. This gap poses a significant security risk, as any entity capable of reaching these endpoints can potentially join the cluster, extract data, or inject malicious information.
Proposed Solution: PSK-Authenticated Cluster Communication with Secure Bootstrapping
We will implement a security model for inter-node communication that combines a Global Cluster Secret (PSK) for authentication with the existing NodeID for identification. A secure bootstrapping mechanism, leveraging existing JWT tokens, will allow new nodes to obtain the Global Cluster Secret automatically.
Crucial Prerequisite: TLS Encryption
All inter-node communication MUST be encrypted using TLS (HTTPS). Transmitting any secrets (including the Global Cluster Secret) over unencrypted HTTP is unacceptable and negates the purpose of this security enhancement. This can be achieved either by configuring KVS nodes to serve HTTPS directly or by placing them behind a reverse proxy (e.g., Nginx, Traefik) that handles TLS termination for all inter-node traffic.
Core Components & How They Work
Global Cluster Secret (GCS)
Purpose: A single, strong, randomly generated secret key shared by all legitimate nodes in the cluster. It serves as the primary authentication credential for internal cluster communication, verifying that a request originates from a trusted cluster member.
Configuration: The GCS will be configurable through multiple sources to facilitate automated deployments:
Usage: For every outgoing internal cluster request (e.g., /members/join, /members/gossip, /merkle_tree/root), the GCS will be included in a custom HTTP header, e.g., X-KVS-Cluster-Secret.
Node Identity (NodeID)
Purpose: The existing node_id from the configuration will be used to uniquely identify the specific node making an internal request. While the GCS authenticates membership, the NodeID provides granular identification for logging, auditing, and potential future node-specific authorization.
Usage: The NodeID will be included in another custom HTTP header, e.g., X-KVS-Node-ID, alongside the GCS.
Secure Bootstrapping Mechanism
Purpose: To enable new nodes to securely obtain the Global Cluster Secret without manual intervention or having the GCS hardcoded in their initial configuration.
Mechanism:
Detailed Implementation Plan
Phase 1: Configuration & TLS Enforcement
Phase 2: Cluster Authentication Middleware
IGNORE_WHEN_COPYING_START
IGNORE_WHEN_COPYING_END
func (s *Server) clusterAuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !s.config.ClusteringEnabled {
// If clustering is disabled, these endpoints should not be accessible.
http.Error(w, "Clustering is disabled", http.StatusForbidden)
return
}
}
Apply Middleware (server/routes.go):
code Go
Phase 3: Outgoing Request Modification
Phase 4: Secure Bootstrapping Endpoint
IGNORE_WHEN_COPYING_START
IGNORE_WHEN_COPYING_END
// server/handlers.go
func (s *Server) getClusterCredentialsHandler(w http.ResponseWriter, r *http.Request) {
// This endpoint should already be protected by JWT middleware requiring admin:cluster:bootstrap scope
// No request body needed, as the secret is global.
resp := map[string]string{
"cluster_secret": s.config.ClusterSecret,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
s.logger.WithField("remote_addr", r.RemoteAddr).Info("Served cluster credentials to new node")
}
Add Route (server/routes.go):
code Go
IGNORE_WHEN_COPYING_START
IGNORE_WHEN_COPYING_END
// In server/routes.go, inside setupRoutes():
if s.config.AuthEnabled {
// ... other auth routes ...
router.Handle("/auth/cluster-bootstrap", s.authService.Middleware(
[]string{"admin:cluster:bootstrap"}, nil, "",
)(s.getClusterCredentialsHandler)).Methods("GET") // Or POST if a body is needed for future extensions
}
Modify BootstrapService (cluster/bootstrap.go):
code Go
Security Considerations
Future Enhancements (Optional)
This comprehensive plan addresses the security vulnerability while providing flexible configuration and a secure bootstrapping process for new KVS nodes.