Skip to main content

AWS PrivateLink

This guide walks you through setting up AWS PrivateLink to allow Infracost to securely connect to your private GitHub Enterprise Server or GitLab instance.

note

Email hello@infracost.io if you would like to test this integration.

Architecture Overview

AWS PrivateLink creates a private, one-way network tunnel from Infracost's AWS account into your VPC, so that Infracost can reach your VCS without any traffic crossing the public internet.

How it works:

  1. Infracost Runner initiates API calls (repo process, PR comments) through a VPC Endpoint in the Infracost AWS account.
  2. The VPC Endpoint connects over the AWS backbone to the VPC Endpoint Service in your account — no traffic traverses the public internet.
  3. The Network Load Balancer forwards traffic to your GitHub Enterprise or GitLab instance.
  4. Your VCS sends webhook events (push, pull request) back to Infracost — either over the public internet (Hybrid mode) or through a second PrivateLink tunnel (Fully Private mode).

See Data Flow Overview below for detailed diagrams of each connectivity option.

Prerequisites

  • Your VCS (GitHub Enterprise or GitLab) is running in an AWS VPC
  • You have the ability to create AWS resources (NLB, VPC Endpoint Service) in your account

Step 1: Gather Your Environment Details

Before starting, collect the following information from your AWS environment:

Information NeededExample
VPC ID where your VCS runsvpc-0abc123def456
Subnet IDs in that VPC (at least one)subnet-111, subnet-222, subnet-333
EC2 Instance ID of your VCSi-0abc123def456
Security Group IDs for the NLBsg-0abc123
Your AWS regionus-east-1
Internal URL used to reach your VCShttps://github.mycompany.internal

Step 2: Note Infracost's Connection Details

Infracost will connect from:

  • AWS Account ID: 237144093413
  • Region: us-east-2

Important: If your VCS is in a region other than us-east-2, you'll be using cross-region PrivateLink. Your VPC Endpoint Service configuration must include us-east-2 in the supported_regions setting.

Step 3: Deploy the VPC Endpoint Service Infrastructure

Using either the resource list in Appendix A or the Terraform configuration in Appendix B, deploy the necessary resources to your account to become a PrivateLink endpoint provider for Infracost.

Step 4: Provide Information to Infracost

After deploying the infrastructure, send Infracost the following:

InformationHow to Find It
Your AWS regione.g., us-east-1
VPC Endpoint Service nameFind in AWS Console or Terraform output: com.amazonaws.vpce.REGION.vpce-svc-XXXX
Internal VCS URLThe URL your teams use to access the VCS
TLS certificate rotation scheduleOnly needed if you use self-signed certificates (not needed for AWS ACM certificates)

Step 5: Confirm Connectivity

Once Infracost confirms the connection is configured on their side, they will verify connectivity to your VCS through the PrivateLink tunnel.


Data Flow Overview

You can choose between two connectivity scenarios based on your security and network requirements:

Option A: Hybrid Connectivity (Public Internet for Webhooks)

This is the simpler option where outbound webhooks use the public internet while incoming API calls to your VCS use PrivateLink.

Data Flow Summary:

1. WEBHOOKS (VCS → Infracost)

  • Triggered by: Push events, Merge/Pull Requests
  • Path: Public Internet (HTTPS)
  • Direction: Your VCS → Infracost webhook endpoint

2. VCS API CALLS (Infracost → VCS)

  • Purpose: process repos, fetch configs, post PR comments
  • Path: AWS PrivateLink (private, no public internet)
  • Direction: Infracost → VPC Endpoint → Your VPC Endpoint Service → VCS

Requirements:

  • Your VCS must have outbound internet access to reach Infracost's webhook endpoint
  • Simpler configuration with no additional DNS setup required

This option keeps all traffic on PrivateLink but requires bi-directional routing configuration.

Data Flow Summary:

1. WEBHOOKS (VCS → Infracost)

  • Triggered by: Push events, Merge/Pull Requests
  • Path: AWS PrivateLink (fully private)
  • Direction: Your VCS → Your VPC Endpoint → Infracost VPC Endpoint Service → Infracost webhook endpoint

2. VCS API CALLS (Infracost → VCS)

  • Purpose: Process repos, fetch configs, post PR comments
  • Path: AWS PrivateLink (fully private)
  • Direction: Infracost → VPC Endpoint → Your VPC Endpoint Service → VCS

Requirements:

  • Bi-directional PrivateLink setup: You must also create a VPC Endpoint in your account that connects to an Infracost-provided VPC Endpoint Service
  • DNS Configuration: The Infracost webhook endpoint configured in your VCS must be set to that of the VPC Endpoint you create, which is known after creating it (as opposed to using the default, public-internet hostname for Infracost webhooks)

When to Choose This Option:

  • Your VCS has no outbound internet access
  • Your security policies require all traffic to remain on private networks
  • You need complete network isolation from the public internet

Appendix A: Required AWS Resources Overview

The Terraform configuration in Appendix B creates the following AWS resources. If you do not use Terraform, please create the equivalent resources:

1. Network Load Balancer

  • Purpose: Acts as the entry point for incoming PrivateLink connections
  • Type: Internal Network Load Balancer
  • Configuration:
    • Deployed across your specified subnets
    • Cross-zone load balancing enabled
    • Security group rules on PrivateLink traffic disabled (allows Infracost connections)

2. Target Group

  • Purpose: Defines where the NLB forwards traffic
  • Configuration:
    • Protocol: TCP
    • Port: 443
    • Target type: EC2 instance
    • Health check: TCP on port 443, every 30 seconds

3. Target Group Attachment

  • Purpose: Registers your VCS EC2 instance with the target group
  • Configuration:
    • Links the target group to your VCS instance on port 443

4. NLB Listener

  • Purpose: Listens for incoming connections and forwards them
  • Configuration:
    • Protocol: TCP
    • Port: 443
    • Action: Forward to the target group

5. VPC Endpoint Service

  • Purpose: Exposes your NLB as a PrivateLink service that Infracost can connect to
  • Configuration:
    • Auto-accepts connections (no manual approval required)
    • Attached to the NLB
    • Supported regions: Your region + us-east-2 (required for cross-region connectivity)
    • Allowed principals: Your account + Infracost's account (237144093413)

Appendix B: Terraform Configuration

  1. Replace github with gitlab if connecting a GitLab instance
  2. Update the locals block with your environment-specific values
  3. Run Terraform to create:
    • A Network Load Balancer pointing to your VCS instance
    • A Target Group with health checks on port 443
    • A VPC Endpoint Service that allows connections from Infracost
locals {
infracost_account_id = "237144093413" # Infracost prod account ID
github_app_vpc_id = "<VPC ID of your VCS instance>"
github_app_subnet_ids = ["<subnet-1>", "<subnet-2>", "<subnet-3>"]
github_app_instance_id = "<EC2 instance ID where your VCS runs>"
github_nlb_security_groups = ["<security-group-id>"]
}

# NETWORK LOAD BALANCER
resource "aws_lb" "github_nlb" {
name = "infracost-github-nlb"
load_balancer_type = "network"
subnets = local.github_app_subnet_ids
internal = true

enable_deletion_protection = true
enable_cross_zone_load_balancing = true
security_groups = local.github_nlb_security_groups
enforce_security_group_inbound_rules_on_private_link_traffic = "off"
}

# TARGET GROUP
resource "aws_lb_target_group" "github_tg" {
name = "infracost-github-tg"
protocol = "TCP"
port = 443
vpc_id = local.github_app_vpc_id
target_type = "instance"

health_check {
port = 443
protocol = "TCP"
interval = 30
unhealthy_threshold = 2
}
}

resource "aws_lb_target_group_attachment" "github_app_attachment" {
target_group_arn = aws_lb_target_group.github_tg.arn
target_id = local.github_app_instance_id
port = 443
}

# LISTENER
resource "aws_lb_listener" "github_listener" {
load_balancer_arn = aws_lb.github_nlb.arn

protocol = "TCP"
port = 443

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.github_tg.id
}
}

# VPC ENDPOINT SERVICE
resource "aws_vpc_endpoint_service" "github" {
acceptance_required = false
network_load_balancer_arns = [aws_lb.github_nlb.arn]
supported_regions = ["<your-region>", "us-east-2"] # MUST include us-east-2
allowed_principals = [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:root",
"arn:aws:iam::${local.infracost_account_id}:root"
]
}

Appendix C: Resource Relationship Diagram