From 2147144aa00e6e6449abb5bd9737ad9e8f05925a Mon Sep 17 00:00:00 2001 From: Nick Marden Date: Fri, 23 Jan 2026 14:43:56 +0700 Subject: [PATCH] feat: add configure-helm skill and update configure-route - Move skills to agents/ directory (canonical location) - Symlink from .claude/skills/ for Claude Code slash commands - Update configure-route with all verifier types: - json_field (Microsoft Graph) - query_param (URL token) - header_query_param (encoded header params) - validators (JSON Schema) - preserve_host option - Add configure-helm skill for complete K8s deployments: - Multiple routes configuration - Ingress/Gateway API options - TLS with cert-manager or built-in ACME - Secrets management - Redis/Valkey for multi-replica relay - gatekeeper-relay deployment - Promote skills in README with new section - Update docs/USAGE.md with both skills - Add maintenance note to AGENTS.md --- .claude/skills/configure-helm.md | 1 + .claude/skills/configure-route.md | 266 +----------------- AGENTS.md | 11 + README.md | 55 ++++ agents/README.md | 38 +++ agents/configure-helm.md | 435 ++++++++++++++++++++++++++++++ agents/configure-route.md | 371 +++++++++++++++++++++++++ docs/USAGE.md | 80 ++++-- 8 files changed, 965 insertions(+), 292 deletions(-) create mode 120000 .claude/skills/configure-helm.md mode change 100644 => 120000 .claude/skills/configure-route.md create mode 100644 agents/README.md create mode 100644 agents/configure-helm.md create mode 100644 agents/configure-route.md diff --git a/.claude/skills/configure-helm.md b/.claude/skills/configure-helm.md new file mode 120000 index 0000000..bec5540 --- /dev/null +++ b/.claude/skills/configure-helm.md @@ -0,0 +1 @@ +../../agents/configure-helm.md \ No newline at end of file diff --git a/.claude/skills/configure-route.md b/.claude/skills/configure-route.md deleted file mode 100644 index f9dd1c9..0000000 --- a/.claude/skills/configure-route.md +++ /dev/null @@ -1,265 +0,0 @@ -# Configure Route Skill - -This skill walks users through configuring a new webhook route for gatekeeper. - -## Usage - -Invoke with `/configure-route` or ask "I want to configure a webhook for [provider]" - -## Instructions - -When the user wants to configure a new webhook route, guide them through these steps interactively. Ask one question at a time and wait for their response before proceeding. - -### Step 1: Identify the Provider - -Ask which webhook provider they want to configure. Offer these options: - -- **Slack** - Slack Events API, slash commands, interactive components -- **GitHub** - Repository webhooks, organization webhooks -- **Shopify** - Store webhooks (orders, products, customers) -- **Google Calendar** - Calendar push notifications -- **Generic HMAC** - Any provider using HMAC signatures -- **API Key** - Providers using simple header token authentication -- **Other** - Help them determine the best approach - -### Step 2: External Hostname - -Ask: "What hostname will [provider] send webhooks to?" - -Example: `slack-webhooks.example.com` or `webhooks.mycompany.com` - -This is the public DNS name that will receive webhook traffic. - -### Step 3: Delivery Mode - -Ask: "How should webhooks be delivered to your internal service?" - -**Option A: Direct forwarding** -- Gatekeeperd forwards directly to your backend -- Requires a firewall rule allowing traffic from gatekeeperd to your internal service -- Lower latency, simpler setup if firewall access is available - -**Option B: Relay client** -- A relay client inside your network polls gatekeeperd for webhooks -- No inbound firewall rules needed -- Only requires outbound HTTPS from your network to gatekeeperd - -### Step 4: Internal Destination - -Ask: "What is the internal URL where webhooks should be delivered?" - -For direct mode: This is the full URL gatekeeperd will forward to. -For relay mode: This is the URL the relay client will forward to locally. - -Suggest provider-specific defaults: -- Slack: `http://your-app:8080/webhooks/slack` or `/slack/events` -- GitHub: `http://your-app:8080/webhooks/github` or `/github/events` -- Shopify: `http://your-app:8080/webhooks/shopify` -- Google Calendar: `http://your-app:8080/webhooks/gcal` or `/calendar/notifications` - -### Step 5: Generate Configuration - -Based on their answers, generate the complete configuration. - -#### For Direct Mode - -```yaml -# Add to gatekeeperd.yaml - -verifiers: - {verifier-name}: - {provider-specific-config} - -routes: - - hostname: {hostname} - path: {path} - ip_allowlist: {recommended-allowlist} # if applicable - verifier: {verifier-name} - destination: {destination-url} -``` - -#### For Relay Mode - -Generate both server and client configs: - -```yaml -# Add to gatekeeperd.yaml - -verifiers: - {verifier-name}: - {provider-specific-config} - -routes: - - hostname: {hostname} - path: {path} - ip_allowlist: {recommended-allowlist} # if applicable - verifier: {verifier-name} - relay_token: "${RELAY_TOKEN_{PROVIDER}}" -``` - -```yaml -# Add to gatekeeper-relay.yaml - -channels: - - name: {provider}-webhooks - token: "${RELAY_TOKEN_{PROVIDER}}" - destination: "{local-destination}" -``` - -### Step 6: Provider-Specific Setup Instructions - -After generating the configuration, provide setup instructions specific to the provider. - -#### Slack - -1. Go to https://api.slack.com/apps and select your app -2. Navigate to "Event Subscriptions" (or "Interactivity & Shortcuts" for interactive components) -3. Set the Request URL to: `https://{hostname}{path}` -4. Copy the "Signing Secret" from "Basic Information" -5. Set the environment variable: `export SLACK_SIGNING_SECRET="your-signing-secret"` - -Configuration uses: -```yaml -verifiers: - slack: - type: slack - signing_secret: "${SLACK_SIGNING_SECRET}" - max_timestamp_age: 5m # Replay attack protection -``` - -Recommended IP allowlist: `aws` (Slack runs on AWS EC2) -```yaml -ip_allowlists: - aws: - fetch_url: "https://ip-ranges.amazonaws.com/ip-ranges.json" - fetch_jq: '.prefixes[] | select(.service=="EC2") | .ip_prefix' - refresh_interval: 24h -``` - -#### GitHub - -1. Go to your repository or organization settings -2. Navigate to "Webhooks" and click "Add webhook" -3. Set Payload URL to: `https://{hostname}{path}` -4. Set Content type to: `application/json` -5. Generate a secret and enter it in the "Secret" field -6. Set the environment variable: `export GITHUB_WEBHOOK_SECRET="your-secret"` - -Configuration uses: -```yaml -verifiers: - github: - type: github - secret: "${GITHUB_WEBHOOK_SECRET}" -``` - -Recommended IP allowlist: GitHub publishes their IP ranges at https://api.github.com/meta -```yaml -ip_allowlists: - github: - fetch_url: "https://api.github.com/meta" - fetch_jq: ".hooks[]" - refresh_interval: 24h -``` - -#### Shopify - -1. Go to your Shopify admin panel -2. Navigate to Settings > Notifications > Webhooks -3. Click "Create webhook" -4. Select the event and set the URL to: `https://{hostname}{path}` -5. Note the webhook signing secret shown after creation -6. Set the environment variable: `export SHOPIFY_WEBHOOK_SECRET="your-secret"` - -Configuration uses: -```yaml -verifiers: - shopify: - type: shopify - secret: "${SHOPIFY_WEBHOOK_SECRET}" -``` - -#### Google Calendar - -1. Use the Google Calendar API to create a watch request -2. Set the `address` to: `https://{hostname}{path}` -3. Set a `token` value in your watch request (this is your shared secret) -4. Set the environment variable: `export GCAL_CHANNEL_TOKEN="your-token"` - -Configuration uses: -```yaml -verifiers: - gcal: - type: api_key - header: "X-Goog-Channel-Token" - token: "${GCAL_CHANNEL_TOKEN}" -``` - -Recommended IP allowlist: -```yaml -ip_allowlists: - google: - fetch_url: "https://www.gstatic.com/ipranges/goog.json" - fetch_jq: ".prefixes[].ipv4Prefix" - refresh_interval: 24h -``` - -#### Generic HMAC - -Ask the user for: -- Header name containing the signature -- Hash algorithm (SHA256 or SHA512) -- Encoding (hex or base64) -- Whether there's a signature prefix (e.g., "sha256=") - -Configuration uses: -```yaml -verifiers: - custom: - type: hmac - secret: "${WEBHOOK_SECRET}" - header: "X-Signature" # Header containing signature - algorithm: sha256 # sha256 or sha512 - encoding: hex # hex or base64 - prefix: "sha256=" # Optional prefix to strip -``` - -#### API Key - -Ask the user for: -- Header name containing the token - -Configuration uses: -```yaml -verifiers: - custom: - type: api_key - header: "X-Webhook-Token" - token: "${WEBHOOK_TOKEN}" -``` - -### Step 7: Environment Variables Summary - -At the end, summarize all environment variables that need to be set: - -```bash -# Required environment variables for this configuration: -export {VAR_NAME}="your-value-here" - -# For relay mode, also set: -export RELAY_TOKEN_{PROVIDER}="generate-a-secure-random-token" -``` - -Remind them: -- Never commit secrets to version control -- Use Kubernetes Secrets or a secret manager in production -- For relay tokens, generate a secure random value (e.g., `openssl rand -hex 32`) - -### Conversation Style - -- Be concise and direct -- Ask one question at a time -- Provide sensible defaults where possible -- Explain trade-offs when relevant (e.g., direct vs relay mode) -- Use code blocks for all configuration snippets -- After generating config, offer to help with additional routes diff --git a/.claude/skills/configure-route.md b/.claude/skills/configure-route.md new file mode 120000 index 0000000..d440e57 --- /dev/null +++ b/.claude/skills/configure-route.md @@ -0,0 +1 @@ +../../agents/configure-route.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 8bd6862..0ca7eb3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -136,6 +136,17 @@ ip_allowlists: refresh_interval: 24h ``` +## Interactive Skills + +Gatekeeper includes AI skills for interactive configuration (see [agents/](agents/)): + +- **Configure Route** ([agents/configure-route.md](agents/configure-route.md)) - Configure a single webhook route +- **Configure Helm** ([agents/configure-helm.md](agents/configure-helm.md)) - Configure a complete Kubernetes deployment + +These are user-facing interactive wizards, not coding agent instructions. In Claude Code, invoke with `/configure-route` or `/configure-helm`. + +**Maintenance**: When adding features that affect configuration (new verifier types, new route options, new Helm values), update the relevant skill files in `agents/` before committing. The skills should always reflect the current capabilities. + ## File Locations - Server entry point: cmd/gatekeeperd/main.go diff --git a/README.md b/README.md index 682d43b..b283299 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ A webhook authentication, authorization, and validation proxy for enterprise env - [Security Considerations](#security-considerations) - [Overview](#security-overview) - [Mitigations](#mitigations) +- [AI-Assisted Configuration](#ai-assisted-configuration) - [Alternatives Considered](#alternatives-considered) - [Planned Work](#planned-work) - [Installation](#installation) @@ -305,6 +306,60 @@ Relay mode eliminates inbound firewall rules entirely. The relay client initiate --- +## AI-Assisted Configuration + +Gatekeeper includes AI skills for interactive configuration. These skills guide you through setup step-by-step, generating complete configuration files with provider-specific instructions. + +### Available Skills + +| Skill | Description | +|-------|-------------| +| **Configure Route** | Configure a single webhook route - walks through provider selection, delivery mode, verifier setup, and generates both server and relay configs | +| **Configure Helm** | Configure a complete Kubernetes deployment - wraps multiple routes plus ingress/gateway, TLS, secrets, and relay setup | + +### Using the Skills + +**With Claude Code** (slash commands): +``` +/configure-route +/configure-helm +``` + +**With any AI assistant** (paste the skill or ask directly): +``` +I want to configure a webhook for Slack +Help me deploy gatekeeper to Kubernetes +``` + +The skill definitions in [`agents/`](agents/) can be provided to any AI assistant as context for interactive configuration. + +### What the Skills Configure + +**Configure Route** supports all verifier types: +- Slack (HMAC-SHA256 with replay protection) +- GitHub (HMAC-SHA256) +- Shopify (HMAC-SHA256 base64) +- Google Calendar (header token) +- Microsoft Graph (JSON field token) +- Generic HMAC (configurable algorithm/encoding) +- API Key, Query Parameter, Header Query Parameter + +**Configure Helm** handles: +- Multiple webhook routes in a single deployment +- Ingress (nginx, Traefik) or Gateway API configuration +- TLS with cert-manager or built-in ACME +- Secrets management (Helm-managed or external) +- Redis/Valkey for multi-replica relay coordination +- gatekeeper-relay deployment for private networks + +### Skill Documentation + +The skill definitions are in the [`agents/`](agents/) directory: +- [`agents/configure-route.md`](agents/configure-route.md) +- [`agents/configure-helm.md`](agents/configure-helm.md) + +--- + ## Alternatives Considered ### Convoy diff --git a/agents/README.md b/agents/README.md new file mode 100644 index 0000000..b680157 --- /dev/null +++ b/agents/README.md @@ -0,0 +1,38 @@ +# Gatekeeper Agent Skills + +This directory contains AI skills for interactive gatekeeper configuration. These skills work with any AI assistant that can follow structured instructions. + +## Available Skills + +| Skill | File | Claude Code | +|-------|------|-------------| +| Configure Route | [`configure-route.md`](configure-route.md) | `/configure-route` | +| Configure Helm | [`configure-helm.md`](configure-helm.md) | `/configure-helm` | + +## Usage + +**With Claude Code**: Invoke skills with slash commands (`/configure-route`, `/configure-helm`) + +**With any AI assistant**: Either provide the skill file as context, or simply ask: +- "I want to configure a webhook for Slack" +- "Help me deploy gatekeeper to Kubernetes" + +## Skill Structure + +Each skill file contains: + +1. **Usage** - How to invoke the skill +2. **Instructions** - Step-by-step flow for Claude to follow +3. **Provider-specific guidance** - Configuration examples and setup instructions +4. **Generated output** - Templates for the configuration files + +## Claude Code Integration + +These skills are symlinked from `.claude/skills/` for Claude Code slash command support: + +``` +.claude/skills/configure-route.md -> ../../agents/configure-route.md +.claude/skills/configure-helm.md -> ../../agents/configure-helm.md +``` + +The canonical versions live here in `agents/` and are tracked in version control. diff --git a/agents/configure-helm.md b/agents/configure-helm.md new file mode 100644 index 0000000..a1e0262 --- /dev/null +++ b/agents/configure-helm.md @@ -0,0 +1,435 @@ +# Configure Helm Skill + +This skill helps users configure a complete Helm deployment of gatekeeper, including multiple routes, secrets, ingress/gateway options, TLS, and relay configuration. + +## Usage + +- **Claude Code**: `/configure-helm` +- **Any AI assistant**: "I want to deploy gatekeeper to Kubernetes" or "Help me set up gatekeeper with Helm" + +## Instructions + +This skill guides users through configuring a complete Helm deployment. It wraps the route configuration process and adds Helm-specific settings. + +### Overview + +A complete gatekeeper Helm deployment includes: + +1. **Routes** - One or more webhook routes (use `/configure-route` for each) +2. **Secrets** - Signing secrets, API tokens, relay tokens +3. **Ingress/Gateway** - External traffic routing and TLS termination +4. **Relay** (optional) - If any routes use relay mode, configure gatekeeper-relay + +### Step 1: Deployment Context + +Ask: "Tell me about your Kubernetes environment:" + +- **Namespace**: Where will gatekeeper be deployed? +- **Cluster type**: What ingress/gateway controller do you use? + - nginx-ingress (traditional Ingress API) + - Traefik Ingress + - Traefik Gateway API + - Istio Gateway + - Other Gateway API implementation + - None (LoadBalancer service directly) +- **TLS**: How do you manage certificates? + - cert-manager with Let's Encrypt + - cert-manager with internal CA + - External certificates (manually managed) + - Built-in ACME (single replica only) + +### Step 2: Configure Routes + +For each webhook route they need, guide them through route configuration. + +Ask: "How many webhook routes do you need to configure?" + +For each route, either: +- Run through the `/configure-route` flow interactively +- Or ask them to describe all routes at once if they prefer + +Collect for each route: +- Provider type +- Hostname +- Path +- Delivery mode (direct or relay) +- Destination URL + +Track which routes use relay mode - this determines whether gatekeeper-relay is needed. + +### Step 3: Secrets Configuration + +Ask: "How will you manage secrets?" + +**Option A: Helm-managed secrets** (simpler) +- Secrets are defined in values.yaml +- Good for development/testing +- Warn: Don't commit secrets to version control + +**Option B: External secret management** (production recommended) +- Use `existingSecret` to reference a pre-created Kubernetes Secret +- Works with External Secrets Operator, Sealed Secrets, Vault, etc. +- Provide the secret name they'll use + +Generate the secrets section based on the configured routes: +- Signing secrets for each verifier +- Relay tokens for relay routes + +### Step 4: Ingress/Gateway Configuration + +Based on their cluster type from Step 1: + +#### For nginx-ingress or Traefik Ingress + +```yaml +ingress: + enabled: true + className: "nginx" # or "traefik" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + tls: + enabled: true +``` + +#### For Traefik Gateway API + +Ask: "Do you want gatekeeper to create its own Gateway, or attach to an existing one?" + +**Create own Gateway** (recommended for proper TLS handling): +```yaml +gateway: + enabled: true + create: true + gatewayClassName: "traefik" + port: 8443 + tls: + enabled: true + issuerName: "letsencrypt-prod" + issuerKind: ClusterIssuer +``` + +**Attach to existing Gateway**: +```yaml +gateway: + enabled: true + create: false + gatewayName: "traefik-gateway" + gatewayNamespace: "traefik" + tls: + enabled: true + issuerName: "letsencrypt-prod" + issuerKind: ClusterIssuer +``` + +#### For LoadBalancer (no ingress) + +```yaml +service: + type: LoadBalancer + annotations: {} # Cloud-specific annotations if needed + +# If using built-in ACME (requires ports 80/443): +tls: + enabled: true + acmeEmail: "certs@example.com" +``` + +Note: Built-in ACME only works with single replica. + +### Step 5: Replica Count and Redis + +Ask: "How many replicas do you need?" + +For single replica: +```yaml +replicaCount: 1 +``` + +For multiple replicas: +- If any routes use relay mode, Redis/Valkey is **required** for coordination +- Explain: Without Redis, each replica maintains its own queue, breaking delivery guarantees + +```yaml +replicaCount: 2 + +redis: + enabled: true + bundled: true # Deploy Valkey as subchart +``` + +Or for external Redis: +```yaml +redis: + enabled: true + bundled: false + host: "redis.example.com" + port: 6379 + # password: "" # or use existingSecret +``` + +### Step 6: Relay Configuration (if needed) + +If any routes use relay mode, generate the gatekeeper-relay values. + +Ask: "Where will the relay client run?" +- Same cluster as gatekeeperd (different namespace) +- Different cluster (private network) +- Docker/VM in private network + +Generate relay values: + +```yaml +# gatekeeper-relay values.yaml +server: "https://{gatekeeperd-external-hostname}" + +channels: + - name: {provider}-webhooks + tokenKey: RELAY_TOKEN_{PROVIDER} + destination: "http://{internal-service}:{port}{path}" + workers: 1 # Increase for high-volume webhooks +``` + +For each relay route, ensure the relay token is defined in both: +1. gatekeeperd secrets (for webhook receipt) +2. gatekeeper-relay secrets (for relay client authentication) + +### Step 7: Generate Complete Configuration + +Generate the complete values files with clear sections: + +#### gatekeeperd/values.yaml + +```yaml +# ============================================================================== +# GATEKEEPER HELM VALUES +# Generated by /configure-helm +# ============================================================================== + +replicaCount: {replica-count} + +# ------------------------------------------------------------------------------ +# INGRESS / GATEWAY +# ------------------------------------------------------------------------------ +{ingress-or-gateway-config} + +# ------------------------------------------------------------------------------ +# REDIS (required for multi-replica with relay) +# ------------------------------------------------------------------------------ +{redis-config-if-needed} + +# ------------------------------------------------------------------------------ +# IP ALLOWLISTS +# (predefined lists are already included, add custom ones here) +# ------------------------------------------------------------------------------ +ipAllowlists: {} + +# ------------------------------------------------------------------------------ +# VERIFIERS +# ------------------------------------------------------------------------------ +verifiers: +{verifier-configs} + +# ------------------------------------------------------------------------------ +# ROUTES +# ------------------------------------------------------------------------------ +routes: +{route-configs} + +# ------------------------------------------------------------------------------ +# SECRETS +# ------------------------------------------------------------------------------ +{secrets-or-existingSecret} +``` + +#### gatekeeper-relay/values.yaml (if relay routes exist) + +```yaml +# ============================================================================== +# GATEKEEPER-RELAY HELM VALUES +# Generated by /configure-helm +# ============================================================================== + +server: "https://{external-hostname}" + +maxConsecutiveFailures: 10 + +channels: +{channel-configs} + +{secrets-or-existingSecret} +``` + +### Step 8: Deployment Instructions + +Provide deployment commands: + +```bash +# Create namespace +kubectl create namespace {namespace} + +# If using external secrets, create the secret first: +kubectl create secret generic gatekeeper-secrets \ + --from-literal=SLACK_SIGNING_SECRET='...' \ + --from-literal=RELAY_TOKEN_SLACK='...' \ + -n {namespace} + +# Deploy gatekeeperd +helm upgrade --install gatekeeperd ./charts/gatekeeperd \ + -f gatekeeperd-values.yaml \ + -n {namespace} + +# If using relay, deploy relay client: +helm upgrade --install gatekeeper-relay ./charts/gatekeeper-relay \ + -f relay-values.yaml \ + -n {namespace} + +# Verify deployment +kubectl get pods -n {namespace} +kubectl logs -l app.kubernetes.io/name=gatekeeperd -n {namespace} +``` + +### Step 9: Post-Deployment Checklist + +Provide a checklist for the user: + +- [ ] DNS records point to the ingress/gateway/LoadBalancer IP +- [ ] TLS certificates are issued (check `kubectl get certificate -n {namespace}`) +- [ ] Pods are running (`kubectl get pods -n {namespace}`) +- [ ] Health endpoint responds (`curl https://{hostname}/healthz`) +- [ ] Test webhook delivery from provider +- [ ] If using relay, verify relay client is connected (check logs) + +### Conversation Style + +- Be concise and direct +- Ask one question at a time +- For route configuration, offer to run through `/configure-route` for each or collect all at once +- Generate complete, ready-to-use values files +- Explain trade-offs (e.g., bundled vs external Redis) +- Use code blocks for all configuration snippets +- Provide copy-pasteable deployment commands + +### Common Configurations + +#### Minimal Single-Route (Direct Mode) + +```yaml +# gatekeeperd values.yaml +replicaCount: 1 + +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + tls: + enabled: true + +verifiers: + slack: + type: slack + signingSecretKey: SLACK_SIGNING_SECRET + +routes: + - hostname: webhooks.example.com + path: /slack + ipAllowlist: aws + verifier: slack + destination: http://backend:8080/webhooks/slack + +secrets: + SLACK_SIGNING_SECRET: "xoxb-your-secret" +``` + +#### Multi-Route with Relay + +```yaml +# gatekeeperd values.yaml +replicaCount: 2 + +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + tls: + enabled: true + +redis: + enabled: true + bundled: true + +verifiers: + slack: + type: slack + signingSecretKey: SLACK_SIGNING_SECRET + github: + type: github + secretKey: GITHUB_WEBHOOK_SECRET + +routes: + # Direct route + - hostname: webhooks.example.com + path: /slack + ipAllowlist: aws + verifier: slack + destination: http://backend:8080/webhooks/slack + + # Relay route (for private network) + - hostname: webhooks.example.com + path: /github + ipAllowlist: github + verifier: github + relayTokenKey: RELAY_TOKEN_GITHUB + +existingSecret: "gatekeeper-secrets" +``` + +```yaml +# gatekeeper-relay values.yaml +server: "https://webhooks.example.com" + +channels: + - name: github-webhooks + tokenKey: RELAY_TOKEN_GITHUB + destination: "http://localhost:8080/webhooks/github" + workers: 5 + +existingSecret: "relay-secrets" +``` + +#### Gateway API with Traefik + +```yaml +# gatekeeperd values.yaml +replicaCount: 2 + +gateway: + enabled: true + create: true + gatewayClassName: "traefik" + port: 8443 + tls: + enabled: true + issuerName: "letsencrypt-prod" + issuerKind: ClusterIssuer + +redis: + enabled: true + bundled: true + +verifiers: + ms-graph: + type: json_field + path: "value.0.clientState.tpVerificationToken" + tokenKey: MS_GRAPH_CLIENT_STATE + +routes: + - hostname: graph-webhooks.example.com + path: /notifications + ipAllowlist: microsoft-graph + verifier: ms-graph + relayTokenKey: RELAY_TOKEN_GRAPH + +existingSecret: "gatekeeper-secrets" +``` diff --git a/agents/configure-route.md b/agents/configure-route.md new file mode 100644 index 0000000..b7007c2 --- /dev/null +++ b/agents/configure-route.md @@ -0,0 +1,371 @@ +# Configure Route Skill + +This skill walks users through configuring a new webhook route for gatekeeper. + +## Usage + +- **Claude Code**: `/configure-route` +- **Any AI assistant**: "I want to configure a webhook for [provider]" + +## Instructions + +When the user wants to configure a new webhook route, guide them through these steps interactively. Ask one question at a time and wait for their response before proceeding. + +### Step 1: Identify the Provider + +Ask which webhook provider they want to configure. Offer these options: + +- **Slack** - Slack Events API, slash commands, interactive components +- **GitHub** - Repository webhooks, organization webhooks +- **Shopify** - Store webhooks (orders, products, customers) +- **Google Calendar** - Calendar push notifications (X-Goog-Channel-Token header) +- **Microsoft Graph** - Outlook Calendar, OneDrive change notifications (token in JSON body) +- **Generic HMAC** - Any provider using HMAC signatures (configurable algorithm/encoding) +- **API Key (Header)** - Providers using simple header token authentication +- **Query Parameter Token** - Providers that send a token in the URL query string +- **Header Query Parameter** - Providers that encode key=value pairs inside a header +- **Other** - Help them determine the best approach + +### Step 2: External Hostname + +Ask: "What hostname will [provider] send webhooks to?" + +Example: `slack-webhooks.example.com` or `webhooks.mycompany.com` + +This is the public DNS name that will receive webhook traffic. + +### Step 3: Path + +Ask: "What path should this route match?" + +Default suggestion: `/` (matches all paths) + +Explain: Routes use segment-aware prefix matching. A route with path `/hooks` matches `/hooks` and `/hooks/github` but NOT `/hookshot`. + +### Step 4: Delivery Mode + +Ask: "How should webhooks be delivered to your internal service?" + +**Option A: Direct forwarding** +- Gatekeeperd forwards directly to your backend +- Requires a firewall rule allowing traffic from gatekeeperd to your internal service +- Lower latency, simpler setup if firewall access is available + +**Option B: Relay client** +- A relay client inside your network polls gatekeeperd for webhooks +- No inbound firewall rules needed +- Only requires outbound HTTPS from your network to gatekeeperd + +### Step 5: Internal Destination + +Ask: "What is the internal URL where webhooks should be delivered?" + +For direct mode: This is the full URL gatekeeperd will forward to. +For relay mode: This is the URL the relay client will forward to locally. + +Suggest provider-specific defaults: +- Slack: `http://your-app:8080/webhooks/slack` or `/slack/events` +- GitHub: `http://your-app:8080/webhooks/github` or `/github/events` +- Shopify: `http://your-app:8080/webhooks/shopify` +- Google Calendar: `http://your-app:8080/webhooks/gcal` or `/calendar/notifications` +- Microsoft Graph: `http://your-app:8080/webhooks/graph` or `/graph/notifications` + +### Step 6: Additional Options + +Ask about optional configuration: + +**IP Allowlist**: "Do you want to restrict requests by source IP?" +- Recommend allowlists for the provider (aws for Slack, github for GitHub, google for Google Calendar, etc.) +- Explain: IP allowlists add defense-in-depth but are optional since signature verification is the primary authentication + +**Preserve Host Header**: "Should the original Host header be passed to your backend?" +- Default: No (destination hostname is used) +- Enable if: Backend needs to see the original public hostname + +**Payload Validation**: "Do you want to validate the payload structure with JSON Schema?" +- Optional defense-in-depth against malformed payloads +- Pre-built schemas available for common providers in `schemas/` directory + +### Step 7: Generate Configuration + +Based on their answers, generate the complete configuration. + +#### For Direct Mode + +```yaml +# Add to gatekeeperd.yaml + +verifiers: + {verifier-name}: + {provider-specific-config} + +# Optional: Add validator if requested +validators: + {validator-name}: + type: json_schema + schema_file: "schemas/{provider}/{event_type}.json" + +routes: + - hostname: {hostname} + path: {path} + ip_allowlist: {recommended-allowlist} # if applicable + verifier: {verifier-name} + validator: {validator-name} # if applicable + destination: {destination-url} + preserve_host: {true/false} # if enabled +``` + +#### For Relay Mode + +Generate both server and client configs: + +```yaml +# Add to gatekeeperd.yaml + +verifiers: + {verifier-name}: + {provider-specific-config} + +routes: + - hostname: {hostname} + path: {path} + ip_allowlist: {recommended-allowlist} # if applicable + verifier: {verifier-name} + relay_token: "${RELAY_TOKEN_{PROVIDER}}" +``` + +```yaml +# Add to gatekeeper-relay.yaml + +channels: + - name: {provider}-webhooks + token: "${RELAY_TOKEN_{PROVIDER}}" + destination: "{local-destination}" + workers: 1 # Increase for high-volume webhooks +``` + +### Step 8: Provider-Specific Setup Instructions + +After generating the configuration, provide setup instructions specific to the provider. + +#### Slack + +1. Go to https://api.slack.com/apps and select your app +2. Navigate to "Event Subscriptions" (or "Interactivity & Shortcuts" for interactive components) +3. Set the Request URL to: `https://{hostname}{path}` +4. Copy the "Signing Secret" from "Basic Information" +5. Set the environment variable: `export SLACK_SIGNING_SECRET="your-signing-secret"` + +**Note**: Gatekeeper automatically handles Slack URL verification challenges. When Slack sends a `url_verification` request during webhook setup, gatekeeper responds immediately with the challenge - your backend does not need to handle this. + +Configuration uses: +```yaml +verifiers: + slack: + type: slack + signing_secret: "${SLACK_SIGNING_SECRET}" + max_timestamp_age: 5m # Replay attack protection (default: 5m) +``` + +Recommended IP allowlist: `aws` (Slack runs on AWS) +```yaml +ip_allowlists: + aws: + fetch_url: "https://ip-ranges.amazonaws.com/ip-ranges.json" + fetch_jq: ".prefixes[].ip_prefix" + refresh_interval: 24h +``` + +#### GitHub + +1. Go to your repository or organization settings +2. Navigate to "Webhooks" and click "Add webhook" +3. Set Payload URL to: `https://{hostname}{path}` +4. Set Content type to: `application/json` +5. Generate a secret and enter it in the "Secret" field +6. Set the environment variable: `export GITHUB_WEBHOOK_SECRET="your-secret"` + +Configuration uses: +```yaml +verifiers: + github: + type: github + secret: "${GITHUB_WEBHOOK_SECRET}" +``` + +Recommended IP allowlist: GitHub publishes their IP ranges at https://api.github.com/meta +```yaml +ip_allowlists: + github: + fetch_url: "https://api.github.com/meta" + fetch_jq: ".hooks[]" + refresh_interval: 24h +``` + +#### Shopify + +1. Go to your Shopify admin panel +2. Navigate to Settings > Notifications > Webhooks +3. Click "Create webhook" +4. Select the event and set the URL to: `https://{hostname}{path}` +5. Note the webhook signing secret shown after creation +6. Set the environment variable: `export SHOPIFY_WEBHOOK_SECRET="your-secret"` + +Configuration uses: +```yaml +verifiers: + shopify: + type: shopify + secret: "${SHOPIFY_WEBHOOK_SECRET}" +``` + +#### Google Calendar + +1. Use the Google Calendar API to create a watch request +2. Set the `address` to: `https://{hostname}{path}` +3. Set a `token` value in your watch request (this is your shared secret) +4. Set the environment variable: `export GCAL_CHANNEL_TOKEN="your-token"` + +Configuration uses: +```yaml +verifiers: + gcal: + type: api_key + header: "X-Goog-Channel-Token" + token: "${GCAL_CHANNEL_TOKEN}" +``` + +Recommended IP allowlist: +```yaml +ip_allowlists: + google: + fetch_url: "https://www.gstatic.com/ipranges/goog.json" + fetch_jq: ".prefixes[].ipv4Prefix" + refresh_interval: 24h +``` + +#### Microsoft Graph (Outlook Calendar, OneDrive, etc.) + +Microsoft Graph change notifications embed the verification token in the JSON body, not a header. + +1. When creating a subscription, set the `clientState` property to include your verification token +2. Use a JSON structure like: `{"tpVerificationToken":"your-secret","routing":"data"}` +3. Set the environment variable: `export MS_GRAPH_CLIENT_STATE="your-secret"` +4. Set the notification URL to: `https://{hostname}{path}` + +Configuration uses: +```yaml +verifiers: + ms-graph: + type: json_field + path: "value.0.clientState.tpVerificationToken" # Path to token in JSON body + token: "${MS_GRAPH_CLIENT_STATE}" +``` + +Path syntax: +- Uses dot notation for nested fields +- Array indices are numbers (e.g., `value.0` for first element) +- Auto-parses JSON strings (if `clientState` is `{"tpVerificationToken":"x"}`, the path extracts `x`) + +Recommended IP allowlist: +```yaml +ip_allowlists: + microsoft-graph: + cidrs: + - "20.20.32.0/19" + - "20.190.128.0/18" + - "20.231.128.0/19" + - "40.126.0.0/18" +``` + +#### Generic HMAC + +Ask the user for: +- Header name containing the signature +- Hash algorithm (SHA256 or SHA512) +- Encoding (hex or base64) + +Configuration uses: +```yaml +verifiers: + custom-hmac: + type: hmac + secret: "${WEBHOOK_SECRET}" + header: "X-Signature" # Header containing signature + hash: SHA256 # SHA256 or SHA512 + encoding: hex # hex or base64 +``` + +#### API Key (Header) + +Ask the user for: +- Header name containing the token + +Configuration uses: +```yaml +verifiers: + custom-apikey: + type: api_key + header: "X-Webhook-Token" + token: "${WEBHOOK_TOKEN}" +``` + +#### Query Parameter Token + +Some providers send a verification token as a URL query parameter (e.g., `?token=secret`). + +Ask the user for: +- Query parameter name (e.g., `token`, `verify`, `secret`) + +Configuration uses: +```yaml +verifiers: + url-token: + type: query_param + name: "token" # Query parameter name + token: "${WEBHOOK_URL_TOKEN}" +``` + +#### Header Query Parameter + +Some providers encode multiple key=value pairs inside a header (e.g., `X-Custom-Header: key1=value1&key2=value2`). + +Ask the user for: +- Header name +- Key name within the header + +Configuration uses: +```yaml +verifiers: + header-param: + type: header_query_param + header: "X-Goog-Channel-Token" # Header containing the encoded parameters + name: "secret" # Key name to extract + token: "${CHANNEL_SECRET}" +``` + +### Step 9: Environment Variables Summary + +At the end, summarize all environment variables that need to be set: + +```bash +# Required environment variables for this configuration: +export {VAR_NAME}="your-value-here" + +# For relay mode, also set: +export RELAY_TOKEN_{PROVIDER}="generate-a-secure-random-token" +``` + +Remind them: +- Never commit secrets to version control +- Use Kubernetes Secrets or a secret manager in production +- For relay tokens, generate a secure random value (e.g., `openssl rand -hex 32`) + +### Conversation Style + +- Be concise and direct +- Ask one question at a time +- Provide sensible defaults where possible +- Explain trade-offs when relevant (e.g., direct vs relay mode) +- Use code blocks for all configuration snippets +- After generating config, offer to help with additional routes or a complete Helm deployment (see `configure-helm` skill) diff --git a/docs/USAGE.md b/docs/USAGE.md index b983f49..98080cc 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -405,46 +405,66 @@ Use log aggregation tools (Loki, Elasticsearch, CloudWatch) to collect and query --- -## Interactive Route Configuration (Claude Code) +## Interactive Configuration (AI Skills) -If you use [Claude Code](https://github.com/anthropics/claude-code), gatekeeper includes an interactive skill to help configure new webhook routes. +Gatekeeper includes AI skills for interactive configuration. These work with Claude Code (as slash commands), Claude.ai, or any AI assistant that can follow the skill instructions. -### Usage +### Available Skills -Invoke the skill with: +| Skill | Claude Code | Description | +|-------|-------------|-------------| +| Configure Route | `/configure-route` | Walks through provider selection, delivery mode, verifier setup | +| Configure Helm | `/configure-helm` | Wraps multiple routes plus ingress/gateway, TLS, secrets, relay | -``` -/configure-route -``` - -Or simply ask: "I want to configure a webhook for Slack" +### Configure Route -### What It Does +Invoke with `/configure-route` in Claude Code, or ask any AI assistant: "I want to configure a webhook for Slack" -The skill walks you through configuring a new webhook route step by step: +The skill walks you through: -1. **Provider selection** - Slack, GitHub, Shopify, Google Calendar, or generic HMAC/API key +1. **Provider selection** - Slack, GitHub, Shopify, Google Calendar, Microsoft Graph, or generic options 2. **External hostname** - The public DNS name for receiving webhooks -3. **Delivery mode** - Direct forwarding or relay client -4. **Internal destination** - Where webhooks should be delivered +3. **Path** - URL path to match (with segment-aware prefix matching) +4. **Delivery mode** - Direct forwarding or relay client +5. **Internal destination** - Where webhooks should be delivered +6. **Optional settings** - IP allowlist, preserve_host, JSON Schema validation -After gathering this information, it generates: - -- Complete `gatekeeperd.yaml` configuration stanza -- Relay client configuration (if using relay mode) -- Provider-specific setup instructions (where to find signing secrets, etc.) -- Environment variable summary +After gathering this information, it generates complete configuration for gatekeeperd and (if relay mode) gatekeeper-relay, plus provider-specific setup instructions. ### Supported Providers -| Provider | Verifier Type | Setup Guidance | -|----------|---------------|----------------| -| Slack | `slack` | Events API, signing secret location. URL verification handled automatically. | -| GitHub | `github` | Repository/org webhook setup | -| Shopify | `shopify` | Admin panel webhook configuration | -| Google Calendar | `api_key` | Calendar API watch requests | -| Generic HMAC | `hmac` | Configurable algorithm/encoding | +| Provider | Verifier Type | Notes | +|----------|---------------|-------| +| Slack | `slack` | HMAC-SHA256 with replay protection. URL verification handled automatically. | +| GitHub | `github` | HMAC-SHA256 | +| Shopify | `shopify` | HMAC-SHA256 base64 | +| Google Calendar | `api_key` | X-Goog-Channel-Token header | +| Microsoft Graph | `json_field` | Token embedded in JSON body | +| Generic HMAC | `hmac` | Configurable algorithm (SHA256/SHA512) and encoding (hex/base64) | | API Key | `api_key` | Simple header token | +| Query Parameter | `query_param` | Token in URL query string | +| Header Query Param | `header_query_param` | Key=value pairs encoded in header | + +### Configure Helm + +Invoke with `/configure-helm` in Claude Code, or ask any AI assistant: "Help me deploy gatekeeper to Kubernetes" + +The skill guides you through a complete Helm deployment: + +1. **Deployment context** - Namespace, ingress/gateway type, TLS management +2. **Routes** - Configure multiple routes (runs `/configure-route` for each) +3. **Secrets** - Helm-managed or external secret management +4. **Ingress/Gateway** - nginx, Traefik Ingress, Gateway API, or LoadBalancer +5. **Replicas and Redis** - Multi-replica coordination for relay routes +6. **Relay deployment** - gatekeeper-relay configuration if needed + +Generates complete, ready-to-use values files for both charts plus deployment commands. + +### Skill Documentation + +The full skill definitions are in [`agents/`](../agents/): +- [`agents/configure-route.md`](../agents/configure-route.md) +- [`agents/configure-helm.md`](../agents/configure-helm.md) ### Example Session @@ -456,8 +476,11 @@ Claude: Which webhook provider do you want to configure? - GitHub - Shopify - Google Calendar +- Microsoft Graph - Generic HMAC - API Key +- Query Parameter Token +- Header Query Parameter You: Slack @@ -478,4 +501,7 @@ You: http://internal.example.com:8080/webhooks/slack Claude: Here's your configuration... [generates complete config for both server and relay client] + +Claude: Would you like to configure another route, or set up the Helm deployment? +Use /configure-helm for a complete Kubernetes deployment with ingress and TLS. ```