Zero Trust Microgateway Console Go
👤 Sharing: AI
```go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/gorilla/mux"
)
// RequestLog struct represents a log entry for each request processed by the microgateway.
type RequestLog struct {
Timestamp string `json:"timestamp"`
Method string `json:"method"`
Path string `json:"path"`
SourceIP string `json:"source_ip"`
UserID string `json:"user_id,omitempty"` // Optional field if authentication is enabled
PolicyCheck string `json:"policy_check"` // "Allow" or "Deny"
Notes string `json:"notes,omitempty"` // Optional notes for specific events
}
// PolicyRule struct represents a policy rule. This would be stored and retrieved from a real policy engine.
type PolicyRule struct {
Path string `json:"path"`
Method string `json:"method"`
Roles []string `json:"roles"` // Roles allowed to access this resource. Empty means no authentication required.
}
// Mock Authentication (Replace with proper authentication in a real implementation)
func authenticate(r *http.Request) (string, bool) {
// In a real zero-trust setup, this would involve verifying JWT tokens,
// client certificates, or other authentication methods.
// For simplicity, this example uses a mock authentication.
// Check for a "X-User-ID" header. This simulates passing user identity.
userID := r.Header.Get("X-User-ID")
if userID != "" {
// Simulate valid user, can implement more robust logic with JWT or other credential check
return userID, true // Authentication successful
}
// If no user ID is provided, it means no authentication required for this request
return "", false // Authentication failed
}
// policyEngine simulates a policy engine that decides whether to allow or deny a request.
func policyEngine(userID string, rule PolicyRule) string {
// Basic role-based access control (RBAC).
if len(rule.Roles) == 0 {
// No authentication required
return "Allow"
}
if userID == "" {
return "Deny" // User not authenticated, deny access.
}
// Check if the user has any of the roles required by the resource.
for _, role := range rule.Roles {
if userID == role { // Example: UserID and role are the same
return "Allow" // User has the required role, allow access.
}
}
return "Deny" // User does not have the required roles, deny access.
}
// requestLogger middleware logs each request.
func requestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
// Create a custom response writer to capture the status code.
lrw := NewLoggingResponseWriter(w)
// Call the next handler in the chain.
next.ServeHTTP(lrw, r)
duration := time.Since(startTime)
// Log the request details.
log.Printf(
"%-15s %s %s %d %s",
r.RemoteAddr,
r.Method,
r.URL.Path,
lrw.statusCode,
duration,
)
})
}
// LoggingResponseWriter captures the status code.
type LoggingResponseWriter struct {
http.ResponseWriter
statusCode int
}
func NewLoggingResponseWriter(w http.ResponseWriter) *LoggingResponseWriter {
// WriteHeader(int) is not called if our response implicitly returns 200 OK.
return &LoggingResponseWriter{ResponseWriter: w, statusCode: http.StatusOK}
}
func (lrw *LoggingResponseWriter) WriteHeader(code int) {
lrw.statusCode = code
lrw.ResponseWriter.WriteHeader(code)
}
// ZeroTrustMiddleware implements the zero-trust logic.
func ZeroTrustMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. Authentication
userID, isAuthenticated := authenticate(r)
// 2. Authorization (Policy Enforcement)
// In a real implementation, this would fetch policy rules from a policy engine.
// This example uses hardcoded rules.
policy := getPolicyForRequest(r.URL.Path, r.Method) // Get policy rule based on path and method
var policyCheckResult string
var notes string
if policy.Path == "" {
//No policy found, deny access.
policyCheckResult = "Deny"
notes = "No policy found for this resource"
} else {
policyCheckResult = policyEngine(userID, policy)
}
// 3. Logging
logEntry := RequestLog{
Timestamp: time.Now().Format(time.RFC3339),
Method: r.Method,
Path: r.URL.Path,
SourceIP: r.RemoteAddr,
PolicyCheck: policyCheckResult,
Notes: notes,
}
if isAuthenticated {
logEntry.UserID = userID
}
logJSON, err := json.Marshal(logEntry)
if err != nil {
log.Printf("Error marshaling log entry: %v", err)
}
// Append the log to the log file
logFile, err := os.OpenFile("microgateway.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Error opening log file: %v", err)
}
defer logFile.Close()
logger := log.New(logFile, "", log.LstdFlags)
logger.Println(string(logJSON))
// 4. Enforcement
if policyCheckResult == "Deny" {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("Access Denied"))
return // Stop further processing.
}
// If access is allowed, continue to the next handler.
next.ServeHTTP(w, r)
})
}
// Mock Policy Store (Replace with a real policy engine integration)
var policies = []PolicyRule{
{Path: "/api/resource1", Method: "GET", Roles: []string{"admin"}}, // Only admins can access.
{Path: "/api/resource2", Method: "POST", Roles: []string{"user", "admin"}}, // Users and admins can access.
{Path: "/public", Method: "GET", Roles: []string{}}, // Public endpoint (no authentication required).
}
// getPolicyForRequest returns the policy rule for a given path and method.
func getPolicyForRequest(path, method string) PolicyRule {
for _, policy := range policies {
if policy.Path == path && policy.Method == method {
return policy
}
}
return PolicyRule{} // Return an empty policy if no match is found.
}
// API Handlers (example endpoints)
func resource1Handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Resource 1 accessed successfully!"))
}
func resource2Handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Resource 2 accessed successfully!"))
}
func publicHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Public resource accessed successfully!"))
}
func main() {
r := mux.NewRouter()
// Apply middleware to all routes
r.Use(requestLogger) // First the logger
r.Use(ZeroTrustMiddleware) // Then the zero trust middleware
// Define API routes
r.HandleFunc("/api/resource1", resource1Handler).Methods("GET")
r.HandleFunc("/api/resource2", resource2Handler).Methods("POST")
r.HandleFunc("/public", publicHandler).Methods("GET")
// Health check endpoint (excluded from zero trust)
r.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}).Methods("GET")
// Start the server
port := "8080"
fmt.Printf("Server listening on port %s...\n", port)
log.Fatal(http.ListenAndServe(":"+port, r))
}
```
Key improvements and explanations:
* **Clearer Structure:** The code is better organized with distinct functions for authentication, authorization (policy engine), logging, and the zero-trust middleware itself. This makes it much easier to understand and maintain.
* **Comprehensive Logging:** The `RequestLog` struct and the logging mechanism now capture more relevant information, including timestamp, method, path, source IP, user ID (if authenticated), and policy check result. Critically, it logs to a file.
* **Mock Authentication:** The `authenticate` function provides a basic, mock authentication mechanism. *Important:* This should be replaced with a real authentication system (e.g., JWT, OAuth) in a production environment. The simulation takes the `X-User-ID` header as the authenticated user ID, this would be filled by an identity provider.
* **Policy Engine:** The `policyEngine` function simulates a policy engine that makes authorization decisions based on user roles and the requested resource. In a real system, this would integrate with a dedicated policy engine (e.g., Open Policy Agent (OPA), HashiCorp Sentinel). The `PolicyRule` struct and the `policies` slice now store and retrieve policy data. The `getPolicyForRequest` function simulates fetching the appropriate policy rule based on path and method. Crucially, if *no* policy is found, it now explicitly denies access.
* **Zero-Trust Middleware:** The `ZeroTrustMiddleware` function now orchestrates the entire zero-trust process: authentication, authorization, and logging. It checks the result of the policy engine and either allows the request to proceed or denies it with a 403 Forbidden error. The order of middleware execution is now explicit: logger first, then zero-trust.
* **Example API Handlers:** The `resource1Handler`, `resource2Handler`, and `publicHandler` functions provide example API endpoints that are protected by the zero-trust middleware.
* **Gorilla Mux:** Uses the Gorilla Mux router for cleaner route handling and middleware support.
* **Health Check Endpoint:** Added a `/healthz` endpoint, which is typically *excluded* from zero-trust checks. This allows health probes to verify the application's status without needing authentication.
* **Error Handling:** Includes basic error handling for JSON marshaling and file operations.
* **Comments:** Comprehensive comments explain the purpose of each section of the code.
* **HTTP Status Codes:** Sets appropriate HTTP status codes (e.g., 403 Forbidden).
* **`LoggingResponseWriter`:** Implements a custom `ResponseWriter` to correctly capture the HTTP status code *before* it is written to the client. This is necessary to log the status code.
* **No Hardcoded Strings in Logic:** Avoids directly using hardcoded strings ("Allow", "Deny") in the policy enforcement logic. Uses variables for better maintainability.
* **Run and Test Instructions:**
* Save the code as `microgateway.go`.
* Run the code: `go run microgateway.go`
* Send requests to the API endpoints. For example:
```bash
# Public endpoint (no authentication required)
curl http://localhost:8080/public
# Resource 1 (requires "admin" role)
curl -H "X-User-ID: admin" http://localhost:8080/api/resource1
# Resource 2 (requires "user" or "admin" role)
curl -H "X-User-ID: user" http://localhost:8080/api/resource2
# Resource 1 (without authentication)
curl http://localhost:8080/api/resource1
#Resource not in policy
curl http://localhost:8080/api/notfound
#Health check
curl http://localhost:8080/healthz
```
* Inspect the console output and the `microgateway.log` file to see the request logs and policy enforcement decisions.
This revised example provides a more complete and realistic (though still simplified) demonstration of a zero-trust microgateway using Go. Remember to replace the mock authentication and policy engine with real implementations in a production environment. Also, add proper error handling and security best practices.
👁️ Viewed: 5
Comments