8.6 KiB
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:
- gRPC uses HTTP/2 - CORS is not enforced
- Server-to-Server - CORS only applies to browser-based requests
- No Origin header - Backend services don't send Origin headers
gRPC Client Connection Example
// 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:
- Web browsers access the REST API (port 8080)
- The web app is served from a different origin than the API
- 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):
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
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):
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:
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:
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
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
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:
// 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:
- Service name is correct (
notifier-grpc) - Port is correct (
50051) - Service is running:
kubectl get pods -l app=notifier - 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:
- Origin is exactly matching (including protocol and port)
- ConfigMap has been updated
- Pod has been restarted to pick up new config:
kubectl rollout restart deployment notifier
Quick Reference
For Backend Services Only (Recommended)
cors:
allowed_origins: [] # Empty - no browser access needed
For Web Frontend + Backend Services
cors:
allowed_origins:
- "https://your-frontend-domain.com"
allow_credentials: true # If using auth tokens
Applying Changes
After updating the ConfigMap:
# 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.