๐Ÿš€ Quick Deploy โ€” Control Plane, Bouncer, and First Control

Audience: DevOps / Platform engineers + Control authors Time: ~60 min ยท uses Docker Compose

This guide is your starting point. It takes you from zero to a working enforcement setup โ€” Control Plane running, a Bouncer protecting a resource, and your first control enforcing decisions. Once complete, the Deploy & Operate section covers production topologies, Helm deployment, and scaling โ€” use those guides to move beyond this initial setup.

Going straight to production? See Installation (Helm / DevOps reference) for the full Kubernetes and Helm configuration reference.

By the end of this guide you will have:

  1. A running Control Plane on your infrastructure โœ“
  2. A Bouncer intercepting traffic to a resource you own โœ“
  3. Your first control authored, deployed to sandbox, and enforcing โœ“
  4. A visible audit decision confirming enforcement โœ“

๐Ÿ“Œ Before you start

RequirementMinimum
Linux VM (or local Docker)2 vCPU, 4 GB RAM
Docker Engine20.10+
Docker Compose2.0+
Ports available3000, 8080, 8082, 7000
GitHub repo (for controls)Any private repo + Personal Access Token
Deployment packageDownload from info@controlcore.io or your account

Troubleshooting: Unsure which ports are in use? Run ss -tlnp | grep -E '3000|8080|8082|7000' before starting. If any port is taken, map the service to a free port in your .env file using the _PORT override vars.


๐Ÿš€ Stage 1 โ€” Deploy the Control Plane (~20 min)

TL;DR โ€” 6 commands to a running Control Plane

# 1. Extract your package
unzip controlcore-kickstart.zip && cd controlcore-kickstart

# 2. Copy and fill the env template
cp .env.example .env
# Edit .env: set DATABASE_*, REDIS_*, SECRET_KEY, JWT_SECRET_KEY,
#             CC_BUILTIN_ADMIN_PASS, GITHUB_TOKEN, POLICY_REPO_URL,
#             and CONTROL_PLANE_PUBLIC_URL

# 3. Start the stack
docker compose up -d

# 4. Wait for health (run until all return "healthy")
watch docker compose ps

# 5. Verify the Control Plane API
curl -s http://localhost:8082/api/v1/health | jq .status

# 6. Open the console
open http://localhost:3000

Expected output of step 5: "ready" โ€” if you see this, Stage 1 is done.

Detailed steps

Step 1 โ€” Fill .env values (~5 min)

The minimum required variables are:

# Control Plane identity
CONTROL_PLANE_PUBLIC_URL=https://controlplane.yourcompany.com   # or http://localhost:3000 for local

# Database (PostgreSQL)
DATABASE_URL=postgresql://ccuser:ccpassword@db:5432/controlcore

# Cache (Redis)
REDIS_URL=redis://:redispassword@redis:6379/0

# Secrets (generate with: openssl rand -hex 32)
SECRET_KEY=<32-char-random>
JWT_SECRET_KEY=<32-char-random>

# Admin password (change after first login)
CC_BUILTIN_ADMIN_PASS=<strong-password>

# GitHub controls repo
GITHUB_TOKEN=<your-github-pat>
POLICY_REPO_URL=https://github.com/your-org/your-controls-repo
POLICY_REPO_BRANCH=main

Troubleshooting: If docker compose up -d fails with port already allocated, the port is in use. Add CONTROL_PLANE_UI_PORT=3001 (or similar) to .env to use a different port. See Deployment Guide for full port mapping vars.

Step 2 โ€” Start the stack (~5 min)

docker compose up -d
docker compose ps   # all services should be "healthy" within 60โ€“90 seconds

Troubleshooting: If a service stays starting after 2 min:

  • docker compose logs control-plane-api โ€” look for DATABASE_URL or REDIS_URL errors
  • docker compose logs db โ€” check PostgreSQL started correctly
  • Verify env values: docker compose config | grep DATABASE_URL Full reference: Troubleshooting โ€” Deployment issues

Step 3 โ€” First login (~2 min)

  1. Open http://localhost:3000 (or your CONTROL_PLANE_PUBLIC_URL)
  2. Log in with username admin and the password you set in CC_BUILTIN_ADMIN_PASS
  3. Go to Profile โ†’ Change Password โ€” do this now

Step 4 โ€” Create API keys (~3 min)

  1. Go to Settings โ†’ Environments
  2. Create a Sandbox API key โ€” copy it, you need it in Stage 2
  3. Create a Production API key โ€” copy and store securely

Troubleshooting: If Settings โ†’ Environments shows no environments, check that the Control Plane API container (control-plane-api) is healthy. Run curl http://localhost:8082/api/v1/health โ€” if it returns an error, check docker compose logs control-plane-api.

Stage 1 done โœ“ โ€” You have a running Control Plane. The console is accessible and you have API keys.


๐Ÿš€ Stage 2 โ€” Deploy a Bouncer to protect a resource (~15 min)

A Bouncer is the enforcement component you place in front of the resource you want to protect. Requests go through the Bouncer, which enforces your controls, before reaching the resource.

You need: the Sandbox API key from Stage 1, and a running resource (API, app, or service) to protect. The Bouncer will act as a reverse proxy in front of it.

Bouncer configuration

Create a new .env.bouncer file (or a separate Compose file):

# Bouncer identity
BOUNCER_ID=bouncer-sandbox-01
BOUNCER_NAME=My First Bouncer
BOUNCER_TYPE=reverse-proxy         # or: sidecar
ENVIRONMENT=sandbox

# Connect to Control Plane
PAP_API_URL=http://localhost:8082  # use your CONTROL_PLANE_PUBLIC_URL
API_KEY=<your-sandbox-api-key>     # from Stage 1 Step 4

# Resource being protected
RESOURCE_NAME=My API               # human-readable label (used to pair Sandbox+Production)
RESOURCE_TYPE=api                  # api | webapp | database | ai-agent | mcp-server
TARGET_HOST=my-api:8080            # internal hostname:port of your resource
ORIGINAL_HOST_URL=https://api.yourcompany.com  # external URL your clients use

# Security posture (fail-closed by default)
SECURITY_POSTURE=deny-all

Start the Bouncer

docker compose -f docker-compose.bouncer.yml --env-file .env.bouncer up -d

# Verify the Bouncer is healthy
curl -s http://localhost:8080/health | jq .status

Expected: "ready"

Confirm registration in the Control Plane

  1. Open the console โ†’ Settings โ†’ PEPs
  2. Your Bouncer (My First Bouncer) should appear with status Active
  3. Go to Settings โ†’ Resources โ€” My API should auto-appear

Troubleshooting: Bouncer not appearing after 30 seconds?

  • docker compose logs bouncer โ€” look for PAP_API_URL connection errors
  • Verify PAP_API_URL is reachable from the Bouncer container: docker exec bouncer curl -s $PAP_API_URL/api/v1/health
  • Confirm API_KEY matches the Sandbox key in Settings โ†’ Environments Full reference: Bouncer Deployment, Troubleshooting

Stage 2 done โœ“ โ€” A Bouncer is running and your resource is registered in the Control Plane.


๐Ÿ“Œ Stage 3 โ€” Author your first control (~20 min)

In Control Core, controls are the authorization rules that decide whether a request is allowed or denied. Controls are implemented as Rego policies โ€” but you don't need to write Rego to get started. The Visual Builder generates it for you.

Step 1 โ€” Create a new control (~5 min)

  1. Go to Controls โ†’ Create Control
  2. Choose Visual Builder
  3. On page 1: select the Resource (My API) and the Bouncer (My First Bouncer)
  4. Name: allow-authenticated-users
  5. Environment: Sandbox

Step 2 โ€” Define a simple condition (~5 min)

In the Visual Builder:

  1. Click Add Condition
  2. Subject attribute: user.authenticated
  3. Operator: equals
  4. Value: true
  5. Effect: Allow

This control says: "allow requests where the user is authenticated."

What is user.authenticated? This attribute comes from the request JWT or session. If you connect an identity provider (Okta, Auth0, etc.) as a PIP later, you can use richer attributes like user.department or user.role. For now, user.authenticated is available from the request context without a PIP.

Step 3 โ€” Generate Rego and save (~2 min)

  1. Click Preview Rego โ€” review the generated code
  2. Click Save Draft

Step 4 โ€” Deploy to Sandbox (~3 min)

  1. Click Deploy to Sandbox
  2. Confirm the deployment status shows Active

Troubleshooting: Deploy fails with "Policy Bridge not connected"?

  • Go to Settings โ†’ Controls Repository and confirm the GitHub repo is connected
  • Click Test connection โ€” if it fails, check your GITHUB_TOKEN has repo scope
  • Full reference: Admin Troubleshooting

Option B โ€” Start from a template (~5 min)

  1. Go to Controls โ†’ Templates
  2. Browse the Scenario Starter Catalog (AI Security, Data Governance, API Security, etc.)
  3. Click any template โ†’ Use this template
  4. Customise the pre-filled conditions for your resource
  5. Deploy to Sandbox

Verify the control is enforcing

Send a test request through the Bouncer:

# Without authentication โ€” should be DENIED
curl -i http://localhost:8080/any-endpoint

# With a valid bearer token โ€” should be ALLOWED
curl -i http://localhost:8080/any-endpoint \
  -H "Authorization: Bearer <your-jwt>"

๐Ÿ‘๏ธ Stage 4 โ€” Confirm the audit decision (~5 min)

  1. Go to Controls โ†’ Audit Logs (or Dashboard)
  2. You should see recent ACCESS_GRANTED and ACCESS_DENIED events for your resource
  3. Click any event to inspect the full decision: subject, resource, action, outcome, and matched control

Troubleshooting: No audit events visible?

  • Confirm traffic is going through the Bouncer (port 8080), not directly to your resource
  • Check docker compose logs bouncer | grep -i "decision"
  • Confirm the Bouncer's ENVIRONMENT=sandbox matches the environment shown in the console

Stage 4 done โœ“ โ€” You have a real enforcement decision in audit logs.


๐Ÿ“Œ You're done ๐ŸŽ‰

Your Control Core stack is live:

ComponentStatus
Control PlaneRunning on your infrastructure
BouncerProtecting My API in Sandbox
First controlActive and enforcing
Audit decisionsVisible in the console

๐Ÿ“Œ Next steps


๐Ÿ› ๏ธ Common first-run issues

SymptomLikely causeFix
control-plane-api container exits immediatelyMissing required env vardocker compose logs control-plane-api โ€” look for KeyError or missing config
Console opens but login failsWrong admin passwordCheck CC_BUILTIN_ADMIN_PASS in .env; restart: docker compose restart control-plane-api
Bouncer shows "Disconnected" in consoleWrong PAP_API_URL or API_KEYVerify URL is reachable from Bouncer container; confirm API key matches Sandbox key
Control deploy fails ("Policy Bridge not connected")GitHub repo not connectedSettings โ†’ Controls Repository โ†’ Test connection โ†’ fix token scope
No audit events after sending requestsTraffic bypassing BouncerEnsure requests go to port 8080 (Bouncer), not directly to the resource
curl returns 403 for all requestsSECURITY_POSTURE=deny-all with no active controlDeploy and activate a control in Sandbox first