Skip to content

Your own AWS account

This page is about the third stack: Metergraph running on ECS Fargate in one AWS account you own, deployed by Terraform. It is not the open source server, and it is not the customer-local bundle. None of the commands on those sections apply here.

One installation belongs to one AWS account. There is no control plane, no replication, no licensing callback, and no Metergraph operator access across the boundary. Traces and provider credentials stay in that account.

The capability delta is the thing to read first

Section titled “The capability delta is the thing to read first”

A BYOC installation runs with METERGRAPH_DEPLOYMENT_PROFILE=byoc-core, and that profile is what gates the product. Gating is by deployment profile, not by plan: capabilities.py:8-41 defines two sets, and the managed set has 19 capabilities where byoc-core has 8.

These eight are present:

telemetry, alerts, api_keys, membership, workspace_settings_read, reports, analysis_runs, optimization.

So ingest (native and OTLP), pricing and enrichment, the spend, performance and trace views, API keys, the six deterministic detectors, alert listing and acknowledgement, membership reads, analysis runs, and report viewing and export all work exactly as they do on the hosted service.

Everything else fails closed. A request to an absent capability returns 404 with code: capability_unavailable and the capability’s name, from a middleware that runs before routing. It is a 404 rather than a 403 on purpose: the surface does not exist in this deployment.

Route prefixCapabilityWhy it is absent
POST /v1/auth/signup, /v1/organization/invitationssignupOperators provision identities in Cognito, so there is no public signup or invitation flow
PATCH /v1/organizationworkspace_settingsSettings are readable, not writable
/v1/upgrade-requestsbillingNothing is billed by Metergraph
/v1/catalog, /v1/adminplatform_adminThe global model and pricing catalog editor is a hosted surface
/v1/campaign, /v1/sme-reviews, /v1/judge-qualificationsevaluationsEvaluation authoring is a hosted surface
/v1/datasetdatasets
/v1/simulation, /v1/tool-replay-cachesimulations
/v1/canariescanaries
/v1/recommendation-deliveries, /v1/github-installations, /v1/email, /internal/deliveries, /internal/githubexternal_deliverySlack, GitHub and email delivery run from Metergraph’s own infrastructure
/v1/provider-batchprovider_probes
/v1/agentagent_apiThe MCP server is not available here
/v1/import-syncimport_syncScheduled import sync is a hosted surface

Three more are gated by shape rather than prefix, in the same file:

  • POST /v1/reports/{id}/approve and POST /v1/recommendations/{id}/approve need external_delivery, so approving a recommendation into a pull request is unavailable.
  • POST /v1/recommendations/{id}/canary needs canaries.
  • /v1/routes/{route}/constraints and /v1/routes/{route}/evaluation need evaluations.

The worker is gated too: under byoc-core it accepts only the ingest_batch and detector_scan job kinds.

An operational kill switch is separate from all of this and answers 503, not 404. A 404 capability_unavailable means the capability is not part of the deployment; a 503 means the deployment is deliberately paused.

ConcernAWS service
ComputeECS Fargate: API, worker, and one-off admin and analysis tasks
IngressInternal ALB, your ACM certificate, a Route 53 private record
DashboardThe React build, served by the API image on the same hostname
DatabaseRDS PostgreSQL 17, Single-AZ, point-in-time recovery
Objects and queueVersioned KMS-encrypted S3, SQS with a native dead-letter queue
AnalysisA Bedrock-only pipeline profile in an isolated one-off Fargate task, through a module-created private Bedrock Runtime endpoint
IdentityA dedicated Cognito user pool with self-registration off
SecretsSecrets Manager, with scoped task roles per service
OperationsCloudWatch logs, metrics and alarms under your CMK

Workloads have no public IP. The deployment runs one API replica and one worker replica after bootstrap, and offers no availability SLA or zone-failure continuity.

Default runtime egress is TCP/443 through a security group you own, so it can be logged and filtered by your existing controls.

DestinationPathNeeded by
The private PostgreSQL endpointVPCAPI, worker, migration, analysis
S3, SQS, Secrets Manager, KMS, CloudWatchVPC endpoints where configuredevery runtime task
Amazon Bedrock RuntimeThe module’s private interface endpointthe analysis task
Your regional Cognito issuer and domainLogged NAT or firewallbrowser login and API token exchange
public.ecr.awsLogged NAT or firewallplatform image pull

No external model provider, email, Slack, GitHub, analytics, licensing or Metergraph control-plane destination is part of byoc-core. Model traffic for an analysis stays on the Bedrock private endpoint.

The module has no defaults for the things that describe your account, so a plan fails until you supply them.

Required inputWhat it is
region, vpc_id, private_subnet_idsAt least two private subnets, for the ALB and RDS subnet groups
private_zone_id, private_hostnameThe private Route 53 zone and the name the ALB answers on
certificate_arn, kms_key_arnYour ACM certificate and your customer-managed key
image, analysis_runner_imageBoth are validated against @sha256: and refused unless pinned by manifest digest
bedrock_model_resource_arnsThe exact foundation-model and inference-profile ARNs the analysis task may invoke. Must be non-empty and must all start with arn:aws...:bedrock:
cognito_user_pool_domain_prefixThe hosted login domain prefix
alarm_sns_topic_arnWhere CloudWatch alarms go
egress_security_group_idYour logged TCP/443 egress security group

The ones worth knowing about among the defaulted inputs:

InputDefaultNote
analysis_pipeline_builder_modelus.anthropic.claude-sonnet-5The model that writes the analysis
analysis_pipeline_max_generation_cost_usd200A worst-case cap on one run’s generation cost. Must be greater than zero
automatic_analysis_enabledtrueScheduling keeps its call-count, complete-day, cooldown, spacing and daily-cap policy
retention_days90Relational trace data and every object version expire on this schedule
backup_retention_days7
log_retention_days30
api_desired_count, worker_desired_count0Deliberately zero, so the first apply creates the infrastructure before anything runs against an unmigrated database
image_architectureARM64Or X86_64
enable_delete_protectiontrueKeys, database and buckets survive an ordinary terraform destroy
break_glass_allow_destroyfalseThe deliberate override for the above

analysis_runner_anthropic_api_key_secret_arn, ..._openai_... and ..._google_... are optional Secrets Manager ARNs. Each is injected into the analysis task under the provider’s own variable name, and is read only by search-enabled workloads. Leave them empty and they are omitted.

There is no public signup here, so the first workspace and its owner are created by an operator against an exact OIDC identity. Cognito is the issuer, and the immutable (identity_issuer, identity_subject) pair is what grants access. Email and display name are presentation data and grant nothing.

  1. The outputs you will need afterwards are private_url, ecs_cluster_arn, migration_admin_task_definition_arn, admin_network_configuration and smoke_test_command.

  2. The admin task definition runs python -m metergraph_app.cli with the database owner role and a list-tenants default command. Every operator command is a container override on that task definition, launched into the subnets and security groups from admin_network_configuration:

    aws ecs run-task \
    --cluster "$CLUSTER_ARN" \
    --task-definition "$ADMIN_TASK_DEFINITION_ARN" \
    --launch-type FARGATE \
    --network-configuration "$ADMIN_NETWORK_CONFIGURATION" \
    --overrides '{"containerOverrides":[{"name":"admin","command":["python","-m","metergraph_app.cli","list-tenants"]}]}'
  3. python -m metergraph_app.cli bootstrap-workspace <slug> \
    --identity-subject <cognito-sub> \
    --email owner@example.com \
    --display-name "Owner Name"

    It refuses if the slug exists, or if that email or identity pair is already registered. --identity-issuer defaults to the deployment’s configured issuer.

  4. python -m metergraph_app.cli grant-member <slug> \
    --identity-subject <cognito-sub> \
    --email member@example.com \
    --role member

    Roles are owner, member and viewer.

  5. The smoke_test_command output gives you the exact invocation. It submits one native and one OTLP GenAI trace with a disposable ingest key, and refuses to run at all unless the target reports deployment_profile=byoc-core.

    python scripts/byoc_smoke.py --base-url https://<private-hostname> \
    --token "$METERGRAPH_APP_TOKEN"

    Confirm both smoke routes appear in the dashboard, then revoke the key.

More operator commands, the RLS check, backups and the tenant purge are on Operations.

Content capture defaults on, and the per-event opt-out strips content before it is stored. Relational trace and call data, and every current and historical object version, expire after retention_days. Operational logs keep log_retention_days. What the SDK sends and what is stored are two different limits: see Content and privacy.