Files
notifier/docs/CORS_KUBERNETES_GUIDE.md

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:

  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

// 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):

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:

  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:
    kubectl rollout restart deployment notifier
    

Quick Reference

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.