MultiJuicer

repository·main·Indexed 43 days ago

https://github.com/juice-shop/multi-juicer

A platform for running multiple, isolated OWASP Juice Shop instances on a central Kubernetes cluster, designed for CTFs and security training. It features dynamic instance creation, a leaderboard, an admin dashboard, and a custom LoadBalancer for participant routing. MultiJuicer includes a Go-based orchestrator, a React/TypeScript frontend, and an optional LLM gateway for secure AI chatbot proxying.

Tokens
25K
Snippets
72
Records
102
Agent score
52%

What's inside MultiJuicer

  1. What is MultiJuicer?

    main

    MultiJuicer is a platform designed to run OWASP Juice Shop for multiple users simultaneously on a central Kubernetes cluster. It is specifically built for hosting CTFs (Capture The Flag) and security training events.

    Key Capabilities:

    • Dynamic Instance Creation: Automatically spins up new, isolated Juice Shop instances for participants as needed.
    • Unified Access: Operates on a single domain using a LoadBalancer that routes traffic to the specific participant's instance.
    • Persistence: Backs up and automatically applies challenge progress if a Juice Shop container restarts.
    • Automated Cleanup: Automatically removes old or unused Juice Shop instances to conserve cluster resources.
  2. Overview of MultiJuicer Architecture

    main

    MultiJuicer is a multi-user platform designed for running OWASP Juice Shop CTF events and security trainings on a Kubernetes cluster. It dynamically manages separate Juice Shop instances for each participating team.

    The platform is delivered as a single Go binary (the MultiJuicer service) that provides:

    • An HTTP frontend, scoreboard, and admin API.
    • Lifecycle management for per-team Juice Shop instances (creation, routing, restarts, and deletion).
    • A webhook receiver for recording challenge solutions.
    • A background reconciliation loop to prevent progress loss during pod restarts.
    • Periodic cleanup of inactive deployments.
    • An optional LLM gateway for proxying chatbot requests to an upstream OpenAI-compatible API.
  3. Estimate compute resource requirements

    main

    When planning your Kubernetes cluster capacity, use the following baseline estimates for resource limits:

    • MultiJuicer Core: 1GB memory & 1 CPU overhead.
    • Per JuiceShop Instance: 300MB memory & 0.2 CPU per participant or team.

    Note: These values can be adjusted by customizing the Helm configuration.

  4. How challenge solution tracking and scoring works

    main

    MultiJuicer tracks progress by intercepting events from Juice Shop instances and using Kubernetes annotations as a source of truth.

    Challenge Solving Flow

    1. Webhook: When a user solves a challenge, the Juice Shop instance sends a webhook to http://multijuicer-private.{ns}.svc.cluster.local:8082/team/{team}/webhook.
    2. Persistence: The webhook handler validates the payload and updates the team's Kubernetes deployment annotations with the new solution.
    3. Reconciliation: A background sync loop (running on the leader node) periodically reconciles persisted progress with the live Juice Shop state, re-applying 'continue codes' if a pod restarts with empty progress.
    4. Scoring: The scoring service monitors deployment annotations. When changes are detected, it recalculates scores.
    5. Updates: Frontend clients receive these score updates via long polling.
  5. MultiJuicer Frontend Architecture and Hooks

    main

    The web frontend is a React/TypeScript application built with Vite. It provides interfaces for participants (joining teams, viewing scoreboards) and admins (managing instances).

    Data Fetching via Custom Hooks The frontend uses specialized React hooks to manage real-time data via HTTP long polling:

    • useHttpLongPoll: A generic implementation for long polling.
    • useScoreboard: Fetches the global leaderboard.
    • useTeamStatus: Fetches status for the current user or a specific team.
    • useActivityFeed: Fetches the recent activity feed of challenge solutions.
  6. How team joining and instance creation works

    main

    When a user joins a team, MultiJuicer automates the provisioning of a dedicated Juice Shop environment. The process follows these steps:

    1. Authentication: The user submits a team name and passcode to the join endpoint.
    2. Provisioning: MultiJuicer creates a unique Kubernetes deployment and service for that team.
    3. LLM Setup (Optional): If the LLM gateway is enabled, MultiJuicer creates a per-team Kubernetes Secret containing an HMAC-signed team token. This token is mounted into the Juice Shop pod as the LLM_API_KEY environment variable.
    4. Session Management: MultiJuicer sets a signed cookie to associate the user's browser session with their team.
    5. Access: The user is redirected to their specific team's Juice Shop instance via a proxy.
  7. Security considerations for the LLM Gateway

    main

    While the LLM Gateway provides significant protection against API key theft, be aware of the following:

    • RBAC Permissions: Enabling the gateway requires MultiJuicer's service account to have permissions to create Secrets in the namespace. It is highly recommended to run MultiJuicer in a dedicated namespace to prevent it from having read access to other workloads' secrets.
    • No Rate Limiting: The gateway does not currently enforce per-team rate limits. A participant could potentially consume significant tokens via rapid requests. Monitor usage annotations and set spending limits at your LLM provider.
    • Token Scope: A team's token grants access to the full LLM API through the gateway. If your provider exposes other endpoints (e.g., embeddings, image generation), they are accessible via the token.
    • Internal Access: If a participant extracts their team token via RCE, they can make direct requests to the gateway from within the cluster, bypassing the JuiceShop UI.
  8. How instance cleanup is managed

    main

    To manage resources, MultiJuicer automatically deletes inactive team instances.

    • Mechanism: A cleanup ticker runs on the leader node (defaulting to every 1 minute).
    • Criteria: It checks the multi-juicer.owasp-juice.shop/lastRequest annotation on all Juice Shop deployments.
    • Action: If the time since the last request exceeds the configured grace period, the deployment is deleted. Associated Services and per-team Secrets are automatically cleaned up via Kubernetes OwnerReferences.
  9. How MultiJuicer handles progress reconciliation and cleanup

    main

    MultiJuicer uses background processes to ensure platform stability and resource efficiency. To prevent multiple replicas from running these tasks simultaneously, it uses leader election via a Kubernetes Lease named multi-juicer-leader.

    Progress Reconciliation

    • Webhooks received via the internal port are persisted as JSON annotations on the team's deployment.
    • A leader-only background loop (running every 60 seconds) fetches the live challenge state from Juice Shop pods and compares it to the persisted state. If the live state has regressed (e.g., due to a pod restart), the loop re-applies the saved 'continue code' to restore progress.

    Inactive-Instance Cleanup

    • A leader-only ticker (defaulting to 1 minute) identifies Juice Shop deployments that have exceeded the inactivity threshold defined by config.juiceShop.deleteInactiveAfter (default 24h).
    • Cleanup is based on the multi-juicer.owasp-juice.shop/lastRequest annotation.
    • When a deployment is deleted, its associated Service and (if LLM is enabled) Secret are automatically garbage-collected via Kubernetes OwnerReferences.
  10. MultiJuicer Deployment Architecture

    main

    The system is deployed via Helm and consists of two primary workload types:

    MultiJuicer (Core Service)

    • Replicas: 1 or more replicas behind a LoadBalancer/Ingress on port :8080.
    • Internal Ports: Exposes :8082 via a cluster-internal multijuicer-private ClusterIP Service for webhooks and the LLM gateway.
    • Leader Election: Uses Kubernetes Lease-based leader election to ensure singleton background tasks (like progress reconciliation and cleanup) are only performed by one replica.

    Juice Shop Instances

    • Lifecycle: Individual Deployments and Services created on-demand per team by the MultiJuicer service.

    Deployment is managed via the Helm chart located in helm/multi-juicer/.

  11. How the LLM Gateway works

    main

    When enabled, the LLM gateway allows Juice Shop instances to use LLM capabilities securely.

    1. Authentication: The Juice Shop chatbot calls the cluster-internal multijuicer-private service using the team's LLM_API_KEY (the signed token) as a bearer token.
    2. Validation: The gateway validates the bearer token against the cookie signing key to identify the team.
    3. Proxying: The gateway substitutes the real upstream API key (which is only stored in MultiJuicer) and reverse-proxies the request to the configured upstream LLM API.
    4. Usage Tracking: The gateway parses usage fields from chat-completion responses (supporting both JSON and SSE) and accumulates token counts in memory per team.
    5. Persistence: A periodic flusher writes these accumulated token counts to the team's deployment annotations using optimistic concurrency.