VPC / Private Cloud Deployment

Reference for running Cybros as a single-tenant install inside a private VPC, using managed datastores and a private ingress. This is the "cloud-native but isolated" story: your account, your keys, your network.

Use deploy/helm/cybros/values-vpc.yaml as the starting overlay.


Topology

                        Private DNS  cybros.vpc.internal
                                 │
                    ┌────────────▼────────────┐   internal ALB/NLB (TLS)
                    │      Ingress (private)   │   scheme: internal
                    └───────┬─────────┬────────┘
                            │         │
                       ┌────▼───┐ ┌───▼────┐        Private subnets (no IGW route)
                       │  web   │ │  api   │  ┌──────────────────────────────┐
                       │ pods   │ │ pods   │──┼─▶ RDS / Aurora Postgres      │
                       └────────┘ └───┬────┘  │   (managed, encrypted, HA)   │
                                      │        └──────────────────────────────┘
                                 ┌────▼────┐   ┌──────────────────────────────┐
                                 │ worker  │──▶│ ElastiCache Redis (managed)  │
                                 │ celery-B│   └──────────────────────────────┘
                                 └────┬────┘
                                      │ (controlled egress via NAT + SG allowlist)
             ┌────────────────────────┼───────────────────────────┐
             ▼                        ▼                            ▼
        GitHub App               IdP (SSO/SCIM)                 KMS (CMEK)
     api.github.com            your identity provider        key operations

Networking

  • Private subnets for all Cybros pods and managed datastores. No public IPs.

  • Ingress = internal load balancer (scheme: internal). Expose to users via VPN, private link, or a corporate proxy — never a public listener.

  • Egress is default-deny, opened only for the integrations you enable:

    DestinationWhenNotes
    api.github.com / GHESGitHub App enabledContinuous Security Guard
    Your IdPSSO/SCIM enabledSAML/OIDC + provisioning
    Cloud KMSCMEK enabledenvelope-key operations
    Payment APIPAYMENT_PROVIDER != stubStripe/Razorpay
    AnthropicAI_PROVIDER = anthropicleave stub to avoid

    Enforce with a NetworkPolicy (pod egress) and security-group / NAT rules.


Managed datastores

  • Postgres: RDS/Aurora, encrypted at rest (with your KMS key), Multi-AZ, automated backups + PITR. DATABASE_URL=postgresql+asyncpg://...:5432/cybros.
  • Redis: ElastiCache, in a private subnet group. REDIS_URL=redis://...:6379/0.
  • The chart's bundled subcharts stay disabled (postgresql.enabled=false, redis.enabled=false).

Secrets & keys (no static credentials)

  • secrets.create=false, externalSecret.enabled=true — the chart references a Secret managed by the External Secrets Operator (or Sealed Secrets / Vault CSI) synced from your cloud secrets manager.

  • The pod ServiceAccount is annotated for IRSA / Workload Identity so pods reach Secrets Manager and KMS without long-lived keys:

    serviceAccount:
      annotations:
        eks.amazonaws.com/role-arn: arn:aws:iam::<acct>:role/cybros-app
    
  • CMEK: SECRET_ENCRYPTION_KEY is derived/unwrapped from your KMS key (cmek.provider: aws-kms, cmek.keyId: arn:...). See docs/data-residency.md.


Install

helm dependency build deploy/helm/cybros
helm upgrade --install cybros deploy/helm/cybros \
  -f deploy/helm/cybros/values-vpc.yaml \
  --namespace cybros --create-namespace \
  --set ingress.host=cybros.vpc.internal \
  --set cmek.keyId=arn:aws:kms:us-east-1:<acct>:key/<id>

The pre-install migration Job runs alembic upgrade head against RDS before the app rolls. Verify residency/mode:

curl -s https://cybros.vpc.internal/api/v1/system/deployment
# { "mode":"private", "data_residency":"us", "features": { "cmek": true, ... } }

HA & scaling

  • api/web run 2+ replicas; autoscaling.enabled=true gives the api an HPA.
  • podDisruptionBudget.enabled=true keeps ≥1 api pod during node drains.
  • Keep the worker at 1 replica with -B (embedded beat) to avoid duplicate scheduled jobs; scale scan throughput by splitting beat out and adding beat-less worker replicas.