diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-07 15:38:03 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-07 15:38:03 -0600 |
| commit | c02bcbb27e291ada3ab59a671f064f054c0e58db (patch) | |
| tree | 4a2cb8b0b70e5b01721695d88219af4b1effd1c0 | |
| parent | 7d108cd6d4b44c490f8b0bd7af48af0d067ae0fc (diff) | |
docs: create initial draft of presentation
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | share/man/README.md | 645 |
2 files changed, 646 insertions, 0 deletions
@@ -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 |
