feat: Implement CSR signing and node registration handler for agent join
This commit is contained in:
@ -248,124 +248,9 @@ func runInit(cmd *cobra.Command, args []string) {
|
||||
log.Printf("Failed to create API server: %v", err)
|
||||
} else {
|
||||
// Register the join handler
|
||||
apiServer.RegisterJoinHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("Received join request from %s", r.RemoteAddr)
|
||||
|
||||
// In Phase 2, we're not requiring client certificates yet
|
||||
log.Printf("Processing join request without client certificate verification (Phase 2)")
|
||||
|
||||
// Read request body
|
||||
var joinReq cli.JoinRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&joinReq); err != nil {
|
||||
log.Printf("Error decoding join request: %v", err)
|
||||
http.Error(w, "Invalid request format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
if joinReq.NodeName == "" || joinReq.AdvertiseAddr == "" || joinReq.CSRData == "" {
|
||||
log.Printf("Invalid join request: missing required fields")
|
||||
http.Error(w, "Missing required fields", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Processing join request for node: %s, advertise address: %s",
|
||||
joinReq.NodeName, joinReq.AdvertiseAddr)
|
||||
|
||||
// Decode CSR data
|
||||
csrData, err := base64.StdEncoding.DecodeString(joinReq.CSRData)
|
||||
if err != nil {
|
||||
log.Printf("Error decoding CSR data: %v", err)
|
||||
http.Error(w, "Invalid CSR data", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Create a temporary file for the CSR
|
||||
tempCSRFile, err := os.CreateTemp("", "node-csr-*.pem")
|
||||
if err != nil {
|
||||
log.Printf("Error creating temp CSR file: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer os.Remove(tempCSRFile.Name())
|
||||
|
||||
// Write CSR data to temp file
|
||||
if _, err := tempCSRFile.Write(csrData); err != nil {
|
||||
log.Printf("Error writing CSR data to temp file: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
tempCSRFile.Close()
|
||||
|
||||
// Create a temp file for the signed certificate
|
||||
tempCertFile, err := os.CreateTemp("", "node-cert-*.pem")
|
||||
if err != nil {
|
||||
log.Printf("Error creating temp cert file: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer os.Remove(tempCertFile.Name())
|
||||
tempCertFile.Close()
|
||||
|
||||
// Sign the CSR
|
||||
if err := pki.SignCertificateRequest(
|
||||
filepath.Join(pkiDir, "ca.key"),
|
||||
filepath.Join(pkiDir, "ca.crt"),
|
||||
tempCSRFile.Name(),
|
||||
tempCertFile.Name(),
|
||||
365*24*time.Hour, // 1 year validity
|
||||
); err != nil {
|
||||
log.Printf("Error signing CSR: %v", err)
|
||||
http.Error(w, "Failed to sign certificate", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the signed certificate
|
||||
signedCert, err := os.ReadFile(tempCertFile.Name())
|
||||
if err != nil {
|
||||
log.Printf("Error reading signed certificate: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the CA certificate
|
||||
caCert, err := os.ReadFile(filepath.Join(pkiDir, "ca.crt"))
|
||||
if err != nil {
|
||||
log.Printf("Error reading CA certificate: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a unique node UID
|
||||
nodeUID := uuid.New().String()
|
||||
|
||||
// Store node registration in etcd (placeholder for now)
|
||||
// In a future phase, we'll implement proper node registration with subnet assignment
|
||||
|
||||
// Create response
|
||||
joinResp := cli.JoinResponse{
|
||||
NodeName: joinReq.NodeName,
|
||||
NodeUID: nodeUID,
|
||||
SignedCertificate: base64.StdEncoding.EncodeToString(signedCert),
|
||||
CACertificate: base64.StdEncoding.EncodeToString(caCert),
|
||||
AssignedSubnet: "10.100.0.0/24", // Placeholder, will be properly implemented in network phase
|
||||
}
|
||||
|
||||
// If etcd peer was requested, add join instructions (placeholder)
|
||||
if etcdPeer {
|
||||
joinResp.EtcdJoinInstructions = "Etcd peer join not implemented in this phase"
|
||||
}
|
||||
|
||||
// Send response
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(joinResp); err != nil {
|
||||
log.Printf("Error encoding join response: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Successfully processed join request for node: %s", joinReq.NodeName)
|
||||
})
|
||||
joinHandler := api.NewJoinHandler(etcdStore, caKeyPath, caCertPath)
|
||||
apiServer.RegisterJoinHandler(joinHandler)
|
||||
log.Printf("Registered join handler with CA key: %s, CA cert: %s", caKeyPath, caCertPath)
|
||||
|
||||
// Start the server in a goroutine
|
||||
go func() {
|
||||
|
Reference in New Issue
Block a user