forge

Deploy a New Tenant

This checklist tells you exactly what to update to onboard a new Forge tenant.


1. Create Tenant Config Files

Copy these templates and place them at the correct paths.

Templates to Copy

Destination Paths

examples/deployments/forge-tenant/terragrunt/_global_settings/tenants/<tenant_name>.hcl

examples/deployments/forge-tenant/terragrunt/environments/<aws_account>/regions/<aws_region>/vpcs/<vpc_alias>/tenants/<tenant_name>/terragrunt.hcl

examples/deployments/forge-tenant/terragrunt/environments/<aws_account>/regions/<aws_region>/vpcs/<vpc_alias>/tenants/<tenant_name>/runner_settings.hcl

examples/deployments/forge-tenant/terragrunt/environments/<aws_account>/regions/<aws_region>/vpcs/<vpc_alias>/tenants/<tenant_name>/config.yaml

Example for tenant=sbg, account=sec-plat, region=eu-west-1, vpc_alias=shared

cp examples/templates/tenant/_global_settings/tenant.hcl \
   examples/deployments/forge-tenant/terragrunt/_global_settings/tenants/sbg.hcl

mkdir -p examples/deployments/forge-tenant/terragrunt/environments/sec-plat/regions/eu-west-1/vpcs/shared/tenants/sbg

cp examples/templates/tenant/tenant/terragrunt.hcl \
   examples/deployments/forge-tenant/terragrunt/environments/sec-plat/regions/eu-west-1/vpcs/shared/tenants/sbg/terragrunt.hcl

cp examples/templates/tenant/tenant/runner_settings.hcl \
   examples/deployments/forge-tenant/terragrunt/environments/sec-plat/regions/eu-west-1/vpcs/shared/tenants/sbg/runner_settings.hcl

cp examples/templates/tenant/tenant/config.yaml \
   examples/deployments/forge-tenant/terragrunt/environments/sec-plat/regions/eu-west-1/vpcs/shared/tenants/sbg/config.yaml

2. Edit config.yaml — Tenant Configuration Fields

Controls GitHub integration, IAM roles, runner specs (EC2 & ARC).


Top-level Structure & Key Fields

gh_config:
  ghes_url: <GITHUB_URL>              # Empty string for github.com, full GHES URL otherwise
  ghes_org: <GITHUB_ORG>              # Exact GitHub organization name

tenant:
  iam_roles_to_assume:                # List of full AWS IAM role ARNs for runner assume roles
    - arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>
  ecr_registries:                    # Allowed ECR repo URLs (full), e.g. 123456789012.dkr.ecr.us-east-1.amazonaws.com
    - <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com

ec2_runner_specs:
  <runner_type>:                     # e.g. small, medium, gpu
    ami_name: <AMI_NAME_PATTERN>    # AMI name pattern, supports wildcard *, e.g. forge-gh-runner-v*
    ami_owner: <ACCOUNT_ID>         # AWS account ID owning AMI
    ami_kms_key_arn: ''             # Set to '' if AMI is unencrypted, else KMS ARN string
    max_instances: <MAX_PARALLEL>   # Max EC2 runners allowed in parallel
    instance_types:                 # List of allowed instance types (prefer spot-compatible)
      - <AWS_INSTANCE_TYPE>         # e.g. t3.large, m5.large
    pool_config:                    # Warm pool config for pre-warming runners; empty list [] disables
      - size: <POOL_SIZE>           # Number of instances to keep warm
        schedule_expression: <AWS_CRON_EXPR>  # AWS cron expression (6 fields, use AWS docs)
        schedule_expression_timezone: <TIMEZONE>  # Optional timezone, e.g. UTC, America/New_York

arc_runner_specs:
  <runner_type>:                    # e.g. dependabot, k8s
    runner_size:
      max_runners: <MAX>            # Max pods/runners (Max Pod allowed in parallel)
      min_runners: <MIN>            # Min pods/runners (warm pool)
    scale_set_name: <NAME>          # Used for ARC annotations and scale set identification
    scale_set_type: <dind|k8s>      # Must be exactly 'dind' or 'k8s', no other values allowed
    container_actions_runner: <ECR_IMAGE_URL>   # Full ECR container image URL for the runner container
    container_requests_cpu: <CPU>   # Kubernetes CPU requests, e.g. 500m (mandatory unit)
    container_requests_memory: <MEM> # Kubernetes memory requests, e.g. 1Gi (mandatory unit)
    container_limits_cpu: <CPU>     # Kubernetes CPU limits
    container_limits_memory: <MEM>  # Kubernetes memory limits


Field Guidance & Gotchas


Common Pitfalls — Avoid These


3. Minimal Working config.yaml Example

gh_config:
  ghes_url: ''
  ghes_org: cisco-sbg

tenant:
  iam_roles_to_assume:
    - arn:aws:iam::123456789012:role/role_for_forge_runners
  ecr_registries:
    - 123456789012.dkr.ecr.us-east-1.amazonaws.com

ec2_runner_specs:
  small:
    ami_name: forge-gh-runner-v*
    ami_owner: '123456789012'
    ami_kms_key_arn: ''
    max_instances: 10
    instance_types:
      - t3.small
      - t3.medium
    pool_config:
      - size: 2
        schedule_expression: "cron(*/10 8 * * ? *)"
        schedule_expression_timezone: "America/Los_Angeles"

arc_runner_specs:
  dependabot:
    runner_size:
      max_runners: 100
      min_runners: 1
    scale_set_name: dependabot
    scale_set_type: dind
    container_actions_runner: 123456789012.dkr.ecr.us-east-1.amazonaws.com/actions-runner:latest
    container_requests_cpu: 500m
    container_requests_memory: 1Gi
    container_limits_cpu: '1'
    container_limits_memory: 2Gi

4. Deploy Secrets

  1. Navigate to the tenant directory matching your AWS account, region, VPC, and tenant:
cd examples/deployments/forge-tenant/terragrunt/environments/<aws_account_alias>/regions/<aws_region>/vpcs/<vpc_alias>/tenants/<tenant_name>
  1. Deploy only the secrets to AWS Secrets Manager:
terragrunt apply --target aws_secretsmanager_secret_version.cicd_secrets

Pro tip: Use --target carefully — only apply secrets here to avoid accidental resource changes in other modules.


5. Create GitHub App

  1. Pull the registration UI container (amd64):
docker pull ghcr.io/cisco-open/forge-forge-github-app-register:main
  1. Run it locally, exposing port 5000:
docker run --rm -p 5000:5000 ghcr.io/cisco-open/forge-forge-github-app-register:main
  1. Open the UI: Go to http://localhost:5000/ in your browser.

  2. In the UI:

${local.tenant_name}-${local.region_alias}-${local.vpc_alias}-${include.env.locals.runner_group_name_suffix}

Example:

sec-plat-euw1-shared-sbg-cicd-forge
  1. After creation:

Tips:


6. Set GitHub App Secrets

Run the update-github-app-secrets.sh script to inject critical GitHub App values into your secrets:

./scripts/update-github-app-secrets.sh /full/path/to/tenant_dir client_id <GITHUB_APP_CLIENT_ID>
./scripts/update-github-app-secrets.sh /full/path/to/tenant_dir name <GITHUB_APP_NAME>
./scripts/update-github-app-secrets.sh /full/path/to/tenant_dir id <GITHUB_APP_ID>
./scripts/update-github-app-secrets.sh /full/path/to/tenant_dir key /path/to/private-key.pem
./scripts/update-github-app-secrets.sh /full/path/to/tenant_dir installation_id <GITHUB_APP_INSTALLATION_ID>

Notes:


7. Deploy

  1. Navigate to your tenant directory:
cd examples/deployments/forge-tenant/terragrunt/environments/<aws_account_alias>/regions/<aws_region>/vpcs/<vpc_alias>/tenants/<tenant_name>
  1. Deploy everything in one go:
terragrunt apply
  1. Verify success:

For more advanced scenarios or troubleshooting, see the full documentation.