CydraLabs

Documentation

Deployment

CydraLabs runs as a hosted service or in your own cloud account. This page covers the components, a local evaluation with Docker Compose, the AWS reference deployment and the Kubernetes Helm chart, and the settings production needs.

Deployment options

Deployment options and their availability
OptionDescriptionStatus
CydraLabs-managed SaaSHosted and operated by CydraLabs.Pilot programme
Customer cloud or private VPCDeployed into your own cloud account with the CydraLabs reference deployment.Pilot programme
On-premises or sovereign deploymentPlanned for environments that cannot use cloud services.Roadmap
Local evaluation (Docker Compose)The whole platform on one machine with fictional data, for evaluation and development. Not for production.Evaluation

Deployment into your own cloud account is delivered through the pilot programme, with CydraLabs engineers. The deployment package (Terraform, Helm chart and container images) is provided to pilot customers; contact us to join.

Components

Runtime components
ComponentRoleVersion
WebPublic site and portal (Next.js); proxies /api to the API so cookies stay on the same siteIncluded
APIREST API, the gateway enforcement point and sign-in (FastAPI, Python 3.12)Included
WorkerDeferred work: risk recalculation, graph projection, webhooks, periodic sweeps (Dramatiq). Exactly one worker runs the schedulerIncluded
Policy engineOpen Policy Agent with the CydraLabs decision policyOPA 1.10.1
PostgreSQLSystem of record, row-level tenant isolation, graph tables, evidence chain16
RedisWork queue and rate-limit counters (no persistent state)7
Object storageReports and evidence exports (any S3-compatible store)S3 API
Identity providerOpenID Connect sign-in for people. Self-service sign-up and mandatory MFA use Keycloak with the CydraLabs extensionKeycloak 26.4 or any OIDC provider

Analytical services never sit on the action path: a decision needs the API, the database, the policy engine and (for rate limits) Redis. See the architecture.

Docker Compose (evaluation)

For evaluation and development, not production: it runs in development mode with development credentials, a development sign-in that needs no password, seeded fictional organisations and no TLS.

Start everything (Docker with Compose v2)
docker compose up --build
# optional OpenTelemetry collector:
docker compose --profile observability up --build
# reset all data:
docker compose down -v
Local URLs
ServiceURL
Portalhttp://localhost:3000
API and Swagger UIhttp://localhost:8000/api/docs
Keycloak (realm cydralabs)http://localhost:8080
Mailpit (captured email)http://localhost:8025

The stack also runs PostgreSQL, Redis, OPA, SeaweedFS (S3-compatible storage), a one-off migration job and the worker. Sign in by choosing one of the seeded users of Northwind Financial Group or Contoso Health. On Windows, keep the checkout outside folders synchronised by OneDrive.

AWS reference deployment

Terraform for a production-shaped environment in your AWS account, in any region (examples use eu-west-1):

AWS resources
AreaWhat is created
NetworkVPC across 2 or 3 availability zones with public, private and isolated data subnets, NAT gateways, an S3 gateway endpoint and flow logs
ComputeAmazon EKS 1.33 with a managed Graviton node group (m7g.large, 3 to 9 nodes), Kubernetes secrets encrypted with KMS, private API endpoint by default
DatabaseAmazon RDS for PostgreSQL 16, Multi-AZ, encrypted with KMS, TLS required, 14-day backups, deletion protection
CacheAmazon ElastiCache for Redis 7, Multi-AZ with automatic failover, encryption at rest and in transit, AUTH token
StorageS3 bucket for exports: versioning, Object Lock (governance mode, 365 days by default), SSE-KMS, a bucket policy that refuses requests without TLS
SecretsAWS Secrets Manager for database and Redis URLs, signing key seed, pepper and the OIDC client secret
ImagesAmazon ECR repositories with immutable tags and scan on push
EdgeApplication Load Balancer (TLS 1.3/1.2 policy), ACM certificate, AWS WAF with managed rule groups and a per-IP rate limit, Route 53 record
Deploy accessOptional GitHub Actions OIDC role, so deployments need no stored AWS keys

Deploying

  1. Prerequisites: Terraform 1.9 or later, AWS CLI v2, kubectl, Helm 3, Docker with buildx, and an OIDC identity provider (Entra ID, Okta, Cognito or Keycloak) with the redirect URI https://<your host>/api/v1/auth/callback.
  2. Copy the example variables file, set the environment, region, public URL, DNS zone and OIDC settings, then terraform init, plan and apply (about 25 to 35 minutes).
  3. Store the OIDC client secret in the Secrets Manager entry Terraform created.
  4. Run the deploy script. It builds arm64 images (with SBOM and provenance), installs the AWS Load Balancer Controller, creates the database roles, writes the Kubernetes secrets, installs the Helm chart with an atomic upgrade and runs smoke tests.

Kubernetes Helm chart

Chart cydralabs 0.1.0 (Kubernetes 1.27 or later). Databases, Redis and object storage are always external; the chart never contains secret values.

Install (create the two secrets beforehand)
helm upgrade --install cydra ./cydralabs -n cydralabs --create-namespace \
  -f ./cydralabs/values-production.yaml
What the chart deploys
WorkloadDefaults
api2 replicas, autoscaling 2–8 (production values 3–12), disruption budget, probes on /healthz and /readyz
web2 replicas, autoscaling 2–6 (production 3–10), probe on /healthz
worker1 replica (production 2), plus a single worker-scheduler
opa2 replicas (production 3), reachable from the API and worker and nothing else
Migration jobPre-install and pre-upgrade hook running database migrations with the owner credentials
Ingressnginx by default; ALB in the production values; /api routed straight to the API
  • Secrets: cydralabs-app (DATABASE_URL, REDIS_URL, SIGNING_KEY_SEED, SECRET_PEPPER, OIDC_CLIENT_SECRET, optional SIGNING_PREVIOUS_KEYS and S3 keys) and cydralabs-migrate (DATABASE_OWNER_URL). With IAM roles for service accounts, omit the S3 keys.
  • Hardening: non-root (UID 10001), immutable root filesystem (readOnlyRootFilesystem), all capabilities dropped, no privilege escalation, RuntimeDefault seccomp, no service-account token mounted.
  • Network policies: default deny, DNS allowed, per-component ingress, and egress limited to PostgreSQL, Redis, object storage and the identity provider.
  • Images: pin by digest in production; a digest takes precedence over the tag.

Production settings

All settings are environment variables, validated at start-up. With ENVIRONMENT=production, the API, worker and migration job refuse to start when any of these is true:

  • Development sign-in is enabled (AUTH_DEV_LOGIN_ENABLED).
  • SIGNING_KEY_SEED or SECRET_PEPPER still has its development value.
  • SESSION_COOKIE_SECURE is not true.
  • CORS_ALLOWED_ORIGINS contains *.
  • POLICY_FAIL_OPEN_READONLY is set without POLICY_FAIL_OPEN_ACKNOWLEDGED=true.
  • OIDC_ISSUER, OIDC_CLIENT_ID or OIDC_CLIENT_SECRET is missing.
  • EMAIL_BACKEND=smtp without SMTP_HOST, SMTP_USERNAME and SMTP_PASSWORD, or with SMTP_STARTTLS off; or the memory email backend, which is meant for tests.
  • Self-service sign-up (AUTH_SIGNUP_ENABLED) without KEYCLOAK_SIGNUP_CLIENT_SECRET or without SMTP email.
  • AUTH_EVENTS_SECRET is set but shorter than 32 characters.
Recommended production settings
SettingRecommendation
DATABASE_URLThe runtime role (cydra_app), never the schema owner; TLS required
REDIS_URLTLS (rediss://) with an AUTH token
POLICY_ENGINE / OPA_URLopa and the OPA service URL (the default is the embedded evaluator)
OBJECT_STORE / S3_*s3, the bucket and region. If the bucket requires KMS, set S3_SERVER_SIDE_ENCRYPTION=aws:kms and S3_KMS_KEY_ID
PUBLIC_WEB_URL / OIDC_REDIRECT_URIYour public host and its /api/v1/auth/callback
WORKER_ENABLEDtrue, with the worker deployed
TRUST_FORWARDED_HEADERStrue behind a load balancer, with FORWARDED_ALLOW_IPS limited to it
OTEL_EXPORTER_OTLP_ENDPOINTYour OpenTelemetry collector, for traces
RETENTION_*_DAYSRetention periods to match your policy

Database and migrations

  • Create two roles before running any migration: cydra_owner, which owns the schema, and cydra_app (LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS), which the application uses. The deploy script and the Compose stack do this for you.
  • Migrations run as the owner (alembic upgrade head; the Helm hook or the Compose migrate job). The application must never connect as the owner: row-level security relies on the runtime role.
  • Do not load demonstration data in production. Your organisation is created when its administrator signs in and completes onboarding.

Operating the platform

Health

GET /healthz reports that the process is up; GET /readyz also checks the database. The web app has its own /healthz.

Backups and restore

  • PostgreSQL holds all authoritative state, including the evidence chain: use point-in-time recovery and test restores regularly.
  • After a restore, verify the evidence chain (GET /api/v1/evidence/verify, or the verify-evidence command) and rebuild the graph (POST /api/v1/graph/rebuild).
  • Redis needs no backup.

Upgrades

Migrations run before the new version starts. Schema changes are made in expand, migrate and contract steps so the previous version keeps working during a rolling upgrade. Roll back a release with helm rollback; check the release notes before rolling back across a migration.

Observability

Logs are structured JSON on standard output, with secrets and personal data redacted. Traces are exported over OTLP/HTTP (API requests and database calls; health checks excluded). Metrics and logs are not exported over OTLP in this release.

Applies to the CydraLabs proof-of-concept platform. Last updated 4 October 2026. Questions or corrections: contact us.