Ctrl K
ComunidadGuías…

docker-compose.cloud.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# ANT — self-hosted cloud override (multi-user, Google sign-in, NO billing).
#
#   docker compose -f docker-compose.yml -f docker-compose.cloud.yml up -d
#
# Requires a .env (or exported shell vars) with at least:
#   ANT_JWT_PUBLIC_KEY + ANT_JWT_PRIVATE_KEY (see below),
#   GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
# See docs/guides/self-host-cloud.md for the full checklist.
#
# YAML anchors are file-local, so this file cannot merge into the base's
# `x-ant-env-common` anchor. Instead each ant service sets its own
# `environment:` keys — compose merges per-service environment maps key-wise,
# so ANT_REDIS_URL / ANT_WORKSPACE_BASE_PATH etc. from the base still apply.
#
# ANT_REQUIRE_BILLING is deliberately NOT set here — it is reserved for the
# managed deployment (fails boot when the @ant/cloud billing overlay is
# absent). Self-hosted cloud runs unmetered.
#
# Secrets are scoped to the services that CONSUME them, not applied uniformly.
# ant-preview spawns user-authored install and dev commands, and those children
# share its UID and process namespace — so anything in that service's
# environment is reachable from user code via /proc. Sign-in secrets have no
# consumer there, so they are not granted there (report C-001).
#
# Sessions are ES256 only. Generate a P-256 pair once and put the private half
# on ant-api only:
#
#   openssl ecparam -genkey -name prime256v1 -noout \
#     | openssl pkcs8 -topk8 -nocrypt -out jwt-private.pem
#   openssl ec -in jwt-private.pem -pubout -out jwt-public.pem
#   ANT_JWT_PRIVATE_KEY="$(cat jwt-private.pem)"
#   ANT_JWT_PUBLIC_KEY="$(cat jwt-public.pem)"
#
# Child UID isolation (ANT_CHILD_UID/GID below) is the complementary control.

# Every ant service: mode + the origin CORS and cookie derivation read.
x-ant-env-cloud-base: &ant-env-cloud-base
  ANT_SERVER_MODE: cloud
  FRONTEND_URL: ${FRONTEND_URL:-http://localhost:4200}

# Session VERIFICATION (ant-realtime, ant-preview). The ES256 public key
# carries no minting authority — safe even where user-authored code can read
# the env via /proc (C-001, M-NEW-013).
x-ant-env-cloud-verify: &ant-env-cloud-verify
  ANT_JWT_PUBLIC_KEY: ${ANT_JWT_PUBLIC_KEY:-}

# Session SIGNING. Consumed ONLY by ant-api, the only process that mounts the
# auth router and therefore the only one that mints a session.
x-ant-env-cloud-sign: &ant-env-cloud-sign
  ANT_JWT_PRIVATE_KEY: ${ANT_JWT_PRIVATE_KEY:-}

# Sign-in and administration. Consumed ONLY by ant-api, which is the only
# process that mounts the auth and admin routers.
x-ant-env-cloud-identity: &ant-env-cloud-identity
  GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:?set GOOGLE_CLIENT_ID in .env (Google Cloud Console OAuth client)}
  GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:?set GOOGLE_CLIENT_SECRET in .env (Google Cloud Console OAuth client)}
  GOOGLE_REDIRECT_URI: ${GOOGLE_REDIRECT_URI:-}   # empty = derived as ${FRONTEND_URL}/api/auth/google/callback
  ANT_SUPER_ADMIN_EMAILS: ${ANT_SUPER_ADMIN_EMAILS:-}

services:
  ant-api:
    environment:
      <<: [*ant-env-cloud-base, *ant-env-cloud-verify, *ant-env-cloud-sign, *ant-env-cloud-identity]

  ant-realtime:
    environment:
      <<: [*ant-env-cloud-base, *ant-env-cloud-verify]

  # No HTTP surface → verifies nothing, signs nothing.
  #
  # Cloud mode REFUSES user-authored spawns (run_command, stdio MCP) unless
  # children can be dropped to a different UID *and GID* (childIdentity gate).
  # The image ships the `ant-child` account (uid/gid 10001, no login); changing
  # UID/GID needs CAP_SETUID/CAP_SETGID, which a non-root service does not have —
  # so the two user-code services run as container root and every user-authored
  # child is dropped to ant-child with its supplementary groups cleared.
  #
  # ANT_CHILD_GID MUST be non-empty: an empty GID emits no setpriv --regid, and
  # the dropped child keeps egid 0 + root's groups (H-014). It defaults to the
  # ant-child gid; override both only to match a different image account.
  #
  # The credentialed dependency FETCH gets a THIRD identity (ant-acquire, 10002):
  # it carries a user's registry PAT in its environment, and /proc/<pid>/environ
  # is readable by any process sharing its UID — so it must not share the one
  # every other user-code child runs under (M-NEW-001). Same group as ant-child
  # so the installed tree stays writable by the credential-free lifecycle pass.
  ant-job:
    user: "0:0"
    # bwrap builds each user-authored child's mount namespace from an
    # unprivileged user namespace. Docker's default seccomp and AppArmor
    # profiles refuse CLONE_NEWUSER without CAP_SYS_ADMIN, so lift them for the
    # two services that run user code (cheaper than granting SYS_ADMIN).
    security_opt:
      - seccomp=unconfined
      - apparmor=unconfined
    environment:
      <<: *ant-env-cloud-base
      ANT_CHILD_UID: ${ANT_CHILD_UID:-10001}
      ANT_CHILD_GID: ${ANT_CHILD_GID:-10001}
      # Credentialed dependency-FETCH runs under its OWN uid so a same-UID peer
      # cannot read the user's PAT from /proc/<pid>/environ (M-NEW-001).
      ANT_CHILD_ACQUIRE_UID: ${ANT_CHILD_ACQUIRE_UID:-10002}
      ANT_CHILD_ACQUIRE_GID: ${ANT_CHILD_ACQUIRE_GID:-10001}

  # Verifies proxy ownership; never serves sign-in. Runs user-authored code, so
  # it receives the public key ONLY.
  ant-preview:
    user: "0:0"
    # bwrap builds each user-authored child's mount namespace from an
    # unprivileged user namespace. Docker's default seccomp and AppArmor
    # profiles refuse CLONE_NEWUSER without CAP_SYS_ADMIN, so lift them for the
    # two services that run user code (cheaper than granting SYS_ADMIN).
    security_opt:
      - seccomp=unconfined
      - apparmor=unconfined
    environment:
      <<: [*ant-env-cloud-base, *ant-env-cloud-verify]
      ANT_CHILD_UID: ${ANT_CHILD_UID:-10001}
      ANT_CHILD_GID: ${ANT_CHILD_GID:-10001}
      # Credentialed dependency-FETCH runs under its OWN uid so a same-UID peer
      # cannot read the user's PAT from /proc/<pid>/environ (M-NEW-001).
      ANT_CHILD_ACQUIRE_UID: ${ANT_CHILD_ACQUIRE_UID:-10002}
      ANT_CHILD_ACQUIRE_GID: ${ANT_CHILD_ACQUIRE_GID:-10001}