Skip to content

Commit ed61f6b

Browse files
authored
Merge pull request #1 from philips-labs/feature/add-runner-infra
Create infra code for runners
2 parents 8ebf0fb + 32168e2 commit ed61f6b

20 files changed

+511
-0
lines changed

examples/default/main.tf

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
locals {
2+
environment = "default-action-runners"
3+
aws_region = "eu-west-1"
4+
}
5+
6+
module "runners" {
7+
source = "../../"
8+
9+
aws_region = local.aws_region
10+
vpc_id = module.vpc.vpc_id
11+
12+
environment = local.environment
13+
tags = {
14+
Project = "ProjectX"
15+
}
16+
17+
}
18+

examples/default/outputs.tf

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
output "action_runners" {
2+
value = {
3+
runners = module.runners.runners
4+
}
5+
}

examples/default/providers.tf

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
provider "aws" {
2+
region = local.aws_region
3+
version = "2.59"
4+
}
5+

examples/default/vpc.tf

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module "vpc" {
2+
source = "git::https://github.com/philips-software/terraform-aws-vpc.git?ref=2.1.0"
3+
4+
environment = local.environment
5+
aws_region = local.aws_region
6+
}
7+

main.tf

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
resource "random_string" "random" {
2+
length = 24
3+
special = false
4+
upper = false
5+
}
6+
7+
module "dsitrubtion_cache" {
8+
source = "./modules/action-runner-binary-cache"
9+
10+
aws_region = var.aws_region
11+
environment = var.environment
12+
tags = var.tags
13+
14+
distribution_bucket_name = "${var.environment}-dist-${random_string.random.result}"
15+
}
16+
17+
module "runners" {
18+
source = "./modules/runners"
19+
20+
aws_region = var.aws_region
21+
vpc_id = var.vpc_id
22+
environment = var.environment
23+
tags = var.tags
24+
25+
s3_location_runner_distribution = module.dsitrubtion_cache.s3_location_runner_distribution
26+
}
27+
28+
29+
resource "aws_iam_policy" "dist_bucket" {
30+
name = "${var.environment}-gh-distribution-bucket"
31+
path = "/"
32+
description = "Policy for the runner to download the github action runner."
33+
34+
policy = templatefile("${path.module}/policies/action-runner-s3-policy.json",
35+
{
36+
s3_arn = module.dsitrubtion_cache.distribution_bucket.arn
37+
}
38+
)
39+
}
40+
41+
resource "aws_iam_role_policy_attachment" "dist_bucket" {
42+
role = module.runners.role.name
43+
policy_arn = aws_iam_policy.dist_bucket.arn
44+
}
45+
46+
resource "aws_resourcegroups_group" "resourcegroups_group" {
47+
name = "${var.environment}-group"
48+
49+
resource_query {
50+
query = <<-JSON
51+
{
52+
"ResourceTypeFilters": [
53+
"AWS::AllSupported"
54+
],
55+
"TagFilters": [
56+
{
57+
"Key": "Environment",
58+
"Values": ["${var.environment}"]
59+
}
60+
]
61+
}
62+
JSON
63+
}
64+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
locals {
2+
action_runner_distribution_object_key = "actions-runner-linux.tar.gz"
3+
}
4+
5+
resource "aws_s3_bucket" "action_dist" {
6+
bucket = var.distribution_bucket_name
7+
acl = "private"
8+
force_destroy = true
9+
tags = var.tags
10+
}
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
output "distribution_bucket" {
2+
value = aws_s3_bucket.action_dist
3+
}
4+
5+
output "s3_location_runner_distribution" {
6+
value = "s3://${aws_s3_bucket.action_dist.id}/${local.action_runner_distribution_object_key}"
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
variable "aws_region" {
2+
description = "AWS region."
3+
type = string
4+
}
5+
6+
variable "tags" {
7+
description = "Map of tags that will be added to created resources. By default resources will be tagged with name and environment."
8+
type = map(string)
9+
default = {}
10+
}
11+
12+
variable "environment" {
13+
description = "A name that identifies the environment, used as prefix and for tagging."
14+
type = string
15+
}
16+
17+
variable "distribution_bucket_name" {
18+
description = "Bucket for storing the action runner distribution."
19+
type = string
20+
}
21+

modules/runners/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Action runner module
2+
3+
The module create resources to facilitate the `orchestrator labmda` to recreate action runners.
4+
5+
- *launch template* : A launch template is created that can create an action runner, by default a spot instance is requested. For configuration parameters SSM is used.
6+
- *security group* : Security groups attached to the action runner.
7+
- *s3 bucket* : To avoid the action runner distribution to be downloaded from Github every time (which could be slow), a version is cached in a S3 bucket.
8+
- *policies and roles* : Policies and roles for the action runner. By default the session manager is enabled

modules/runners/main.tf

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
locals {
2+
name_sg = var.overrides["name_sg"] == "" ? local.tags["Name"] : var.overrides["name_sg"]
3+
4+
tags = merge(
5+
{
6+
"Name" = format("%s", var.environment)
7+
},
8+
{
9+
"Environment" = format("%s", var.environment)
10+
},
11+
var.tags,
12+
)
13+
}
14+
15+
data "aws_ami" "runner" {
16+
most_recent = "true"
17+
18+
dynamic "filter" {
19+
for_each = var.ami_filter
20+
content {
21+
name = filter.key
22+
values = filter.value
23+
}
24+
}
25+
26+
owners = var.ami_owners
27+
}
28+
29+
resource "aws_launch_template" "runner" {
30+
name = "${var.environment}-action-runner"
31+
32+
dynamic "block_device_mappings" {
33+
for_each = [var.block_device_mappings]
34+
content {
35+
device_name = "/dev/xvda"
36+
37+
ebs {
38+
delete_on_termination = lookup(block_device_mappings.value, "delete_on_termination", true)
39+
volume_type = lookup(block_device_mappings.value, "volume_type", "gp2")
40+
volume_size = lookup(block_device_mappings.value, "volume_size", 30)
41+
encrypted = lookup(block_device_mappings.value, "encrypted", true)
42+
iops = lookup(block_device_mappings.value, "iops", null)
43+
}
44+
}
45+
}
46+
47+
iam_instance_profile {
48+
name = aws_iam_instance_profile.runner.name
49+
}
50+
51+
instance_initiated_shutdown_behavior = "terminate"
52+
53+
instance_market_options {
54+
market_type = var.market_options
55+
}
56+
57+
image_id = data.aws_ami.runner.id
58+
instance_type = var.instance_type
59+
60+
vpc_security_group_ids = [aws_security_group.runner_sg.id]
61+
62+
tag_specifications {
63+
resource_type = "instance"
64+
tags = local.tags
65+
}
66+
67+
user_data = base64encode(templatefile("${path.module}/templates/user-data.sh", {
68+
environment = var.environment
69+
pre_install = var.userdata_pre_install
70+
post_install = var.userdata_post_install
71+
s3_location_runner_distribution = var.s3_location_runner_distribution
72+
}))
73+
}
74+
75+
resource "aws_security_group" "runner_sg" {
76+
name_prefix = "${var.environment}-github-actions-runner-sg"
77+
description = "Github Actions Runner security group"
78+
79+
vpc_id = var.vpc_id
80+
81+
egress {
82+
from_port = 0
83+
to_port = 0
84+
protocol = "-1"
85+
cidr_blocks = ["0.0.0.0/0"]
86+
}
87+
tags = merge(
88+
local.tags,
89+
{
90+
"Name" = format("%s", local.name_sg)
91+
},
92+
)
93+
}

modules/runners/outputs.tf

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
output "launch_template" {
2+
value = aws_launch_template.runner
3+
}
4+
5+
output "role" {
6+
value = aws_iam_role.runner
7+
}

modules/runners/policies.tf

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
data "aws_caller_identity" "current" {}
2+
3+
resource "aws_iam_role" "runner" {
4+
name = "${var.environment}-github-action-runners-runner-role"
5+
assume_role_policy = templatefile("${path.module}/policies/instance-role-trust-policy.json", {})
6+
tags = local.tags
7+
}
8+
9+
resource "aws_iam_instance_profile" "runner" {
10+
name = "${var.environment}-github-action-runners-profile"
11+
role = aws_iam_role.runner.name
12+
}
13+
14+
resource "aws_iam_policy" "runner_session_manager_policy" {
15+
name = "${var.environment}-github-action-runners-session-manager"
16+
path = "/"
17+
description = "Policy session manager."
18+
19+
policy = templatefile("${path.module}/policies/instance-session-manager-policy.json", {})
20+
}
21+
22+
resource "aws_iam_role_policy_attachment" "runner_session_manager_policy" {
23+
role = aws_iam_role.runner.name
24+
policy_arn = aws_iam_policy.runner_session_manager_policy.arn
25+
}
26+
27+
resource "aws_iam_role_policy_attachment" "runner_session_manager_aws_managed" {
28+
role = aws_iam_role.runner.name
29+
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
30+
}
31+
32+
resource "aws_iam_policy" "ssm_parameters" {
33+
name = "${var.environment}-runner-ssm-parameters"
34+
path = "/"
35+
description = "Policy for the runner to download the github action runner."
36+
37+
policy = templatefile("${path.module}/policies/instance-ssm-parameters-policy.json",
38+
{
39+
arn_ssm_parameters = "arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}-*"
40+
}
41+
)
42+
}
43+
44+
resource "aws_iam_role_policy_attachment" "ssm_parameters" {
45+
role = aws_iam_role.runner.name
46+
policy_arn = aws_iam_policy.ssm_parameters.arn
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Sid": "",
6+
"Effect": "Allow",
7+
"Principal": {
8+
"Service": "ec2.amazonaws.com"
9+
},
10+
"Action": "sts:AssumeRole"
11+
}
12+
]
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Effect": "Allow",
6+
"Action": [
7+
"ssmmessages:CreateControlChannel",
8+
"ssmmessages:CreateDataChannel",
9+
"ssmmessages:OpenControlChannel",
10+
"ssmmessages:OpenDataChannel"
11+
],
12+
"Resource": "*"
13+
}
14+
]
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Effect": "Allow",
6+
"Action": ["ssm:DeleteParameter"],
7+
"Resource": "${arn_ssm_parameters}"
8+
},
9+
{
10+
"Effect": "Allow",
11+
"Action": ["ssm:GetParameters"],
12+
"Resource": "${arn_ssm_parameters}"
13+
}
14+
]
15+
}

0 commit comments

Comments
 (0)