Skip to content

Control Plane

Overview

The Control Plane is the multi-tenant management layer for JustIAM. It provides a centralized UI and API for operators to manage tenants, licensing, infrastructure, worker configurations, and agent pools.

The control plane is only used in multi-tenant deployments. Single-tenant deployments are managed directly through the tenant admin UI and docker-compose configuration.


Architecture

                    ┌─────────────────────┐
                    │   Control Plane UI   │
                    │  (React / TypeScript) │
                    └──────────┬──────────┘
                    ┌──────────▼──────────┐
                    │  Control Plane API   │
                    │      (Go)           │
                    └──────────┬──────────┘
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
  ┌─────▼─────┐         ┌─────▼─────┐         ┌─────▼─────┐
  │ Tenant A  │         │ Tenant B  │         │ Tenant C  │
  │ (backend) │         │ (backend) │         │ (backend) │
  └───────────┘         └───────────┘         └───────────┘

Dashboard

The control plane dashboard shows a high-level overview of the deployment:

  • Total tenants, active users, and license status
  • Recent activity and alerts

Tenant management

Creating a tenant

Navigate to Tenants → New Tenant or use the API:

POST /tenants
Content-Type: application/json

{
  "slug": "acme",
  "display_name": "Acme Corp"
}

This creates:

  1. A new PostgreSQL database for the tenant
  2. A Kubernetes Secret with the tenant's connection string and JWT secret
  3. An entry in the tenant registry ConfigMap

Tenant detail

Each tenant page provides:

Section Operations
Overview Stats (users, groups, apps), status, backend version
Admin password View or reset the initial admin password
Database Connection info, migrations
Backups List backups, trigger a new backup, download
Secrets Rotate JWT secret, login-worker token, proxy token
Worker config Set worker mode (inline/agent), login-worker mode, concurrency limits
Bootstrap token Manage the Terraform bootstrap token
CP token Rotate the control-plane-to-tenant API token

Deleting a tenant

DELETE /tenants/:slug

Danger

This drops the tenant's database and removes all associated Kubernetes resources. This action is irreversible.


License management

The control plane manages the license for the entire deployment.

Activate a license

POST /license
Content-Type: application/json

{
  "key": "<license-key>"
}

When activated, the license is fanned out to all tenants automatically.

View license status

GET /license

Returns the current license status, limits, expiry, and per-tenant allocation.

Clear the license

DELETE /license

Reverts all tenants to free-tier mode.

Per-tenant allocation

Allocate a specific user cap to a tenant:

PUT /tenants/:slug/license-allocation
Content-Type: application/json

{
  "max_users": 500
}

Renewal

POST /license/refresh

If the license has a renewal_url, this fetches a replacement license immediately.

See Licensing for the full license lifecycle.


Worker configuration

The control plane manages how each tenant executes tasks and login scripts.

Task worker mode

PUT /tenants/:slug/worker
Content-Type: application/json

{
  "mode": "agent"
}
Mode Description
inline Tasks run in the backend process (default)
agent Tasks dispatched to external gRPC agents

Task concurrency limit

PUT /tenants/:slug/worker-limit
Content-Type: application/json

{
  "max_concurrent": 10
}

Login worker mode

PUT /tenants/:slug/login-worker
Content-Type: application/json

{
  "mode": "shared",
  "url": "http://login-worker-shared.justiam-mt.svc:8090",
  "max_concurrent": 5
}
Mode Description
inline Post-render scripts run in the backend process
shared Scripts run in a shared login-worker deployment
dedicated Scripts run in a per-tenant login-worker pod

Agent pools

Agent pools group external task workers. Tenants are assigned to pools, and tasks are dispatched to agents in the assigned pool.

Create a pool

POST /pools
Content-Type: application/json

{
  "name": "compute-heavy",
  "labels": ["gpu", "compute"]
}

Assign a tenant to a pool

POST /pools/:poolName/tenants
Content-Type: application/json

{
  "slug": "acme"
}

Shared agent pool

The control plane can manage a shared agent pool for tenants that don't need dedicated agents:

  • Initialize: Creates the shared pool with HMAC registration
  • Scale: Adjust the number of agents
  • Rotate key: Rotate the HMAC self-registration key
POST /shared-agent-pool/init
POST /shared-agent-pool/scale
Content-Type: application/json

{
  "replicas": 5
}

Infrastructure

The Infrastructure page shows the status of all deployed components:

  • Backend pods and versions
  • Login worker pods (shared and dedicated)
  • Agent pools and connected agents
  • Database status

Worker version upgrades

POST /workers/upgrade-login-worker
Content-Type: application/json

{
  "version": "1.3.0"
}

Settings

SMTP

Configure the SMTP relay used by all tenants for password reset and notification emails:

PUT /settings/smtp
Content-Type: application/json

{
  "host": "smtp.example.com",
  "port": 587,
  "username": "noreply@example.com",
  "password": "smtp-password",
  "from": "noreply@example.com"
}

Test SMTP:

POST /settings/smtp/test
Content-Type: application/json

{
  "to": "admin@example.com"
}

Alerts

Configure alert rules for operational events:

PUT /settings/alerts
Content-Type: application/json

{
  "license_expiring": true,
  "capacity_warnings": true,
  "daily_reports": true,
  "alert_email": "ops@example.com"
}

Audit log

The control plane maintains its own audit log, separate from tenant audit logs. It tracks:

  • Tenant creation and deletion
  • License changes
  • Worker configuration changes
  • Secret rotations
  • Admin actions

Authentication

The control plane UI authenticates operators via OIDC:

  • GET /auth/login — initiates the login flow
  • GET /auth/callback — handles the OIDC callback
  • POST /auth/logout — ends the session

API tokens

Operators can create API tokens for automation:

POST /me/tokens
Content-Type: application/json

{
  "name": "terraform-automation",
  "expires_in_days": 90
}

Deployment

The control plane is deployed as two separate services:

Component Manifest
CP Backend k8s-mt/cp-backend.yaml
CP Frontend k8s-mt/controlplane/

Both are deployed in the justiam-mt namespace alongside the main backend and frontend.

kubectl apply -f k8s-mt/cp-backend.yaml
kubectl apply -f k8s-mt/controlplane/