license: Add MIT license

This commit is contained in:
Björn Benouarets
2026-02-05 23:59:17 +01:00
parent 30adf0c701
commit 137be3e1e0
8 changed files with 611 additions and 295 deletions

View File

@@ -5,40 +5,40 @@
The SecNex API Gateway follows a modular architecture with clear separation of concerns. The system is built using the chi/v5 HTTP router and implements a middleware pipeline pattern. The SecNex API Gateway follows a modular architecture with clear separation of concerns. The system is built using the chi/v5 HTTP router and implements a middleware pipeline pattern.
``` ```
┌──────────────────────────────────────────────────────────── ┌────────────────────────────────────────────────────────────┐
Client Request │ │ Client Request
└─────────────────────────┬────────────────────────────────── └─────────────────────────┬──────────────────────────────────┘
┌──────────────────────────────────────────────────────────── ┌────────────────────────────────────────────────────────────┐
Gateway (chi Router) │ │ Gateway (chi Router)
│ ┌──────────────────────────────────────────────────────┐ │ │ ┌──────────────────────────────────────────────────────┐ │
│ │ Middleware Pipeline │ │ │ │ Global Middleware Pipeline │ │
│ │ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ │ │ │ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ │
│ │ │ Request ID │→ │ Real IP │→ │ Logger │ │ │ │ │ │ Request ID │→ │ Real IP │→ │ Logger │ │ │
│ │ └────────────┘ └────────────┘ └──────────────┘ │ │ │ │ └────────────┘ └────────────┘ └──────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │ │ └──────────────────────────────────────────────────────┘ │
└─────────────────────────┬────────────────────────────────── └─────────────────────────┬──────────────────────────────────┘
┌──────────────────────────────────────────────────────────── ┌────────────────────────────────────────────────────────────┐
│ Route Handler │ Route Handler │
│ ┌──────────────────────────────────────────────────────┐ │ │ ┌──────────────────────────────────────────────────────┐ │
│ │ Per-Route Middleware Chain │ │ │ │ Per-Route Middleware Chain │ │
│ │ ┌────────────┐ ┌─────────┐ ┌──────────────┐ │ │ │ │ ┌────────────┐ ┌──────────────┐ │ │
│ │ │ Strip │→ │ WAF │→ │ Auth │ │ │ │ │ Strip │→ │ Reverse │ │ │
│ │ │ Prefix │ │ Filter │ │ Middleware │ │ │ │ │ Prefix │ │ Proxy │ │ │
│ │ └────────────┘ └─────────┘ └──────────────┘ │ │ │ │ └────────────┘ └──────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │ │ └──────────────────────────────────────────────────────┘ │
└─────────────────────────┬────────────────────────────────── └─────────────────────────┬──────────────────────────────────┘
┌──────────────────────────────────────────────────────────── ┌────────────────────────────────────────────────────────────┐
│ Reverse Proxy (httputil.ReverseProxy) │ Reverse Proxy (httputil.ReverseProxy) │
│ │ │ │ │
│ ▼ │ ▼ │
│ Backend Service │ Backend Service │
└──────────────────────────────────────────────────────────── └────────────────────────────────────────────────────────────┘
``` ```
## Component Architecture ## Component Architecture
@@ -51,18 +51,17 @@ app/
├── config/ # Configuration management ├── config/ # Configuration management
│ ├── config.go # Config interface │ ├── config.go # Config interface
│ ├── file.go # File-based config loader │ ├── file.go # File-based config loader
│ └── types.go # Configuration type definitions │ └── database.go # Database configuration
├── server/ # Core server components ├── server/ # Core server components
│ ├── gateway.go # Main gateway server │ ├── gateway.go # Main gateway server
│ ├── routes.go # Route handler creation │ ├── routes.go # Route registration
── proxy.go # Host-based virtual hosting ── api.go # API definitions
│ ├── host.go # Host definitions
│ └── target.go # Target (backend) definitions
├── middlewares/ # HTTP middleware ├── middlewares/ # HTTP middleware
│ ├── auth.go # Authentication middleware │ ├── host.go # Host logging middleware
│ └── waf.go # Web Application Firewall │ └── logger.go # Structured logging middleware
── handlers/ # Request handlers ── utils/ # Utility functions
│ └── route.go # Route handlers (placeholder)
└── res/ # HTTP responses
└── error.go # Error response utilities
``` ```
### Core Components ### Core Components
@@ -71,25 +70,39 @@ app/
The Gateway is the main server component that: The Gateway is the main server component that:
- Initializes the chi router - Initializes the chi router
- Applies global middleware (request_id, real_ip, logger) - Applies global middleware (request_id, real_ip, logger, host)
- Configures proxy directors for each API
- Registers route handlers - Registers route handlers
- Starts the HTTP server - Starts the HTTP server
#### Routes (`server/routes.go`) #### Routes (`server/routes.go`)
The Routes component creates handlers for each configured route: The Routes component handles:
1. Finds the matching API backend target - Creating route handlers from configuration
2. Creates a reverse proxy using `httputil.NewSingleHostReverseProxy` - Applying strip prefix middleware
3. Optionally strips prefix from the request path - Registering routes with chi router (method-agnostic)
4. Applies middleware chain: WAF → Auth - Connecting routes to API backends
#### Configuration (`config/`) #### API (`server/api.go`)
Configuration is loaded from YAML and provides: API definitions that:
- Gateway settings (host, port, features) - Link hosts to backend targets
- Route definitions with security policies - Implement `http.Handler` interface for proxying
- API backend targets - Delegate requests to the reverse proxy
- Proxy configurations for virtual hosting
#### Hosts (`server/host.go`)
Host definitions for:
- Virtual hosting support
- Domain-based routing
- Host header validation
#### Targets (`server/target.go`)
Target (backend) definitions that:
- Store backend service URLs
- Create `httputil.ReverseProxy` instances
- Handle proxy configuration
## Middleware Chain ## Middleware Chain
@@ -100,56 +113,56 @@ Applied to all requests via chi middleware:
| Feature | Description | | Feature | Description |
|---------|-------------| |---------|-------------|
| `request_id` | Adds unique request ID to context | | `request_id` | Adds unique request ID to context |
| `real_ip` | Determines the real client IP | | `real_ip` | Determines the real client IP from headers |
| `logger` | Logs HTTP requests | | `logger` | Logs HTTP requests with structured JSON output |
| `host` | Logs the host header for each request |
### Per-Route Middleware ### Per-Route Middleware
Applied in order to each route handler: Applied to each route handler:
1. **StripPrefix** - Removes specified prefix from request path before proxying 1. **StripPrefix** - Removes specified prefix from request path before proxying
2. **WAF** - Filters requests based on HTTP method
3. **Auth** - Validates authentication credentials
## Request Flow ## Request Flow
1. **Client Request** → Gateway receives HTTP request 1. **Client Request** → Gateway receives HTTP request
2. **Global Middleware** → Request ID, Real IP, Logging applied 2. **Global Middleware** → Request ID, Real IP, Host logging, Logger applied
3. **Route Matching** → Chi matches route pattern (e.g., `/api/v1/dev/*`) 3. **Route Matching** → Chi matches route pattern (e.g., `/api/v1/*`)
4. **Per-Route Middleware** → StripPrefix → WAF → Auth 4. **Per-Route Middleware** → StripPrefix (if enabled)
5. **Reverse Proxy** → Request forwarded to backend API 5. **Reverse Proxy** → Request forwarded to backend API
6. **Response** → Backend response returned to client 6. **Response** → Backend response returned to client
## Authentication Flow
The authentication middleware supports path-based filtering:
```
┌─────────────────────┐
│ Include Set? │
└──────────┬──────────┘
┌─────┴─────┐
│ Yes │ No
▼ ▼
┌─────────┐ ┌─────────────┐
│ Match │ │ Exclude │
│ Include?│ │ Set? │
└────┬────┘ └──────┬──────┘
│ │
┌──┴──┐ ┌──┴──┐
│Yes │No │Yes │No
▼ ▼ ▼ ▼
┌────┐┌────┐ ┌────┐┌────┐
│Auth││Skip│ │Skip││Auth│
└────┘└────┘ └────┘└────┘
```
## Configuration Flow ## Configuration Flow
1. Load `gateway.yaml` via `config.NewFileConfig()` 1. Load `gateway.yaml` via `config.NewFile()`
2. Parse YAML into `Configuration` struct 2. Parse YAML into `Configuration` struct
3. Create Gateway with configuration 3. Create Hosts from configuration
4. Create Routes from route definitions and API targets 4. Create Targets from configuration
5. Register handlers with chi router 5. Create APIs (linking Hosts to Targets)
6. Start HTTP server 6. Create Routes (linking Routes to APIs)
7. Initialize Gateway with all components
8. Configure proxy directors
9. Register routes with chi router
10. Start HTTP server
## Logging
The gateway uses structured JSON logging via `masterlog`:
- **HTTP Request Logging** - method, path, status, duration, host, IP
- **Gateway Events** - startup, route registration, proxy configuration
- **Sensitive Field Pseudonymization** - user_id, email, ip fields are pseudonymized
Example log output:
```json
{
"level": "info",
"msg": "HTTP Request",
"method": "GET",
"path": "/api/v1/users",
"status": 200,
"duration": "45ms",
"host": "localhost:8080",
"ip": "127.0.0.1:52342"
}
```

View File

@@ -12,33 +12,30 @@ gateway:
- request_id - request_id
- real_ip - real_ip
- logger - logger
- host
proxies: hosts:
- id: "proxy-id" - id: "host-001"
host: "example.com" name: "localhost"
target: "http://backend:3000" domain: "localhost:8080"
targets:
- id: "target-001"
name: "httpbin"
url: "https://httpbin.org"
apis: apis:
- id: "api-id" - id: "api-001"
target: "https://api.example.com" host: "host-001"
target: "target-001"
routes: routes:
- id: "route-id" - id: "route-001"
api: "api-001"
path: "/api/v1/*" path: "/api/v1/*"
strip_prefix: strip_prefix:
enabled: true enabled: true
prefix: "/api/v1" prefix: "/api/v1"
security:
auth:
enabled: true
type: "api_key"
header: "X-Api-Key"
path:
include: []
exclude: []
waf:
enabled: true
methods: ["GET", "POST"]
``` ```
## Sections ## Sections
@@ -61,37 +58,49 @@ Available global features:
|---------|-------------| |---------|-------------|
| `request_id` | Adds unique request ID to each request | | `request_id` | Adds unique request ID to each request |
| `real_ip` | Determines real client IP from headers | | `real_ip` | Determines real client IP from headers |
| `logger` | Logs all HTTP requests | | `logger` | Logs all HTTP requests with structured JSON |
| `host` | Logs the host header for each request |
### Proxies ### Hosts
Virtual hosting configuration for host-based routing. Virtual hosting configuration for domain-based routing.
| Field | Type | Description | | Field | Type | Description |
|-------|------|-------------| |-------|------|-------------|
| `id` | string | Unique proxy identifier | | `id` | string | Unique host identifier (referenced by APIs) |
| `host` | string | Domain/host name to match | | `name` | string | Human-readable name |
| `target` | string | Backend URL to proxy to | | `domain` | string | Domain/host name to match |
### Targets
Backend service definitions referenced by APIs.
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique target identifier (referenced by APIs) |
| `name` | string | Human-readable name |
| `url` | string | Backend URL to proxy to |
### APIs ### APIs
Backend service definitions referenced by routes. Links hosts to backend targets.
| Field | Type | Description | | Field | Type | Description |
|-------|------|-------------| |-------|------|-------------|
| `id` | string | Unique API identifier (referenced by routes) | | `id` | string | Unique API identifier (referenced by routes) |
| `target` | string | Backend URL | | `host` | string | Host ID to use |
| `target` | string | Target ID to proxy to |
### Routes ### Routes
Route definitions with security policies. Route definitions with path patterns and prefix stripping.
| Field | Type | Description | | Field | Type | Description |
|-------|------|-------------| |-------|------|-------------|
| `id` | string | Unique route identifier (must match API ID) | | `id` | string | Unique route identifier |
| `api` | string | API ID to use for this route |
| `path` | string | Chi route pattern (e.g., `/api/v1/*`) | | `path` | string | Chi route pattern (e.g., `/api/v1/*`) |
| `strip_prefix` | object | Prefix stripping configuration | | `strip_prefix` | object | Prefix stripping configuration |
| `security` | object | Security policies (auth, WAF) |
#### Strip Prefix #### Strip Prefix
@@ -100,91 +109,112 @@ Route definitions with security policies.
| `enabled` | boolean | Enable prefix stripping | | `enabled` | boolean | Enable prefix stripping |
| `prefix` | string | Prefix to remove from path | | `prefix` | string | Prefix to remove from path |
#### Security
##### Authentication
| Field | Type | Description |
|-------|------|-------------|
| `enabled` | boolean | Enable authentication |
| `type` | string | Auth type (`api_key`, `session`, etc.) |
| `header` | string | Header name to validate |
| `path` | object | Path-based filtering |
##### Auth Path Filtering
| Field | Type | Description |
|-------|------|-------------|
| `include` | array | Paths that require auth (empty = all) |
| `exclude` | array | Paths that skip auth |
**Include/Exclude Logic:**
- If `include` is set → only matching paths require auth
- If `include` is empty → all paths require auth except `exclude`
Wildcards (`*`) are supported in path patterns.
##### WAF (Web Application Firewall)
| Field | Type | Description |
|-------|------|-------------|
| `enabled` | boolean | Enable WAF |
| `methods` | array | Allowed HTTP methods (`["*"]` for all) |
## Example Configurations ## Example Configurations
### Public API (No Auth) ### Simple Proxy (No Prefix Stripping)
```yaml ```yaml
gateway:
host: "0.0.0.0"
port: 8080
features:
- logger
hosts:
- id: "host-001"
name: "localhost"
domain: "localhost:8080"
targets:
- id: "target-001"
name: "backend"
url: "https://api.example.com"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
routes: routes:
- id: "public-api" - id: "route-001"
path: "/public/*" api: "api-001"
strip_prefix: path: "/api/*"
enabled: true
prefix: "/public"
security:
auth:
enabled: false
waf:
enabled: true
methods: ["GET", "POST"]
``` ```
### Protected API with API Key **Request flow:**
- Client requests: `/api/users/123`
- Backend receives: `/api/users/123`
### Prefix Stripping
```yaml ```yaml
routes: routes:
- id: "protected-api" - id: "route-001"
api: "api-001"
path: "/api/v1/*" path: "/api/v1/*"
strip_prefix: strip_prefix:
enabled: true enabled: true
prefix: "/api/v1" prefix: "/api/v1"
security:
auth:
enabled: true
type: "api_key"
header: "X-Api-Key"
waf:
enabled: true
methods: ["*"]
``` ```
### Mixed Auth (Path-based) **Request flow:**
- Client requests: `/api/v1/users/123`
- Gateway strips: `/api/v1`
- Backend receives: `/users/123`
### Multiple Routes
```yaml ```yaml
routes: routes:
- id: "mixed-api" - id: "public-route"
api: "api-001"
path: "/public/*"
strip_prefix:
enabled: true
prefix: "/public"
- id: "api-route"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
```
### Multiple Backends
```yaml
hosts:
- id: "host-001"
name: "api-host"
domain: "api.example.com"
- id: "host-002"
name: "admin-host"
domain: "admin.example.com"
targets:
- id: "target-001"
name: "api-backend"
url: "https://api-backend.internal"
- id: "target-002"
name: "admin-backend"
url: "https://admin-backend.internal"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
- id: "api-002"
host: "host-002"
target: "target-002"
routes:
- id: "route-001"
api: "api-001"
path: "/api/*" path: "/api/*"
security: - id: "route-002"
auth: api: "api-002"
enabled: true path: "/admin/*"
header: "Authorization"
path:
include: ["/api/admin/*", "/api/users/*/profile"]
exclude: ["/api/health", "/api/public/*"]
waf:
enabled: true
methods: ["*"]
``` ```
## Configuration Loading ## Configuration Loading
@@ -192,7 +222,7 @@ routes:
The gateway loads configuration from a file path relative to the binary: The gateway loads configuration from a file path relative to the binary:
```go ```go
cfg, err := config.NewFileConfig("../gateway.yaml") cfg, err := config.NewFile("../gateway.yaml")
``` ```
For Docker deployments, mount the config file: For Docker deployments, mount the config file:
@@ -201,3 +231,16 @@ For Docker deployments, mount the config file:
volumes: volumes:
- ./gateway.yaml:/app/gateway.yaml:ro - ./gateway.yaml:/app/gateway.yaml:ro
``` ```
## Chi Route Patterns
The gateway uses chi/v5 routing patterns. Common patterns:
| Pattern | Matches | Example |
|---------|---------|---------|
| `/api/*` | `/api/` and any subpath | `/api/users`, `/api/users/123` |
| `/api/v1/*` | `/api/v1/` and any subpath | `/api/v1/users` |
| `/users/{id}` | `/users/` with any value | `/users/123` |
| `/files/*` | `/files/` and any subpath | `/files/doc.pdf` |
Note: `/*` matches zero or more path segments.

View File

@@ -4,7 +4,7 @@ Welcome to the official documentation for the SecNex API Gateway.
## Overview ## Overview
SecNex API Gateway is a high-performance, configurable API gateway built in Go. It provides reverse proxy capabilities with built-in security features including authentication and web application firewall (WAF) functionality. SecNex API Gateway is a high-performance, configurable API gateway built in Go. It provides reverse proxy capabilities with path-based routing, prefix stripping, and structured logging.
## Quick Start ## Quick Start
@@ -28,11 +28,11 @@ docker compose up -d
## Features ## Features
- **Reverse Proxy** Route requests to backend services - **Reverse Proxy** Route requests to backend services
- **Authentication** Header-based authentication (API key, session tokens) - **Path-based Routing** Configurable route patterns with chi/v5
- **WAF** Web Application Firewall with method filtering and IP-based access control - **Prefix Stripping** Remove path prefixes before proxying
- **Path-based Routing** Configurable route patterns with prefix stripping - **Host-based Routing** Virtual hosting support
- **Middleware Pipeline** Extensible middleware chain for custom logic - **Middleware Pipeline** Extensible middleware chain (request ID, real IP, logging)
- **Logging** Structured logging with sensitive field pseudonymization - **Logging** Structured JSON logging with sensitive field pseudonymization
## Health Check ## Health Check

View File

@@ -47,14 +47,13 @@ Response: `OK`
After configuring routes in `gateway.yaml`, make requests to the gateway: After configuring routes in `gateway.yaml`, make requests to the gateway:
```bash ```bash
# Example: Request to a route configured at /api/v1/dev/* # Example: Request to a route configured at /api/v1/*
curl http://localhost:8080/api/v1/dev/users curl http://localhost:8080/api/v1/users
# With API key authentication # All HTTP methods are supported
curl -H "X-Api-Key: your-key-here" http://localhost:8080/api/v1/dev/data curl -X POST http://localhost:8080/api/v1/data
curl -X PUT http://localhost:8080/api/v1/data/123
# With session authentication curl -X DELETE http://localhost:8080/api/v1/data/123
curl -H "Authorization: Bearer token" http://localhost:8080/api/v1/protected
``` ```
## Route Examples ## Route Examples
@@ -65,6 +64,7 @@ curl -H "Authorization: Bearer token" http://localhost:8080/api/v1/protected
```yaml ```yaml
routes: routes:
- id: "api" - id: "api"
api: "api-001"
path: "/api/v1/*" path: "/api/v1/*"
strip_prefix: strip_prefix:
enabled: true enabled: true
@@ -76,65 +76,57 @@ routes:
- Gateway strips: `/api/v1` - Gateway strips: `/api/v1`
- Backend receives: `/users/123` - Backend receives: `/users/123`
### Authentication Example ### Multiple Routes Example
**Configuration:** **Configuration:**
```yaml ```yaml
security: routes:
auth: - id: "public-route"
enabled: true api: "api-001"
type: "api_key" path: "/public/*"
header: "X-Api-Key" strip_prefix:
enabled: true
prefix: "/public"
- id: "api-route"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
``` ```
**Valid request:** **Requests:**
```bash ```bash
curl -H "X-Api-Key: secret123" http://localhost:8080/api/v1/data # Public route - backend receives /status
``` curl http://localhost:8080/public/status
**Invalid request (missing header):** # API route - backend receives /users
```bash curl http://localhost:8080/api/v1/users
curl http://localhost:8080/api/v1/data
# Returns: 401 Unauthorized
```
### WAF Method Filtering Example
**Configuration:**
```yaml
security:
waf:
enabled: true
methods: ["GET", "POST"]
```
**Allowed:**
```bash
curl -X GET http://localhost:8080/api/v1/data
curl -X POST http://localhost:8080/api/v1/data
```
**Blocked:**
```bash
curl -X DELETE http://localhost:8080/api/v1/data
# Returns: 403 Forbidden
``` ```
## Logging ## Logging
The gateway uses structured logging via `masterlog`. Logs include: The gateway uses structured JSON logging via `masterlog`. All HTTP requests are logged with:
- Request ID (if enabled) - Request ID (if enabled)
- Client IP (if real_ip enabled) - Client IP (if real_ip enabled)
- Request method and path - Request method and path
- Response status - Response status code
- Request duration
- Host header
**Example log output:** **Example log output:**
```json ```json
{ {
"level": "info", "level": "info",
"msg": "Registering route", "msg": "HTTP Request",
"path": "/api/v1/dev/*" "method": "GET",
"path": "/api/v1/users",
"status": 200,
"duration": "45ms",
"host": "localhost:8080",
"ip": "127.0.0.1:52342"
} }
``` ```
@@ -147,30 +139,116 @@ The gateway uses structured logging via `masterlog`. Logs include:
lsof -i :8080 lsof -i :8080
``` ```
2. Verify configuration file exists and is valid YAML 2. Verify configuration file exists and is valid YAML:
```bash
cat ../gateway.yaml
```
3. Check logs for detailed error messages 3. Check logs for detailed error messages
### 401 Unauthorized ### 404 Not Found
- Verify auth header is included - Verify the route path matches your request
- Check header name matches configuration - Check chi route pattern syntax (use `/*` for wildcards)
- Verify path is not excluded from auth - Ensure the route is registered (check startup logs)
### 403 Forbidden
- Check WAF method configuration
- Verify HTTP method is allowed
### Backend connection errors ### Backend connection errors
- Verify API target URL is correct - Verify target URL is correct in configuration
- Check backend service is running - Check backend service is running and accessible
- Verify network connectivity - Verify network connectivity from gateway to backend
- Check DNS resolution if using domain names
### Route not matching
- Ensure request path matches the route pattern exactly
- Remember that `/*` matches zero or more path segments
- Check that multiple routes don't have conflicting patterns
## Performance Considerations ## Performance Considerations
- The gateway uses Go's `httputil.ReverseProxy` for efficient proxying - The gateway uses Go's `httputil.ReverseProxy` for efficient proxying
- HTTP/2 is supported when both client and backend support it
- Keep-alive connections are reused by default - Keep-alive connections are reused by default
- Consider connection pooling for high-traffic scenarios - Consider connection pooling for high-traffic scenarios
- Monitor memory usage with high request volumes - Monitor memory usage with high request volumes
## Common Patterns
### API Versioning
```yaml
routes:
- id: "v1-api"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
- id: "v2-api"
api: "api-001"
path: "/api/v2/*"
strip_prefix:
enabled: true
prefix: "/api/v2"
```
### Microservices Routing
```yaml
targets:
- id: "user-service"
name: "User Service"
url: "https://user-service.internal"
- id: "order-service"
name: "Order Service"
url: "https://order-service.internal"
apis:
- id: "user-api"
host: "host-001"
target: "user-service"
- id: "order-api"
host: "host-001"
target: "order-service"
routes:
- id: "users-route"
api: "user-api"
path: "/users/*"
strip_prefix:
enabled: true
prefix: "/users"
- id: "orders-route"
api: "order-api"
path: "/orders/*"
strip_prefix:
enabled: true
prefix: "/orders"
```
### External API Proxy
```yaml
targets:
- id: "external-api"
name: "External API"
url: "https://api.external.com"
apis:
- id: "external"
host: "host-001"
target: "external-api"
routes:
- id: "external-proxy"
api: "external"
path: "/proxy/external/*"
strip_prefix:
enabled: true
prefix: "/proxy/external"
```
Request to `/proxy/external/users` becomes `/users` on the external API.

129
CLAUDE.md
View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview ## Project Overview
SecNex API Gateway is a Go-based API gateway built with chi/v5 routing. It acts as a reverse proxy with configurable security features including authentication and WAF (Web Application Firewall) capabilities. SecNex API Gateway is a Go-based API gateway built with chi/v5 routing. It acts as a reverse proxy with configurable features including path-based routing, prefix stripping, and structured logging.
## Build and Run ## Build and Run
@@ -23,77 +23,79 @@ The gateway loads configuration from `gateway.yaml` (sibling to the `app/` direc
app/ app/
├── main.go # Entry point ├── main.go # Entry point
├── config/ # Configuration loading and types ├── config/ # Configuration loading and types
├── server/ # Gateway, routes, and proxy setup ├── server/ # Gateway, routes, hosts, targets, and API definitions
├── middlewares/ # Auth and WAF middleware ├── middlewares/ # HTTP middleware (logger, host)
── handlers/ # Route handlers (currently empty) ── utils/ # Utility functions
└── res/ # HTTP error responses
``` ```
### Core Components ### Core Components
**Gateway (`server/gateway.go`)** **Gateway (`server/gateway.go`)**
- Main server using chi/v5 router - Main server using chi/v5 router
- Dynamically enables features via config: `request_id`, `real_ip`, `logger` - Dynamically enables features via config: `request_id`, `real_ip`, `logger`, `host`
- Configures proxy directors for each API
- Registers route handlers and starts HTTP server - Registers route handlers and starts HTTP server
**Routes (`server/routes.go`)** **Routes (`server/routes.go`)**
- Creates handlers for each route configured in `gateway.yaml` - Creates handlers for each route configured in `gateway.yaml`
- For each route: - For each route:
1. Finds the matching API backend target 1. Finds the matching API backend target
2. Creates a reverse proxy using `httputil.NewSingleHostReverseProxy` 2. Creates a handler with optional strip prefix middleware
3. Optionally strips prefix from the request path 3. Registers with chi router using `r.Handle()` (method-agnostic)
4. Applies WAF middleware (method filtering)
5. Applies Auth middleware (header-based authentication)
**Proxy (`server/proxy.go`)** **API (`server/api.go`)**
- Host-based virtual hosting proxy (separate from routes) - Links hosts to backend targets
- Maps `proxy.host` to a backend target - Implements `http.Handler` interface
- Currently unused in main.go but available - Delegates to the reverse proxy
**Configuration Flow** **Hosts (`server/host.go`)**
1. `config.NewFileConfig("../gateway.yaml")` loads YAML - Host definitions for virtual hosting
- Domain-based routing support
**Targets (`server/target.go`)**
- Backend service definitions
- Creates `httputil.NewSingleHostReverseProxy` instances
### Configuration Flow
1. `config.NewFile("../gateway.yaml")` loads YAML
2. `server.NewGateway(cfg)` creates gateway with chi router 2. `server.NewGateway(cfg)` creates gateway with chi router
3. `server.NewRoutes(cfg.GetRoutes(), cfg.GetApis())` creates handlers 3. `server.NewRoutes(cfg, apis)` creates route handlers
4. `gateway.SetRoutes(routes)` registers handlers 4. `routes.Register(g.router)` registers handlers
5. Gateway starts HTTP server
### Middleware Chain (per route) ### Middleware Chain
Middlewares are applied in order via decorator pattern in `server/routes.go:createHandlers`: **Global Middleware** (applied via chi middleware):
1. StripPrefix (if enabled) - removes prefix from path before proxying 1. RequestID - adds unique request ID
2. WAF - filters by HTTP method (or `["*"]` for all methods) 2. RealIP - determines real client IP
3. Auth - validates presence of auth header 3. Logger - structured JSON logging
4. Host - logs host header
**Per-Route Middleware** (applied in order):
1. StripPrefix - removes prefix from path before proxying (if enabled)
### Key Implementation Details ### Key Implementation Details
**Auth Middleware** (`middlewares/auth.go`) **Strip Prefix Middleware** (`server/routes.go`)
- Checks for presence of configured header (e.g., `X-Api-Key`, `Authorization`) - Removes specified prefix from request path before proxying
- Path-based filtering via `include`/`exclude` patterns: - Ensures resulting path starts with `/`
- If `include` is set → only those paths require auth
- If `include` is empty → all paths require auth except `exclude` patterns
- Supports wildcard patterns (`*`) in path matching
- Deletes the auth header before forwarding to backend
**WAF Configuration** (`middlewares/waf.go`)
- Currently only implements HTTP method filtering
- `methods: ["*"]` allows all methods
- `methods: ["GET"]` only allows GET
**Route Handler Pattern** **Route Handler Pattern**
Each route in `gateway.yaml` must have: Each route in `gateway.yaml` must have:
- `id` - must match an API entry - `id` - unique route identifier
- `path` - chi route pattern (e.g., `/api/v1/dev/*`) - `api` - API ID to use (references an API entry)
- `path` - chi route pattern (e.g., `/api/v1/*`)
- `strip_prefix` - optional prefix removal - `strip_prefix` - optional prefix removal
- `security.auth` - optional auth middleware
- `security.waf` - optional method filtering
### Module Structure ### Module Structure
The codebase uses an internal Go module: The codebase uses an internal Go module:
``` ```
git.secnex.io/secnex/gateway git.secnex.io/secnex/api-gateway
``` ```
Internal imports use this path (e.g., `git.secnex.io/secnex/gateway/config`). Internal imports use this path (e.g., `git.secnex.io/secnex/api-gateway/config`).
### Logging ### Logging
@@ -101,3 +103,48 @@ Uses `git.secnex.io/secnex/masterlog` with:
- JSON encoder - JSON encoder
- Pseudonymizer for sensitive fields (`user_id`, `email`, `ip`) - Pseudonymizer for sensitive fields (`user_id`, `email`, `ip`)
- Debug-level logging enabled in main.go - Debug-level logging enabled in main.go
- Custom `LoggerMiddleware` for structured HTTP request logging
### Dependencies
- `github.com/go-chi/chi/v5` - HTTP router
- `git.secnex.io/secnex/masterlog` - Structured logging
- `go.yaml.in/yaml/v3` - YAML configuration parsing
- `gorm.io/gorm` - Database ORM (for future use)
- `gorm.io/driver/postgres` - PostgreSQL driver (for future use)
## Configuration Reference
```yaml
gateway:
host: "0.0.0.0"
port: 8080
features:
- request_id
- real_ip
- logger
- host
hosts:
- id: "host-001"
name: "localhost"
domain: "localhost:8080"
targets:
- id: "target-001"
name: "httpbin"
url: "https://httpbin.org"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
routes:
- id: "route-001"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
```

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 SecNex GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

103
README.md
View File

@@ -1 +1,104 @@
# SecNex API Gateway # SecNex API Gateway
![Go Version](https://img.shields.io/badge/Go-1.25.5-00ADD8?style=flat&logo=go)
![License](https://img.shields.io/badge/License-MIT-blue?style=flat)
A high-performance, configurable API gateway built in Go with chi/v5 routing. Provides reverse proxy capabilities with path-based routing, prefix stripping, and structured logging.
## Features
- **Reverse Proxy** - Route requests to backend services via HTTP reverse proxy
- **Path-based Routing** - Configurable route patterns with chi/v5 router
- **Prefix Stripping** - Remove path prefixes before forwarding to backends
- **Host-based Routing** - Virtual hosting support via host headers
- **Middleware Pipeline** - Extensible middleware chain (request ID, real IP, logging)
- **Structured Logging** - JSON logging with sensitive field pseudonymization
## Quick Start
```bash
# Clone the repository
git clone https://git.secnex.io/secnex/gateway.git
cd gateway/app
# Run the gateway
go run main.go
```
The gateway loads configuration from `../gateway.yaml` and starts on the configured host/port (default: `0.0.0.0:8080`).
## Health Check
```bash
curl http://localhost:8080/_/health
```
Returns `200 OK` when the gateway is running.
## Documentation
- [Documentation](https://git.secnex.io/secnex/gateway/-/tree/main/.docs)
- [Architecture](https://git.secnex.io/secnex/gateway/-/blob/main/.docs/architecture.md)
- [Configuration](https://git.secnex.io/secnex/gateway/-/blob/main/.docs/configuration.md)
- [Usage](https://git.secnex.io/secnex/gateway/-/blob/main/.docs/usage.md)
- [Development](https://git.secnex.io/secnex/gateway/-/blob/main/.docs/development.md)
- [Deployment](https://git.secnex.io/secnex/gateway/-/blob/main/.docs/deployment.md)
## Example Configuration
```yaml
gateway:
host: "0.0.0.0"
port: 8080
features:
- request_id
- real_ip
- logger
- host
hosts:
- id: "host-001"
name: "localhost"
domain: "localhost:8080"
targets:
- id: "target-001"
name: "httpbin"
url: "https://httpbin.org"
apis:
- id: "api-001"
host: "host-001"
target: "target-001"
routes:
- id: "route-001"
api: "api-001"
path: "/api/v1/*"
strip_prefix:
enabled: true
prefix: "/api/v1"
```
## Project Structure
```
app/
├── main.go # Entry point
├── config/ # Configuration loading
├── server/ # Gateway, routes, proxy
├── middlewares/ # HTTP middleware
└── utils/ # Utility functions
```
## Requirements
- Go 1.25.5 or later
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
Made with ❤️ by [SecNex](https://secnex.io)

View File

@@ -2,25 +2,36 @@ gateway:
host: "0.0.0.0" host: "0.0.0.0"
port: 8080 port: 8080
features: features:
- host
- request_id - request_id
- real_ip - real_ip
- logger - logger
proxies: hosts:
- id: "proxy-id" - id: "host-001"
host: "example.com" name: "host-001"
target: "http://backend:3000" domain: "localhost:8080"
- id: "host-002"
name: "host-002"
domain: "api.deinserver.co"
targets:
- id: "target-001"
name: "target-001"
url: "https://httpbin.org"
apis: apis:
- id: "api-id" - id: "api-001"
target: "https://api.example.com" host: "host-001"
target: "target-001"
routes: routes:
- id: "route-id" - id: "route-001"
path: "/api/v1/*" api: "api-001"
path: "/api/v1/public/*"
strip_prefix: strip_prefix:
enabled: true enabled: true
prefix: "/api/v1" prefix: "/api/v1/public"
security: security:
auth: auth:
enabled: true enabled: true