Sidecar Pattern Deep Dive¶
Understanding the sidecar pattern and how it applies to OAuth2 authentication.
What is the Sidecar Pattern?¶
The sidecar pattern is a microservices design pattern where auxiliary functionality is deployed alongside the main application container in the same pod. The sidecar container extends and enhances the main container's behavior.
graph TB
subgraph "Traditional Deployment"
A[Application
with embedded auth]
end
subgraph "Sidecar Pattern"
B[Application
pure business logic]
C[Sidecar
auth logic]
B <--> C
end
style B fill:#10b981,stroke:#333,stroke-width:2px,color:#fff
style C fill:#4c51bf,stroke:#333,stroke-width:2px,color:#fff
Benefits for Authentication¶
1. Separation of Concerns¶
Your application focuses on business logic, while the sidecar handles authentication.
Without sidecar:
# Your app code mixed with auth logic
from flask import Flask, session, redirect
import oauth_lib
app = Flask(__name__)
@app.route('/')
def index():
if not session.get('user'):
return redirect('/login')
# Business logic here
return f"Hello {session['user']}"
@app.route('/login')
def login():
# OAuth dance...
return oauth_lib.authorize()
With sidecar:
# Your app code - pure business logic
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
# User is already authenticated by sidecar
user = request.headers.get('X-Auth-Request-User')
return f"Hello {user}"
2. Language Agnostic¶
The sidecar works with any programming language or framework.
graph TB
subgraph Applications
A[Python/Flask]
B[Node.js/Express]
C[Go/net/http]
D[Java/Spring]
E[.NET/ASP.NET]
end
subgraph "oauth2-proxy Sidecar"
F[Handles OAuth for ALL]
end
A -.->|Works with| F
B -.->|Works with| F
C -.->|Works with| F
D -.->|Works with| F
E -.->|Works with| F
style F fill:#4c51bf,stroke:#333,stroke-width:3px,color:#fff
3. Easy Updates¶
Update authentication logic without changing application code.
graph LR
A[Update oauth2-proxy
image version] --> B[Restart pod]
B --> C[New auth features
without app changes]
style C fill:#10b981,stroke:#333,stroke-width:2px,color:#fff
4. Consistent Security¶
All applications get the same security controls automatically.
Pod Architecture¶
Network Sharing¶
Containers in the same pod share the same network namespace, enabling communication via localhost.
graph TB
subgraph Pod Network Namespace
direction LR
subgraph "oauth2-proxy"
A[":4180"]
end
subgraph "application"
B[":8080"]
end
A -->|localhost:8080| B
end
C[External Traffic
:4180] --> A
style A fill:#4c51bf,stroke:#333,stroke-width:2px,color:#fff
style B fill:#10b981,stroke:#333,stroke-width:2px,color:#fff
Key Points:
- oauth2-proxy listens on :4180 (exposed externally via Service)
- Application listens on :8080 (only accessible within pod)
- Communication is fast (localhost, no network overhead)
- Application port is never exposed externally
Volume Sharing¶
Containers can share volumes for configuration and templates.
spec:
containers:
- name: oauth2-proxy
volumeMounts:
- name: config
mountPath: /etc/oauth2-proxy
- name: templates
mountPath: /templates
- name: app
volumeMounts:
- name: app-config
mountPath: /etc/app
volumes:
- name: config
configMap:
name: oauth2-proxy-config
- name: templates
configMap:
name: oauth2-proxy-templates
- name: app-config
configMap:
name: app-config
Lifecycle Management¶
Both containers start and stop together.
stateDiagram-v2
[*] --> Pending: kubectl apply
Pending --> Running: Both containers start
Running --> Terminating: kubectl delete
Terminating --> [*]: Both containers stop
note right of Running
If either container fails,
pod is restarted
end note
Request Flow¶
Detailed Request Flow¶
sequenceDiagram
autonumber
participant Client
participant Service
participant Proxy as oauth2-proxy
:4180
participant App as application
:8080
Client->>Service: GET / HTTP/1.1
Host: app.example.com
Service->>Proxy: Forward to pod
port 4180
alt Cookie Present
Proxy->>Proxy: Validate cookie
Proxy->>App: GET / HTTP/1.1
X-Auth-Request-Email: user@example.com
X-Auth-Request-User: user
App->>Proxy: HTTP/1.1 200 OK
Content
Proxy->>Client: HTTP/1.1 200 OK
Content
else No Cookie
Proxy->>Client: HTTP/1.1 200 OK
Sign-in page HTML
Client->>Proxy: Click OAuth button
Proxy->>Client: HTTP/1.1 302 Found
Location: https://github.com/login...
end
Header Injection¶
The oauth2-proxy sidecar automatically injects user information:
| Header | Description | Example |
|---|---|---|
X-Auth-Request-User |
User identifier | octocat |
X-Auth-Request-Email |
User email | octocat@github.com |
X-Auth-Request-Preferred-Username |
Preferred username | octocat |
X-Forwarded-User |
Forwarded user | octocat |
X-Forwarded-Email |
Forwarded email | octocat@github.com |
Authorization |
Bearer token (optional) | Bearer eyJ... |
Configuration¶
Pod-Level Configuration¶
Each pod can have its own authentication configuration.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
spec:
template:
spec:
containers:
- name: oauth2-proxy
env:
# App-specific redirect URL
- name: OAUTH2_PROXY_REDIRECT_URL
value: "https://app1.example.com/oauth2/callback"
# App-specific upstream
- name: OAUTH2_PROXY_UPSTREAMS
value: "http://127.0.0.1:8080"
Shared Configuration¶
Common settings are shared via ConfigMap.
graph TB
A[ConfigMap
oauth2-proxy-config] --> B[app1 pod]
A --> C[app2 pod]
A --> D[app3 pod]
E[Secret
oauth2-proxy-secret] --> B
E --> C
E --> D
style A fill:#f59e0b,stroke:#333,stroke-width:2px,color:#fff
style E fill:#ef4444,stroke:#333,stroke-width:2px,color:#fff
Shared via ConfigMap: - OAuth provider type - Cookie settings - Email domain restrictions - Template configuration
Shared via Secret: - OAuth client ID & secret - Cookie encryption secret
Per-pod via Environment: - Redirect URL (app-specific) - Upstream port (app-specific)
Resource Management¶
Resource Requests and Limits¶
Each sidecar has its own resource allocation.
containers:
- name: oauth2-proxy
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
- name: app
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
Typical Resource Usage:
| Container | Memory | CPU | Notes |
|---|---|---|---|
| oauth2-proxy | 50-100 MB | 10-50m | Low overhead |
| Application | Varies | Varies | Your app's needs |
Scaling Considerations¶
graph TB
subgraph "3 Replicas"
A[app-pod-1
oauth2-proxy + app]
B[app-pod-2
oauth2-proxy + app]
C[app-pod-3
oauth2-proxy + app]
end
D[Service] --> A
D --> B
D --> C
E[Each pod:
~150MB total] -.-> A
E -.-> B
E -.-> C
Scaling Impact: - Each replica adds one oauth2-proxy sidecar - At 10 replicas × 100MB = 1GB overhead - Trade-off: More memory for better isolation
Comparison with Alternatives¶
vs. Centralized oauth2-proxy¶
graph TB
subgraph "Centralized"
direction TB
A[oauth2-proxy
deployment] --> B[app1]
A --> C[app2]
A --> D[app3]
E[Complex Istio
ext_authz config] -.-> A
end
subgraph "Sidecar"
direction TB
F[app1 + sidecar]
G[app2 + sidecar]
H[app3 + sidecar]
I[Simple pod
configuration] -.-> F
end
style A fill:#ef4444,stroke:#333,stroke-width:2px,color:#fff
style E fill:#ef4444,stroke:#333,stroke-width:2px,color:#fff
style I fill:#10b981,stroke:#333,stroke-width:2px,color:#fff
| Feature | Sidecar | Centralized |
|---|---|---|
| Configuration | ✅ Simple | ❌ Complex |
| Debugging | ✅ Easy | ❌ Distributed |
| Isolation | ✅ Per-app | ❌ Shared |
| Flexibility | ✅ Per-app providers | ❌ Single provider |
| Resources | ⚠️ Higher | ✅ Lower |
| Portability | ✅ Easy | ❌ Infrastructure-tied |
vs. Application-Embedded Auth¶
graph LR
subgraph "Embedded Auth"
A[App Code] --> B[Auth Library]
B --> C[OAuth Provider]
end
subgraph "Sidecar"
D[App Code] --> E[oauth2-proxy]
E --> F[OAuth Provider]
end
style A fill:#f59e0b,stroke:#333,stroke-width:2px,color:#fff
style B fill:#f59e0b,stroke:#333,stroke-width:2px,color:#fff
style D fill:#10b981,stroke:#333,stroke-width:2px,color:#fff
style E fill:#4c51bf,stroke:#333,stroke-width:2px,color:#fff
| Aspect | Sidecar | Embedded |
|---|---|---|
| Code changes | ✅ None needed | ❌ Must implement |
| Language support | ✅ Any language | ⚠️ Library dependent |
| Security updates | ✅ Update image | ❌ Code change + deploy |
| Consistency | ✅ Same for all apps | ❌ Varies by app |
| Testing | ✅ Test separately | ❌ Test with app |
Best Practices¶
1. Use Shared ConfigMaps¶
Create one ConfigMap for common settings, environment variables for app-specific settings.
2. Monitor Both Containers¶
3. Health Checks¶
Configure health checks for both containers:
containers:
- name: oauth2-proxy
livenessProbe:
httpGet:
path: /ping
port: 4180
readinessProbe:
httpGet:
path: /ping
port: 4180
- name: app
livenessProbe:
httpGet:
path: /health
port: 8080
4. Resource Limits¶
Always set resource limits to prevent resource contention.
5. Logging¶
Structure logs for easy correlation:
{
"container": "oauth2-proxy",
"pod": "app-7d8f6b-abc123",
"level": "info",
"msg": "Authentication successful"
}