๐ 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:
- A running Control Plane on your infrastructure โ
- A Bouncer intercepting traffic to a resource you own โ
- Your first control authored, deployed to sandbox, and enforcing โ
- A visible audit decision confirming enforcement โ
๐ Before you start
| Requirement | Minimum |
|---|---|
| Linux VM (or local Docker) | 2 vCPU, 4 GB RAM |
| Docker Engine | 20.10+ |
| Docker Compose | 2.0+ |
| Ports available | 3000, 8080, 8082, 7000 |
| GitHub repo (for controls) | Any private repo + Personal Access Token |
| Deployment package | Download 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.envfile using the_PORToverride 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 -dfails withport already allocated, the port is in use. AddCONTROL_PLANE_UI_PORT=3001(or similar) to.envto 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
startingafter 2 min:
docker compose logs control-plane-apiโ look forDATABASE_URLorREDIS_URLerrorsdocker compose logs dbโ check PostgreSQL started correctly- Verify env values:
docker compose config | grep DATABASE_URLFull reference: Troubleshooting โ Deployment issues
Step 3 โ First login (~2 min)
- Open
http://localhost:3000(or yourCONTROL_PLANE_PUBLIC_URL) - Log in with username
adminand the password you set inCC_BUILTIN_ADMIN_PASS - Go to Profile โ Change Password โ do this now
Step 4 โ Create API keys (~3 min)
- Go to Settings โ Environments
- Create a Sandbox API key โ copy it, you need it in Stage 2
- 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. Runcurl http://localhost:8082/api/v1/healthโ if it returns an error, checkdocker 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
- Open the console โ Settings โ PEPs
- Your Bouncer (
My First Bouncer) should appear with status Active - Go to Settings โ Resources โ
My APIshould auto-appear
Troubleshooting: Bouncer not appearing after 30 seconds?
docker compose logs bouncerโ look forPAP_API_URLconnection errors- Verify
PAP_API_URLis reachable from the Bouncer container:docker exec bouncer curl -s $PAP_API_URL/api/v1/health- Confirm
API_KEYmatches 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.
Option A โ Visual Builder (recommended for first control)
Step 1 โ Create a new control (~5 min)
- Go to Controls โ Create Control
- Choose Visual Builder
- On page 1: select the Resource (
My API) and the Bouncer (My First Bouncer) - Name:
allow-authenticated-users - Environment: Sandbox
Step 2 โ Define a simple condition (~5 min)
In the Visual Builder:
- Click Add Condition
- Subject attribute:
user.authenticated - Operator:
equals - Value:
true - 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 likeuser.departmentoruser.role. For now,user.authenticatedis available from the request context without a PIP.
Step 3 โ Generate Rego and save (~2 min)
- Click Preview Rego โ review the generated code
- Click Save Draft
Step 4 โ Deploy to Sandbox (~3 min)
- Click Deploy to Sandbox
- 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_TOKENhasreposcope- Full reference: Admin Troubleshooting
Option B โ Start from a template (~5 min)
- Go to Controls โ Templates
- Browse the Scenario Starter Catalog (AI Security, Data Governance, API Security, etc.)
- Click any template โ Use this template
- Customise the pre-filled conditions for your resource
- 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)
- Go to Controls โ Audit Logs (or Dashboard)
- You should see recent
ACCESS_GRANTEDandACCESS_DENIEDevents for your resource - 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=sandboxmatches 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:
| Component | Status |
|---|---|
| Control Plane | Running on your infrastructure |
| Bouncer | Protecting My API in Sandbox |
| First control | Active and enforcing |
| Audit decisions | Visible in the console |
๐ Next steps
Author Controls
Learn the full control authoring lifecycle: Visual Builder, Rego editor, templates, and SCCA.
View guideDataConnect a Data Source (PIP)
Connect Okta, Workday, or any identity/HR system to enrich controls with real user and resource context.
View guideOperationsPromote to Production
Add a Production Bouncer and promote your sandbox control to enforce on live traffic.
View guideSupportTroubleshooting
Quick diagnostic commands, common error patterns, and fix guides.
View guide๐ ๏ธ Common first-run issues
| Symptom | Likely cause | Fix |
|---|---|---|
control-plane-api container exits immediately | Missing required env var | docker compose logs control-plane-api โ look for KeyError or missing config |
| Console opens but login fails | Wrong admin password | Check CC_BUILTIN_ADMIN_PASS in .env; restart: docker compose restart control-plane-api |
| Bouncer shows "Disconnected" in console | Wrong PAP_API_URL or API_KEY | Verify URL is reachable from Bouncer container; confirm API key matches Sandbox key |
| Control deploy fails ("Policy Bridge not connected") | GitHub repo not connected | Settings โ Controls Repository โ Test connection โ fix token scope |
| No audit events after sending requests | Traffic bypassing Bouncer | Ensure requests go to port 8080 (Bouncer), not directly to the resource |
curl returns 403 for all requests | SECURITY_POSTURE=deny-all with no active control | Deploy and activate a control in Sandbox first |