summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-07 15:38:03 -0600
committermo khan <mo@mokhan.ca>2025-07-07 15:38:03 -0600
commitc02bcbb27e291ada3ab59a671f064f054c0e58db (patch)
tree4a2cb8b0b70e5b01721695d88219af4b1effd1c0
parent7d108cd6d4b44c490f8b0bd7af48af0d067ae0fc (diff)
docs: create initial draft of presentation
-rw-r--r--.gitignore1
-rw-r--r--share/man/README.md645
2 files changed, 646 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 2d67c87d..7873cef1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
bin
target
+*.pdf
# Explicitly include vendor directory
!vendor/
diff --git a/share/man/README.md b/share/man/README.md
index e69de29b..49ead995 100644
--- a/share/man/README.md
+++ b/share/man/README.md
@@ -0,0 +1,645 @@
+# Sparkle & Authzd: Authorization at the Edge
+
+## Slide 1: Overview
+
+### What We Built
+
+Two services that work together to provide authorization at the edge:
+
+1. **Sparkled** - Demo application (Go web service)
+2. **Authzd** - Authorization daemon (gRPC service implementing Envoy's `ext_authz` API)
+
+### Key Innovation
+
+Authorization decisions happen in Envoy *before* requests reach the application.
+
+This is different from Rails where authorization typically happens inside the app.
+
+---
+
+## Slide 2: The Problem We're Solving
+
+### Traditional Rails Approach
+
+```
++-------------+
+| Browser |
++------+------+
+ |
+ | HTTP Request
+ v
++-------------+
+| Rails | <-- Authentication + Authorization happens here
++-------------+
+```
+
+### Challenges
+- Every app reimplements auth logic
+- Hard to enforce consistent policies
+- Difficult to audit authorization decisions
+- Sensitive tokens handled by application code
+
+---
+
+## Slide 3: Our Solution - Authorization at the Edge
+
+```
+ +--------------+
+ | User-Agent |
+ +------+-------+
+ | HTTP Request
+ v
++=========================================+
+| DOCKER IMAGE: Sparkle |
+| |
+| +-------------------------------------+ |
+| | ENVOY PROXY (Sparkle) | |
+| | | |
+| | 1. OAuth2 Filter (login flow) | |
+| | 2. JWT Filter (validates tokens) | |
+| | 3. Ext_Authz Filter (Go authzd) --+ | |
+| | 4. Router (forwards to app) | | |
+| +---------------+-------------------+-+ |
+| | | |
+| v v |
+| +-------------+ +----------+ |
+| | Sparkled | | Go Authzd| |
+| | (App) | | (sidecar)| |
+| +-------------+ +----+-----+ |
++==============================|=========+
+ |
+ | gRPC call
+ | (network)
+ v
++==============================+=========+
+| DOCKER IMAGE: Authzd |
+| |
+| +------------------------------------+ |
+| | ENVOY PROXY (Remote) | |
+| +------------------+-----------------+ |
+| | |
+| v |
+| +---------------+ |
+| | Rust Authzd | |
+| | (remote) | |
+| +---------------+ |
++========================================+
+```
+
+---
+
+## Slide 4: Request Flow - First Time User
+
+```
+User-Agent Envoy(Sparkle) Sparkled GitLab
+ | | | |
+ | GET /dashboard | | |
+ |--------------->| | |
+ | | | |
+ | | No auth cookie | |
+ | 302 Redirect | detected | |
+ |<---------------| | |
+ | | | |
+ | GET gitlab.com/oauth/authorize | |
+ |----------------------------------|------------->|
+ | | |
+ | (User logs in) | |
+ | | |
+ | 302 /callback?code=xyz | |
+ |<---------------------------------|------------->|
+ | | | |
+ | GET /callback | | |
+ |--------------->| | |
+ | | Exchange code | |
+ | |-----------------|------------->|
+ | | | |
+ | | ID token + | |
+ | | Access token | |
+ | |<----------------|--------------|
+ | | | |
+ | Set cookies | | |
+ | 302 /dashboard | | |
+ |<---------------| | |
+```
+
+---
+
+## Slide 5: Request Flow - Authenticated User
+
+```
+User-Agent Envoy(Sparkle) Go Authzd Rust Authzd
+ | | | |
+ | GET /dashboard | | |
+ | (with cookies) | | |
+ |--------------->| | |
+ | | | |
+ | | 1. Extract | |
+ | | ID token | |
+ | | | |
+ | | 2. Validate JWT | |
+ | | ✓ Valid | |
+ | | | |
+ | | 3. Check authz | |
+ | |---------------->| |
+ | | | |
+ | | | gRPC call |
+ | | | (network) |
+ | | |------------->|
+ | | | |
+ | | | Evaluate |
+ | | gRPC: OK | policies |
+ | |<----------------|<-------------|
+ | | | |
+ | | 4. Forward request |
+ | |------------------------------->|
+ | | + JWT claims in headers |
+ | | |
+ | 200 OK | |
+ | Dashboard HTML |<-------------------------------|
+ |<---------------| |
+```
+
+---
+
+## Slide 6: The Dual Authzd Architecture
+
+### Current: Go Sidecar + Rust Remote
+
+```
++-----------------------------------------------------+
+| Docker Container |
+| |
+| +---------+ +--------------+ +----------+ |
+| | Envoy |--->| Go Authzd | | Sparkled | |
+| | (local) | | (sidecar) | | (App) | |
+| +---------+ +------+-------+ +----------+ |
+| | |
++------------------------|----------------------------+
+ |
+ | gRPC call (fallback)
+ v
+ +---------------+
+ | ENVOY PROXY |
+ | (remote) |
+ +-------+-------+
+ |
+ v
+ +---------------+
+ | Rust Authzd |
+ | (remote) |
+ +---------------+
+```
+
+### Future: In-Process Library + Remote Fallback
+
+```
++-----------------------------------------------------+
+| Docker Container |
+| |
+| +---------+ +--------------+ +----------+ |
+| | Envoy |--->| Rust Authzd | | Sparkled | |
+| | (local) | | (library) | | (App) | |
+| +---------+ +------+-------+ +----------+ |
+| | |
++------------------------|----------------------------+
+ |
+ | HTTP call (fallback)
+ v
+ +---------------+
+ | Rust Authzd |
+ | (remote) |
+ +---------------+
+```
+
+### Benefits:
+1. **Local authzd** - Fast, no network latency, basic policies
+2. **Remote authzd** - Centralized policy management, complex rules
+3. **Future**: In-process library eliminates gRPC overhead
+
+---
+
+## Slide 7: Envoy Configuration Deep Dive
+
+### The Filter Chain (order matters!)
+
+```yaml
+http_filters:
+ - name: envoy.filters.http.oauth2 # 1. Handle login/logout
+ - name: envoy.filters.http.jwt_authn # 2. Validate tokens
+ - name: envoy.filters.http.ext_authz # 3. Check authorization
+ - name: envoy.filters.http.router # 4. Route to app
+```
+
+Each filter processes the request and can:
+- Allow it to continue to the next filter
+- Return an immediate response (redirect, error, etc.)
+- Modify headers before passing along
+
+---
+
+## Slide 8: OAuth2 Filter - Authentication
+
+### Configuration
+```yaml
+- name: envoy.filters.http.oauth2
+ config:
+ authorization_endpoint: "https://gitlab.com/oauth/authorize"
+ token_endpoint: "https://gitlab.com/oauth/token"
+ credentials:
+ client_id: "OAUTH_CLIENT_ID"
+ cookie_names:
+ id_token: id_token
+ bearer_token: bearer_token
+ pass_through_matcher: # Skip auth for these paths
+ - name: ":path"
+ string_match:
+ safe_regex:
+ regex: ^.+\.(css|js|png)$
+```
+
+### What it does:
+1. Intercepts unauthenticated requests
+2. Manages OAuth2 flow with GitLab
+3. Stores tokens in encrypted cookies
+4. Handles token refresh automatically
+
+---
+
+## Slide 9: JWT Filter - Token Validation
+
+### Configuration
+```yaml
+- name: envoy.filters.http.jwt_authn
+ providers:
+ id_token_provider:
+ issuer: https://gitlab.com
+ audiences: [OAUTH_CLIENT_ID]
+ remote_jwks:
+ uri: https://gitlab.com/oauth/discovery/keys
+ claim_to_headers: # Extract claims to headers
+ - claim_name: sub
+ header_name: x-jwt-claim-sub
+ - claim_name: nickname
+ header_name: x-jwt-claim-username
+```
+
+### Headers passed to app:
+```
+x-jwt-claim-sub: 123456
+x-jwt-claim-username: john.doe
+x-jwt-payload: <base64 encoded JWT>
+```
+
+---
+
+## Slide 10: Ext_Authz Filter - Authorization
+
+### The gRPC Call
+
+```
++------------+ CheckRequest +------------+
+| Envoy | ---------------------> | Authzd |
+| | | |
+| | <--------------------- | |
++------------+ CheckResponse +------------+
+```
+
+### CheckRequest includes:
+```protobuf
+message CheckRequest {
+ AttributeContext attributes = 1;
+}
+
+message AttributeContext {
+ Request request = 1; // HTTP method, path, headers
+ // ... context about the request
+}
+```
+
+### CheckResponse:
+```protobuf
+message CheckResponse {
+ Status status = 1; // OK or Permission Denied
+ // Can add/remove headers
+}
+```
+
+---
+
+## Slide 11: Authzd Implementation
+
+### Current Cedar Policy
+
+```cedar
+// Allow requests with valid bearer token
+permit(principal, action == Action::"check", resource)
+when {
+ context has bearer_token &&
+ context.bearer_token == "valid-token"
+};
+
+// Allow static assets
+permit(principal, action, resource)
+when {
+ context has path &&
+ context has method &&
+ context.method == "GET" &&
+ context.path like "*.css"
+};
+
+// Allow specific Sparkle endpoints
+permit(principal, action, resource)
+when {
+ context has host &&
+ context.host == "sparkle.runway.gitlab.net" &&
+ context.path == "/health"
+};
+```
+
+---
+
+## Slide 12: How Authzd Makes Decisions
+
+```
+ CheckRequest from Envoy
+ |
+ v
+ +---------------------+
+ | Extract from request |
+ | - Bearer token |
+ | - Path |
+ | - Method |
+ | - Host |
+ +----------+----------+
+ |
+ v
+ +---------------------+
+ | Create Cedar Request |
+ | - Principal: User |
+ | - Action: check |
+ | - Resource: resource |
+ | - Context: {token,..}|
+ +----------+----------+
+ |
+ v
+ +---------------------+
+ | Evaluate Policies |
+ | using Cedar engine |
+ +----------+----------+
+ |
+ +-------+--------+
+ v v
+ ALLOW (200) DENY (401)
+```
+
+---
+
+## Slide 13: Benefits of This Architecture
+
+### 1. **Separation of Concerns**
+ - Envoy handles auth complexity
+ - App focuses on business logic
+ - Policies managed separately
+
+### 2. **Security**
+ - OAuth secrets never reach app
+ - Token validation at edge
+ - Consistent policy enforcement
+
+### 3. **Performance**
+ - Early request rejection
+ - No auth overhead in app
+ - Local authzd = low latency
+
+### 4. **Flexibility**
+ - Easy to add new auth methods
+ - Policy changes without app changes
+ - Gradual migration path
+
+---
+
+## Slide 14: Comparison with Rails
+
+### Rails (Traditional)
+```ruby
+class DashboardController < ApplicationController
+ before_action :authenticate_user!
+ before_action :authorize_dashboard_access
+
+ def show
+ # Business logic
+ end
+
+ private
+
+ def authorize_dashboard_access
+ unless can?(:view, :dashboard)
+ render_403
+ end
+ end
+end
+```
+
+### Our Approach
+```go
+// No auth code needed!
+func (c *DashboardController) Show(w http.ResponseWriter, r *http.Request) {
+ // Just business logic
+ userID := r.Header.Get("x-jwt-claim-sub")
+ // ...
+}
+```
+
+---
+
+## Slide 15: Demo Scenarios
+
+### Scenario 1: Unauthenticated Access
+```bash
+curl http://localhost:10000/dashboard
+# → 302 Redirect to GitLab login
+```
+
+### Scenario 2: Static Asset (No Auth Required)
+```bash
+curl http://localhost:10000/style.css
+# → 200 OK (bypasses auth)
+```
+
+### Scenario 3: Authenticated Access
+```bash
+curl -H "Cookie: id_token=..." http://localhost:10000/dashboard
+# → 200 OK (if authorized)
+```
+
+### Scenario 4: Invalid Token
+```bash
+curl -H "Cookie: id_token=expired" http://localhost:10000/dashboard
+# → 401 Unauthorized
+```
+
+---
+
+## Slide 16: Cedar Policy Language
+
+### Why Cedar?
+
+- **Simple** - Easy to read and write
+- **Fast** - Optimized for authorization decisions
+- **Safe** - Prevents common policy mistakes
+- **Auditable** - Clear decision logs
+
+### Example: Group-based Access
+```cedar
+permit(
+ principal,
+ action == Action::"view",
+ resource == Resource::"admin_panel"
+)
+when {
+ principal.groups.contains("admins")
+};
+```
+
+### Example: Time-based Access
+```cedar
+permit(principal, action, resource)
+when {
+ context.current_hour >= 9 &&
+ context.current_hour < 17 // Business hours only
+};
+```
+
+---
+
+## Slide 17: Debugging Authorization
+
+### Envoy Access Logs
+```json
+{
+ "app": "envoy",
+ "path": "/dashboard",
+ "method": "GET",
+ "response_code": "401",
+ "duration": "5",
+ "ext_authz_status": "denied"
+}
+```
+
+### Authzd Decision Logs
+```json
+{
+ "level": "INFO",
+ "message": "Processing HTTP request",
+ "method": "GET",
+ "path": "/dashboard",
+ "decision": "Deny",
+ "diagnostics": {
+ "reason": "No matching permit policy",
+ "policies_evaluated": ["policy0", "policy1"]
+ }
+}
+```
+
+---
+
+## Slide 18: Migration Strategy
+
+### Phase 1: Parallel Running
+```
+ +----------+
+ +--->| Rails | (existing auth)
+ | +----------+
+ Browser -----+
+ | +----------+
+ +--->| Envoy | (new auth)
+ +----------+
+```
+
+### Phase 2: Gradual Cutover
+- Start with read-only endpoints
+- Move non-critical paths
+- Finally migrate sensitive operations
+
+### Phase 3: Full Migration
+- Remove auth code from Rails
+- Rely entirely on edge authorization
+
+---
+
+## Slide 19: Key Takeaways
+
+1. **Authorization at the edge** is more secure and performant
+
+2. **Envoy handles the complex parts** - OAuth flows, token validation
+
+3. **Cedar policies** are easier to audit than code
+
+4. **Separation of concerns** - Apps do business logic, not auth
+
+5. **Gradual migration** is possible - no big bang required
+
+---
+
+## Slide 20: Questions & Discussion
+
+### Architecture Questions
+- How does this compare to Rails + Devise?
+- What about API authentication?
+- How do we handle service-to-service auth?
+
+### Implementation Questions
+- How complex can Cedar policies get?
+- What's the performance impact?
+- How do we test authorization rules?
+
+### Migration Questions
+- Which services should adopt this first?
+- How do we maintain backwards compatibility?
+- What's the rollback strategy?
+
+---
+
+## Appendix A: Running the Demo
+
+### Local Development
+```bash
+# Terminal 1: Start the services
+make run
+
+# Terminal 2: Watch the logs
+make logs
+
+# Terminal 3: Test requests
+curl -v http://localhost:10000/
+```
+
+### Docker Deployment
+```bash
+# Build the image
+make build-image
+
+# Run everything
+docker run -p 10000:10000 \
+ -e OAUTH_CLIENT_ID=xxx \
+ -e OAUTH_CLIENT_SECRET=yyy \
+ sparkle:latest
+```
+
+---
+
+## Appendix B: Resources
+
+### Documentation
+- Envoy ext_authz: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter
+- Cedar Language: https://www.cedarpolicy.com/
+- Warsaw Accord Design Doc: See pages 3-5
+
+### Code Repositories
+- Sparkled: `/sparkled` - Demo application
+- Authzd: `/authzd` - Authorization daemon
+
+### Key Files
+- `/sparkled/etc/envoy/envoy.yaml` - Envoy configuration
+- `/authzd/etc/authzd/policy0.cedar` - Authorization policies
+- `/sparkled/share/man/ENVOY.md` - Detailed Envoy documentation