Skip to content

Commit

Permalink
feat: support autoscaling runners (#117)
Browse files Browse the repository at this point in the history
## Description

This PR explores using the fleeting plugins to create instances for
GitLab runners

## Related Issue

Fixes #79
Fixes #48 
Fixes #66

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Other (security config, docs update, etc)

## Checklist before merging

- [ ] Test, docs, adr added or updated as needed
- [X] [Contributor Guide
Steps](https://github.com/defenseunicorns/uds-package-gitlab-runner/blob/main/CONTRIBUTING.md#developer-workflow)
followed

---------

Co-authored-by: Jordan McClintock <jordan@defenseunicorns.com>
Co-authored-by: Eric Wyles <23637493+ericwyles@users.noreply.github.com>
  • Loading branch information
3 people committed Sep 6, 2024
1 parent c822744 commit 38482bd
Show file tree
Hide file tree
Showing 27 changed files with 956 additions and 9 deletions.
26 changes: 26 additions & 0 deletions .github/test-infra/asg-iac/config.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
provider "aws" {
region = var.region

default_tags {
tags = {
PermissionsBoundary = var.permissions_boundary_name
}
}
}

terraform {
required_version = ">= 1.8.0"
backend "s3" {
}
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}

random = {
source = "hashicorp/random"
version = "3.6.2"
}
}
}
84 changes: 84 additions & 0 deletions .github/test-infra/asg-iac/irsa.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
data "aws_s3_bucket" "oidc_bucket" {
bucket = "govcloud-ci-oidc"
}

data "aws_partition" "current" {}

data "aws_caller_identity" "current" {}

## This will create a policy for the Autoscaling Group (https://gitlab.com/gitlab-org/fleeting/plugins/aws#setting-an-iam-policy)
resource "aws_iam_policy" "asg_policy" {
name = "${var.name}-policy"
path = "/"
description = "IRSA policy to access the autoscaling group."
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
]
Resource = aws_autoscaling_group.uds-package-gitlab-runner.arn
},
{
Effect = "Allow"
Action = [
"autoscaling:DescribeAutoScalingGroups",
"ec2:DescribeInstances",
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"ec2:GetPasswordData",
"ec2-instance-connect:SendSSHPublicKey",
]
Resource = "arn:${data.aws_partition.current.partition}:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:instance/*"
Condition = {
StringEquals = {
"ec2:ResourceTag/aws:autoscaling:groupName": aws_autoscaling_group.uds-package-gitlab-runner.name
}
}
}
]
})
}

## Create service account role
resource "aws_iam_role" "asg_role" {
name = "${var.name}-asg-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRoleWithWebIdentity"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
"Federated" : "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${data.aws_s3_bucket.oidc_bucket.bucket_regional_domain_name}"
}
"Condition" : {
"StringEquals" : {
"${data.aws_s3_bucket.oidc_bucket.bucket_regional_domain_name}:aud" : "irsa",
"${data.aws_s3_bucket.oidc_bucket.bucket_regional_domain_name}:sub" : "system:serviceaccount:${var.namespace}:${var.service_account}"
}
}
}
]
})

permissions_boundary = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:policy/${var.permissions_boundary_name}"

tags = {
PermissionsBoundary = var.permissions_boundary_name
}
}

resource "aws_iam_role_policy_attachment" "asg_policy_attach" {
role = aws_iam_role.asg_role.name
policy_arn = aws_iam_policy.asg_policy.arn
}
129 changes: 129 additions & 0 deletions .github/test-infra/asg-iac/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
data "aws_availability_zones" "available" {
state = "available"
}

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.1"

name = "${var.name}-vpc"
cidr = "10.0.0.0/16"
azs = [for az_name in slice(data.aws_availability_zones.available.names, 0, min(length(data.aws_availability_zones.available.names), 3)) : az_name]
public_subnets = [for k, v in module.vpc.azs : cidrsubnet(module.vpc.vpc_cidr_block, 5, k)]
enable_nat_gateway = false

instance_tenancy = "default"
vpc_flow_log_permissions_boundary = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:policy/${var.permissions_boundary_name}"

tags = {
Name = "${var.name}-vpc"
}
}

resource "aws_launch_template" "uds-package-gitlab-runner" {
name_prefix = "uds-package-gitlab-runner-"
image_id = var.ami_id
instance_type = "t3.micro"

network_interfaces {
associate_public_ip_address = true
security_groups = [aws_security_group.uds-package-gitlab-runner.id]
}

block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = 8
}
}

tag_specifications {
resource_type = "instance"
tags = {
Name = "${var.name}-launch-template"
}
}
}

# AWS Fleeting Plugin: https://gitlab.com/gitlab-org/fleeting/plugins/aws#autoscaling-group-setup
resource "aws_autoscaling_group" "uds-package-gitlab-runner" {
name = var.name
desired_capacity = 0
max_size = 10
min_size = 0
vpc_zone_identifier = module.vpc.public_subnets

launch_template {
id = aws_launch_template.uds-package-gitlab-runner.id
version = "$Latest"
}
}

resource "aws_security_group" "uds-package-gitlab-runner" {
name = "${var.name}-security-group"
description = "Allow inbound traffic from GitHub runner"
vpc_id = module.vpc.vpc_id

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.runner_ip}/32"]
}

ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [module.vpc.vpc_cidr_block]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "tls_private_key" "jumpbox_tls_key" {
algorithm = "RSA"
rsa_bits = 4096
}

resource "aws_key_pair" "jumpbox_key_pair" {
key_name = "${var.name}-jumpbox-ssh-key"
public_key = tls_private_key.jumpbox_tls_key.public_key_openssh
}

resource "aws_instance" "jumpbox" {
ami = var.ami_id
instance_type = "t3.micro"
key_name = aws_key_pair.jumpbox_key_pair.key_name

tags = {
Name = "${var.name}-jumpbox"
}

# Security group to allow SSH (port 22)
vpc_security_group_ids = [aws_security_group.uds-package-gitlab-runner.id]
subnet_id = module.vpc.public_subnets[0]

associate_public_ip_address = true
}

resource "aws_route53_zone" "uds_dev" {
name = "uds.dev"
vpc {
vpc_id = module.vpc.vpc_id
}
}

resource "aws_route53_record" "my_domain" {
zone_id = aws_route53_zone.uds_dev.id
name = "gitlab.uds.dev"
type = "A"
ttl = 300

records = [aws_instance.jumpbox.private_ip]
}
21 changes: 21 additions & 0 deletions .github/test-infra/asg-iac/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
output "asg_arn" {
value = aws_autoscaling_group.uds-package-gitlab-runner.arn
description = "The ARN of the Autoscaling Group"
}

output "asg_role_arn" {
value = aws_iam_role.asg_role.arn
description = "The ARN of the ASG IRSA role"
}

output "jumpbox_public_ip" {
value = aws_instance.jumpbox.public_ip
description = "The IP Address of the jumpbox"
sensitive = true
}

output "jumpbox_private_key" {
value = tls_private_key.jumpbox_tls_key.private_key_pem
description = "The SSH Key for the jumpbox"
sensitive = true
}
37 changes: 37 additions & 0 deletions .github/test-infra/asg-iac/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
variable "runner_ip" {
description = "Public IP of the GitHub Actions runner"
type = string
}

variable "region" {
description = "AWS region"
type = string
}

variable "name" {
description = "Name for the Autoscaling Group"
type = string
}

variable "ami_id" {
description = "The ID of the AMI to scale in the ASG (must have git and gitlab-runner installed)"
type = string
}

variable "namespace" {
description = "Namespace containing the GitLab Runner Service Account"
type = string
default = "gitlab-runner"
}

variable "service_account" {
description = "Name of the GitLab Runner Service Account"
type = string
default = "gitlab-runner"
}

variable "permissions_boundary_name" {
description = "The name of the permissions boundary for IAM resources. This will be used for tagging and to build out the ARN."
type = string
default = null
}
Loading

0 comments on commit 38482bd

Please sign in to comment.