Skip to main content
This guide is for creating Penn Labs infrastructure from scratch. Only follow these steps if you’re rebuilding the entire infrastructure or setting up a new environment.
This guide walks through bootstrapping the complete Penn Labs infrastructure using Terraform.

Prerequisites

Before starting, ensure you have:
  • Terraform installed
  • psql (PostgreSQL client) installed
  • AWS Console access with permissions to create IAM users
  • All required environment variables (see below)

Step 1: Create AWS Credentials

1

Create Terraform IAM User

  1. Go to AWS IAM Console
  2. Create a new user named terraform
  3. Attach the AdministratorAccess policy to the user
  4. Generate access keys for the user
2

Export AWS Credentials

Export the following environment variables:
VariableDescription
AWS_ACCESS_KEY_IDThe AWS Access Key for terraform
AWS_SECRET_ACCESS_KEYThe AWS Secret Key for terraform
export AWS_ACCESS_KEY_ID="your-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-secret-access-key"
3

Export Additional Environment Variables

Export all environment variables specified in the Terraform README inputs:
export GH_PERSONAL_TOKEN="your-github-token"
export GF_GH_CLIENT_ID="your-grafana-client-id"
export GF_GH_CLIENT_SECRET="your-grafana-client-secret"
export GF_SLACK_URL="your-slack-webhook-url"

Step 2: Create S3 Backend

The S3 backend stores Terraform state remotely, allowing team collaboration and state locking.
1

Prepare Configuration

In the terraform/ directory:
  1. Comment out the terraform block in provider.tf
  2. Comment out everything in vault.tf
This is necessary because the backend and Vault don’t exist yet.
2

Create Backend Bucket

Run the following commands:
terraform init
terraform apply --target module.tfstate_backend
This creates the S3 bucket that will store Terraform state.

Step 3: Initial Infrastructure Deployment

1

Configure Vault DNS

You will need to manually create the verification DNS record for Vault and rerun terraform apply.
After the initial apply, check the AWS Certificate Manager console for the DNS validation record required for the Vault TLS certificate.
2

Export Vault Token

After Vault is initialized, export the root token:
VariableDescription
VAULT_TOKENThe root vault token you just generated
export VAULT_TOKEN="your-vault-root-token"
Keep all previously exported environment variables active.
3

Enable Remote Backend

Uncomment the terraform block in provider.tf, then run:
terraform init
terraform apply
If you encounter issues, running terraform apply a second time usually resolves them.

Step 4: Configure Vault DNS

Create the following DNS records in your DNS provider. Find the Elastic Load Balancer DNS name for Vault in the AWS Management Console.
TypeNameDestination
CNAMEvault.pennlabs.orgxyz.us-east-1.elb.amazonaws.com
CNAME_acme-challenge.pennlabs.org_acme-challenge.upenn.club
Replace xyz.us-east-1.elb.amazonaws.com with the actual ELB DNS name from the AWS console.

Step 5: Initialize Vault

1

Visit Vault UI

Navigate to https://vault.pennlabs.org and follow the initialization prompts.
2

Save Vault Credentials

Save the root token and recovery key in a secure location (e.g., password manager). These cannot be recovered if lost.

Step 6: Complete Vault Configuration

1

Uncomment Vault Configuration

Uncomment everything in vault.tf.
2

Apply Final Configuration

terraform init
terraform apply

Step 7: Configure Production DNS

Create the following DNS records. Find the Traefik load balancer IP address in the AWS Management Console.
TypeNameDestination
Apennlabs.orgy.y.y.y
CNAME*.pennlabs.orgpennlabs.org
A<all product domains>y.y.y.y
CNAME_acme-challenge.<all product domains>_acme-challenge.upenn.club
Replace y.y.y.y with the actual Traefik IP address. Product domains include: ohq.io, pennbasics.com, penncfa.com, pennclubs.com, penncoursealert.com, penncourseplan.com, penncoursereview.com, penndegreeplan.com, penncourses.org, pennmobile.org.

Verification

If all steps completed successfully, you should have:
  • A fully functional EKS Kubernetes cluster
  • RDS PostgreSQL database cluster
  • HashiCorp Vault for secrets management
  • Configured DNS for all product domains
  • GitHub Actions integration
  • Monitoring and observability infrastructure
You can verify the cluster is healthy by running:
kubectl get nodes
kubectl get pods --all-namespaces

Build docs developers (and LLMs) love