feat: implement secure cluster authentication (issue #13)
Implemented a comprehensive secure authentication mechanism for inter-node cluster communication with the following features: 1. Global Cluster Secret (GCS) - Auto-generated cryptographically secure random secret (256-bit) - Configurable via YAML config file - Shared across all cluster nodes for authentication 2. Cluster Authentication Middleware - Validates X-Cluster-Secret and X-Node-ID headers - Applied to all cluster endpoints (/members/*, /merkle_tree/*, /kv_range) - Comprehensive logging of authentication attempts 3. Authenticated HTTP Client - Custom HTTP client with cluster auth headers - TLS support with configurable certificate verification - Protocol-aware (http/https based on TLS settings) 4. Secure Bootstrap Endpoint - New /auth/cluster-bootstrap endpoint - Protected by JWT authentication with admin scope - Allows new nodes to securely obtain cluster secret 5. Updated Cluster Communication - All gossip protocol requests include auth headers - All Merkle tree sync requests include auth headers - All data replication requests include auth headers 6. Configuration - cluster_secret: Shared secret (auto-generated if not provided) - cluster_tls_enabled: Enable TLS for inter-node communication - cluster_tls_cert_file: Path to TLS certificate - cluster_tls_key_file: Path to TLS private key - cluster_tls_skip_verify: Skip TLS verification (testing only) This implementation addresses the security vulnerability of unprotected cluster endpoints and provides a flexible, secure approach to protecting internal cluster communication while allowing for automated node bootstrapping. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,6 @@ import (
|
||||
"kvs/utils"
|
||||
)
|
||||
|
||||
|
||||
|
||||
// healthHandler returns server health status
|
||||
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
mode := s.getMode()
|
||||
@@ -1271,3 +1269,29 @@ func (s *Server) getRevisionHistory(key string) ([]map[string]interface{}, error
|
||||
func (s *Server) getSpecificRevision(key string, revision int) (*types.StoredValue, error) {
|
||||
return s.revisionService.GetSpecificRevision(key, revision)
|
||||
}
|
||||
|
||||
// clusterBootstrapHandler provides the cluster secret to authenticated administrators (Issue #13)
|
||||
func (s *Server) clusterBootstrapHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Ensure clustering is enabled
|
||||
if !s.config.ClusteringEnabled {
|
||||
http.Error(w, "Clustering is disabled", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure cluster secret is configured
|
||||
if s.config.ClusterSecret == "" {
|
||||
s.logger.Error("Cluster secret is not configured")
|
||||
http.Error(w, "Cluster secret is not configured", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Return the cluster secret for secure bootstrap
|
||||
response := map[string]string{
|
||||
"cluster_secret": s.config.ClusterSecret,
|
||||
}
|
||||
|
||||
s.logger.WithField("remote_addr", r.RemoteAddr).Info("Cluster secret retrieved for bootstrap")
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
Reference in New Issue
Block a user