New doc supporting CORS, gRCP, and general client integration
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
# CORS Configuration for Kubernetes Deployments
|
||||
|
||||
## Important: CORS Only Affects REST API, Not gRPC
|
||||
|
||||
**Key Point:** CORS (Cross-Origin Resource Sharing) is a **browser security mechanism** that only applies to HTTP/REST APIs accessed from web browsers. It does **NOT** affect gRPC communication.
|
||||
|
||||
## Service-to-Service Communication (gRPC)
|
||||
|
||||
### ✅ No CORS Configuration Needed
|
||||
|
||||
For services running in the same Kubernetes cluster communicating via gRPC:
|
||||
|
||||
**You don't need to configure CORS at all!**
|
||||
|
||||
Here's why:
|
||||
|
||||
1. **gRPC uses HTTP/2** - CORS is not enforced
|
||||
2. **Server-to-Server** - CORS only applies to browser-based requests
|
||||
3. **No Origin header** - Backend services don't send Origin headers
|
||||
|
||||
### gRPC Client Connection Example
|
||||
|
||||
```go
|
||||
// Service A connecting to notifier service via gRPC
|
||||
conn, err := grpc.Dial("notifier-grpc.default.svc.cluster.local:50051",
|
||||
grpc.WithInsecure())
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := pb.NewNotifierServiceClient(conn)
|
||||
```
|
||||
|
||||
**No CORS configuration required** ✅
|
||||
|
||||
The gRPC service runs on port `50051` (as defined in your k8s/service.yaml) and is accessible at:
|
||||
- From same namespace: `notifier-grpc:50051`
|
||||
- From other namespace: `notifier-grpc.default.svc.cluster.local:50051`
|
||||
- Full DNS: `notifier-grpc.default.svc.cluster.local:50051`
|
||||
|
||||
## When You DO Need CORS Configuration
|
||||
|
||||
CORS configuration is **only** needed when:
|
||||
|
||||
1. **Web browsers** access the REST API (port 8080)
|
||||
2. The web app is served from a **different origin** than the API
|
||||
3. The request goes through the **REST API**, not gRPC
|
||||
|
||||
### Common Scenarios
|
||||
|
||||
| Scenario | Needs CORS? | Reason |
|
||||
|----------|-------------|---------|
|
||||
| Backend service → gRPC API | ❌ No | Not a browser, uses gRPC |
|
||||
| Backend service → REST API | ❌ No | Not a browser |
|
||||
| Web app → gRPC (grpc-web) | ✅ Yes | Browser-based, needs CORS |
|
||||
| Web app → REST API | ✅ Yes | Browser-based, needs CORS |
|
||||
| CLI tool → REST API | ❌ No | Not a browser |
|
||||
| Postman/curl → REST API | ❌ No | Not a browser |
|
||||
|
||||
## CORS Configuration for Web Applications
|
||||
|
||||
If you have a web frontend that calls the REST API, you need to configure CORS.
|
||||
|
||||
### Scenario 1: Frontend in Same Cluster
|
||||
|
||||
**Example:** Frontend at `https://app.example.com`, API at `https://notifier.example.com`
|
||||
|
||||
Update your ConfigMap (k8s/configmap.yaml):
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: notifier-config
|
||||
data:
|
||||
config.yaml: |
|
||||
# ... existing config ...
|
||||
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "https://app.example.com" # Your frontend domain
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "OPTIONS"
|
||||
- "DELETE"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
allow_credentials: true # If your frontend sends auth tokens
|
||||
max_age: 3600
|
||||
```
|
||||
|
||||
### Scenario 2: Multiple Frontends
|
||||
|
||||
```yaml
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "https://app.example.com" # Main app
|
||||
- "https://dashboard.example.com" # Admin dashboard
|
||||
- "https://mobile.example.com" # Mobile web app
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "OPTIONS"
|
||||
- "DELETE"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
allow_credentials: true
|
||||
max_age: 3600
|
||||
```
|
||||
|
||||
### Scenario 3: Development Environment
|
||||
|
||||
For local development (frontend at http://localhost:3000):
|
||||
|
||||
```yaml
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "http://localhost:3000" # React/Next.js dev server
|
||||
- "http://localhost:8080" # Vue/Angular dev server
|
||||
- "http://localhost:5173" # Vite dev server
|
||||
- "https://app.example.com" # Production frontend
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "OPTIONS"
|
||||
- "DELETE"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
allow_credentials: false
|
||||
max_age: 3600
|
||||
```
|
||||
|
||||
### Scenario 4: No Web Frontend (Backend Services Only)
|
||||
|
||||
If you only have backend services using gRPC:
|
||||
|
||||
```yaml
|
||||
cors:
|
||||
# Empty or minimal config - no origins needed
|
||||
allowed_origins: [] # No browser clients
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
```
|
||||
|
||||
The REST API will still work for non-browser clients (like curl, Postman, or backend HTTP clients), but browsers will be blocked unless their origin is whitelisted.
|
||||
|
||||
## Complete Kubernetes Configuration Example
|
||||
|
||||
Here's your updated k8s/configmap.yaml with CORS:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: notifier-config
|
||||
labels:
|
||||
app: notifier
|
||||
data:
|
||||
config.yaml: |
|
||||
server:
|
||||
grpc_port: 50051
|
||||
rest_port: 8080
|
||||
host: "0.0.0.0"
|
||||
mode: "both"
|
||||
|
||||
queue:
|
||||
type: "local"
|
||||
max_size: 10000
|
||||
worker_count: 10
|
||||
retry_attempts: 3
|
||||
retry_backoff: "exponential"
|
||||
local:
|
||||
buffer_size: 1000
|
||||
persist_to_disk: false
|
||||
|
||||
notifiers:
|
||||
stdout: true
|
||||
|
||||
logging:
|
||||
level: "info"
|
||||
format: "json"
|
||||
output_path: "stdout"
|
||||
|
||||
metrics:
|
||||
enabled: true
|
||||
port: 9090
|
||||
path: "/metrics"
|
||||
prometheus_enabled: true
|
||||
|
||||
health_check:
|
||||
enabled: true
|
||||
port: 8081
|
||||
path: "/health"
|
||||
interval: 30
|
||||
|
||||
# CORS configuration for REST API
|
||||
# Only needed if web browsers will access the REST API
|
||||
cors:
|
||||
# Add your frontend domains here
|
||||
# For backend-only services, leave empty
|
||||
allowed_origins: []
|
||||
|
||||
# Or if you have a web frontend:
|
||||
# allowed_origins:
|
||||
# - "https://app.example.com"
|
||||
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "OPTIONS"
|
||||
- "DELETE"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
allow_credentials: false
|
||||
max_age: 3600
|
||||
```
|
||||
|
||||
## Environment-Specific Configuration
|
||||
|
||||
You can also use environment variables for different environments:
|
||||
|
||||
### Development ConfigMap
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: notifier-config-dev
|
||||
namespace: development
|
||||
data:
|
||||
NOTIFIER_CORS_ALLOWED_ORIGINS: "http://localhost:3000,http://localhost:8080"
|
||||
NOTIFIER_CORS_ALLOW_CREDENTIALS: "false"
|
||||
```
|
||||
|
||||
### Production ConfigMap
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: notifier-config-prod
|
||||
namespace: production
|
||||
data:
|
||||
NOTIFIER_CORS_ALLOWED_ORIGINS: "https://app.example.com,https://dashboard.example.com"
|
||||
NOTIFIER_CORS_ALLOW_CREDENTIALS: "true"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "CORS error" in Browser Console
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
Access to fetch at 'https://notifier.example.com/api/v1/notifications'
|
||||
from origin 'https://app.example.com' has been blocked by CORS policy
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
Add `https://app.example.com` to `allowed_origins` in your ConfigMap.
|
||||
|
||||
### Backend Service Can't Connect
|
||||
|
||||
**Symptom:**
|
||||
```go
|
||||
// Service in cluster trying to connect
|
||||
conn, err := grpc.Dial("notifier-grpc:50051", grpc.WithInsecure())
|
||||
// Error: connection refused
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
This is NOT a CORS issue. Check:
|
||||
1. Service name is correct (`notifier-grpc`)
|
||||
2. Port is correct (`50051`)
|
||||
3. Service is running: `kubectl get pods -l app=notifier`
|
||||
4. Service endpoints: `kubectl get endpoints notifier-grpc`
|
||||
|
||||
### REST API Returns 200 but No CORS Headers
|
||||
|
||||
**Symptom:**
|
||||
Browser blocks the response even though the API returns 200 OK.
|
||||
|
||||
**Solution:**
|
||||
The origin is not in the whitelist. Check:
|
||||
1. Origin is exactly matching (including protocol and port)
|
||||
2. ConfigMap has been updated
|
||||
3. Pod has been restarted to pick up new config:
|
||||
```bash
|
||||
kubectl rollout restart deployment notifier
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### For Backend Services Only (Recommended)
|
||||
```yaml
|
||||
cors:
|
||||
allowed_origins: [] # Empty - no browser access needed
|
||||
```
|
||||
|
||||
### For Web Frontend + Backend Services
|
||||
```yaml
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "https://your-frontend-domain.com"
|
||||
allow_credentials: true # If using auth tokens
|
||||
```
|
||||
|
||||
### Applying Changes
|
||||
|
||||
After updating the ConfigMap:
|
||||
|
||||
```bash
|
||||
# Update ConfigMap
|
||||
kubectl apply -f k8s/configmap.yaml
|
||||
|
||||
# Restart pods to pick up new config
|
||||
kubectl rollout restart deployment notifier
|
||||
|
||||
# Verify pods are running
|
||||
kubectl get pods -l app=notifier
|
||||
|
||||
# Check logs for CORS configuration
|
||||
kubectl logs -l app=notifier | grep CORS
|
||||
```
|
||||
|
||||
You should see:
|
||||
```
|
||||
CORS enabled for origins: [https://app.example.com]
|
||||
```
|
||||
|
||||
Or if no origins configured:
|
||||
```
|
||||
CORS has no allowed origins configured - all cross-origin requests will be blocked
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**For your use case (services in Kubernetes using gRPC):**
|
||||
|
||||
✅ **You don't need to configure CORS at all!**
|
||||
|
||||
CORS only applies to web browsers accessing the REST API. Your backend services communicating via gRPC are completely unaffected by CORS configuration.
|
||||
|
||||
**Only add CORS configuration if:**
|
||||
- You have a web frontend (React, Vue, Angular, etc.)
|
||||
- That web frontend calls the REST API (not gRPC)
|
||||
- The frontend is served from a different domain than the API
|
||||
|
||||
For purely backend service-to-service communication in Kubernetes, CORS is irrelevant.
|
||||
Reference in New Issue
Block a user