Skip to content

Self-Hosted Runners

Run Controlinfra scans in your own infrastructure for enhanced security and compliance.

Overview

Self-hosted runners allow you to:

  • Keep credentials local: AWS credentials never leave your infrastructure
  • Meet compliance requirements: Run scans within your security perimeter
  • Use IAM roles: No access keys needed—use instance profiles
  • Control the environment: Your infrastructure, your rules

How It Works

┌─────────────────────────────────────────────────────────────┐
│                     Your Infrastructure                      │
│  ┌─────────────────┐    ┌───────────────────────────────┐  │
│  │  Self-Hosted    │    │       Your AWS Resources      │  │
│  │    Runner       │───▶│  (EC2, RDS, S3, etc.)         │  │
│  │                 │    └───────────────────────────────┘  │
│  │  • Terraform    │                                       │
│  │  • AWS CLI      │    ┌───────────────────────────────┐  │
│  │  • Git          │───▶│    Terraform State (S3)       │  │
│  └────────┬────────┘    └───────────────────────────────┘  │
│           │                                                 │
└───────────┼─────────────────────────────────────────────────┘
            │ Results only

┌─────────────────────────────────────────────────────────────┐
│                    Controlinfra Cloud                        │
│  • Receives scan results                                    │
│  • Displays in dashboard                                    │
│  • AI analysis (using your API key)                         │
└─────────────────────────────────────────────────────────────┘

Prerequisites

  • An EC2 instance (or similar compute) in your AWS account
  • Network access to your AWS resources
  • IAM role with read permissions
  • Outbound internet access (HTTPS to Controlinfra)

Setup Guide

Step 1: Create IAM Role

Create an IAM role for the runner:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TerraformReadAccess",
      "Effect": "Allow",
      "Action": [
        "ec2:Describe*",
        "s3:GetObject",
        "s3:ListBucket",
        "rds:Describe*",
        "iam:Get*",
        "iam:List*",
        "lambda:Get*",
        "lambda:List*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "TerraformStateAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::your-terraform-state-bucket",
        "arn:aws:s3:::your-terraform-state-bucket/*"
      ]
    },
    {
      "Sid": "DynamoDBLocking",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:DeleteItem"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/terraform-locks"
    }
  ]
}

Step 2: Launch EC2 Instance

Launch an EC2 instance with:

SettingRecommendation
AMIAmazon Linux 2023 or Ubuntu 22.04
Instance Typet3.small or larger
IAM RoleThe role created in Step 1
Security GroupOutbound HTTPS (443) only
Storage20GB+ (for Terraform providers)

Step 3: Install Dependencies

SSH into your instance and run:

bash
#!/bin/bash

# Update system
sudo yum update -y  # Amazon Linux
# sudo apt update && sudo apt upgrade -y  # Ubuntu

# Install Git
sudo yum install -y git
# sudo apt install -y git

# Install Terraform
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo yum install -y terraform

# Verify installations
git --version
terraform --version
aws --version

Step 4: Register Runner in Controlinfra

  1. Go to SettingsRunners
  2. Click "Add Runner"
  3. Copy the registration token

Step 5: Install Runner Agent

On your EC2 instance:

bash
# Download runner agent
curl -fsSL https://controlinfra.com/runner/install.sh | bash

# Configure with your token
controlinfra-runner configure --token YOUR_TOKEN

# Start the runner
controlinfra-runner start

Step 6: Verify Connection

In Controlinfra:

  1. Go to SettingsRunners
  2. Your runner should show as "Online"

Runner Configuration

Configuration File

The runner configuration is stored at ~/.controlinfra/runner.yml:

yaml
token: "your-runner-token"
name: "production-runner"
labels:
  - production
  - aws
  - us-east-1
workDir: "/tmp/controlinfra"
logLevel: "info"

Environment Variables

Configure the runner using environment variables:

bash
export CONTROLINFRA_TOKEN="your-token"
export CONTROLINFRA_RUNNER_NAME="production-runner"
export CONTROLINFRA_WORK_DIR="/tmp/controlinfra"
export CONTROLINFRA_LOG_LEVEL="debug"

Labels

Use labels to target specific runners:

yaml
labels:
  - production
  - aws
  - us-east-1

Then in repository settings, specify which runner to use:

Runner: production, aws

Running as a Service

systemd Service

Create /etc/systemd/system/controlinfra-runner.service:

ini
[Unit]
Description=Controlinfra Runner
After=network.target

[Service]
Type=simple
User=controlinfra
ExecStart=/usr/local/bin/controlinfra-runner start
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start:

bash
sudo systemctl enable controlinfra-runner
sudo systemctl start controlinfra-runner

Docker

Run the runner in Docker:

bash
docker run -d \
  --name controlinfra-runner \
  --restart always \
  -e CONTROLINFRA_TOKEN=your-token \
  -v /var/run/docker.sock:/var/run/docker.sock \
  controlinfra/runner:latest

Security Best Practices

1. Network Isolation

  • Place runner in a private subnet
  • Use NAT Gateway for outbound access
  • Restrict inbound access completely

2. IAM Least Privilege

  • Only grant read permissions needed
  • Use resource-level permissions where possible
  • Regularly audit IAM policies

3. Secrets Management

bash
# Don't store secrets in environment variables
# Use AWS Secrets Manager or Parameter Store
aws secretsmanager get-secret-value --secret-id controlinfra/token

4. Logging and Monitoring

bash
# Enable CloudWatch logging
sudo yum install -y amazon-cloudwatch-agent

5. Regular Updates

bash
# Update runner agent regularly
controlinfra-runner update

Multiple Runners

For high availability or multi-environment setups:

Environment-Specific Runners

production-runner (labels: production, us-east-1)
   └── Scans production repositories

staging-runner (labels: staging, us-east-1)
   └── Scans staging repositories

eu-runner (labels: production, eu-west-1)
   └── Scans EU region resources

Load Balancing

Multiple runners with the same labels will automatically load balance:

runner-1 (labels: production)
runner-2 (labels: production)
runner-3 (labels: production)

Assigning Runners to Repositories

In Repository Settings

  1. Navigate to your repository
  2. Go to SettingsRunner
  3. Select runner type:
    • Cloud Runner: Use Controlinfra's hosted runner
    • Self-Hosted: Use your own runner
  4. If self-hosted, select the runner or specify labels

Using Labels

yaml
Repository: my-terraform-repo
Runner Type: Self-Hosted
Runner Labels: production, us-east-1

Troubleshooting

Runner Shows "Offline"

  1. Check the runner service is running:

    bash
    systemctl status controlinfra-runner
  2. Check network connectivity:

    bash
    curl -v https://api.controlinfra.com/health
  3. Verify the token:

    bash
    controlinfra-runner verify

Scans Failing on Runner

  1. Check runner logs:

    bash
    journalctl -u controlinfra-runner -f
  2. Verify Terraform is installed:

    bash
    terraform version
  3. Check IAM permissions:

    bash
    aws sts get-caller-identity

"Permission Denied" Errors

  • Verify IAM role is attached to the instance
  • Check IAM policy has required permissions
  • Ensure the work directory is writable

Terraform Init Failures

  • Check network access to Terraform registries
  • Verify provider credentials
  • Check disk space for provider downloads

Maintenance

Updating the Runner

bash
# Stop the runner
sudo systemctl stop controlinfra-runner

# Update
controlinfra-runner update

# Start the runner
sudo systemctl start controlinfra-runner

Rotating Tokens

  1. Generate new token in Controlinfra Settings
  2. Update runner configuration
  3. Restart the runner
  4. Revoke old token

Log Rotation

Configure log rotation in /etc/logrotate.d/controlinfra:

/var/log/controlinfra/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
}

Next Steps

AI-powered infrastructure drift detection