-
Notifications
You must be signed in to change notification settings - Fork 152
/
main.tf
216 lines (184 loc) · 7.61 KB
/
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# Elastic Beanstalk Application
module "elastic_beanstalk_application" {
source = "cloudposse/elastic-beanstalk-application/aws"
version = "0.11.1"
description = var.description
attributes = ["app"]
context = module.this.context
}
# Elastic Beanstalk Environment
module "elastic_beanstalk_environment" {
source = "cloudposse/elastic-beanstalk-environment/aws"
version = "0.46.0"
attributes = ["env"]
region = var.region
dns_zone_id = var.dns_zone_id
elastic_beanstalk_application_name = module.elastic_beanstalk_application.elastic_beanstalk_application_name
instance_type = var.master_instance_type
tier = "WebServer"
environment_type = var.environment_type
loadbalancer_type = var.loadbalancer_type
loadbalancer_certificate_arn = var.loadbalancer_certificate_arn
availability_zone_selector = var.availability_zone_selector
rolling_update_type = var.rolling_update_type
# Set `min` and `max` number of running EC2 instances to `1` since we want only one Jenkins master running at any time
autoscale_min = 1
autoscale_max = 1
# Since we set `autoscale_min = autoscale_max`, we need to set `updating_min_in_service` to 0 for the AutoScaling Group to work.
# Elastic Beanstalk will terminate the master instance and replace it with a new one in case of any issues with it.
# It's OK since we store all Jenkins state (settings, jobs, etc.) on the EFS.
# If the instance gets replaced or rebooted, Jenkins will find all the data on the EFS after restart.
updating_min_in_service = 0
updating_max_batch = 1
healthcheck_url = var.healthcheck_url
vpc_id = var.vpc_id
loadbalancer_subnets = var.loadbalancer_subnets
application_subnets = var.application_subnets
keypair = var.ssh_key_pair
solution_stack_name = var.solution_stack_name
force_destroy = var.loadbalancer_logs_bucket_force_destroy
loadbalancer_ssl_policy = var.loadbalancer_ssl_policy
associated_security_group_ids = var.associated_security_group_ids
# Provide EFS DNS name to EB in the `EFS_HOST` ENV var. EC2 instance will mount to the EFS filesystem and use it to store Jenkins state
# Add slaves Security Group `JENKINS_SLAVE_SECURITY_GROUPS` (comma-separated if more than one). Will be used by Jenkins to init the EC2 plugin to launch slaves inside the Security Group
env_vars = merge(
{
"EFS_HOST" = var.use_efs_ip_address ? module.efs.mount_target_ips[0] : module.efs.dns_name
"USE_EFS_IP" = var.use_efs_ip_address
"JENKINS_SLAVE_SECURITY_GROUPS" = aws_security_group.slaves.id
},
var.env_vars
)
context = module.this.context
}
# Elastic Container Registry Docker Repository
module "ecr" {
source = "cloudposse/ecr/aws"
version = "0.34.0"
context = module.this.context
}
# EFS to store Jenkins state (settings, jobs, etc.)
module "efs" {
source = "cloudposse/efs/aws"
version = "0.32.7"
attributes = ["efs"]
region = var.region
vpc_id = var.vpc_id
subnets = var.application_subnets
zone_id = [var.dns_zone_id]
# EC2 instances (from `elastic_beanstalk_environment`) are allowed to connect to the EFS
security_groups = [module.elastic_beanstalk_environment.security_group_id]
context = module.this.context
}
# EFS backup
module "efs_backup" {
source = "cloudposse/backup/aws"
version = "0.14.0"
attributes = ["efs"]
backup_resources = [module.efs.arn]
schedule = var.efs_backup_schedule
start_window = var.efs_backup_start_window
completion_window = var.efs_backup_completion_window
cold_storage_after = var.efs_backup_cold_storage_after
delete_after = var.efs_backup_delete_after
context = module.this.context
}
# CodePipeline/CodeBuild to build Jenkins Docker image, store it to a ECR repo, and deploy it to Elastic Beanstalk running Docker stack
module "cicd" {
source = "cloudposse/cicd/aws"
version = "0.19.5"
attributes = ["cicd"]
elastic_beanstalk_application_name = module.elastic_beanstalk_application.elastic_beanstalk_application_name
elastic_beanstalk_environment_name = module.elastic_beanstalk_environment.name
enabled = true
github_oauth_token = var.github_oauth_token
repo_owner = var.github_organization
repo_name = var.github_repo_name
branch = var.github_branch
build_image = var.build_image
build_compute_type = var.build_compute_type
privileged_mode = true
region = var.region
aws_account_id = var.aws_account_id
image_repo_name = module.ecr.repository_name
image_tag = var.image_tag
poll_source_changes = true
force_destroy = var.cicd_bucket_force_destroy
context = module.this.context
}
# Label for EC2 slaves
module "label_slaves" {
source = "cloudposse/label/null"
version = "0.25.0"
attributes = ["slaves"]
context = module.this.context
}
# Security Group for EC2 slaves
resource "aws_security_group" "slaves" {
name = module.label_slaves.id
description = "Security Group for Jenkins EC2 slaves"
vpc_id = var.vpc_id
# Allow the provided Security Groups to connect to Jenkins slave instances
ingress {
from_port = 0
to_port = 0
protocol = -1
security_groups = var.associated_security_group_ids
}
# Allow Jenkins master instance to communicate with Jenkins slave instances on SSH port 22
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [module.elastic_beanstalk_environment.security_group_id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = module.label_slaves.tags
}
# Policy document with permissions to launch new EC2 instances
# https://wiki.jenkins.io/display/JENKINS/Amazon+EC2+Plugin
data "aws_iam_policy_document" "slaves" {
statement {
sid = "AllowLaunchingEC2Instances"
actions = [
"ec2:DescribeSpotInstanceRequests",
"ec2:CancelSpotInstanceRequests",
"ec2:GetConsoleOutput",
"ec2:RequestSpotInstances",
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:DescribeInstances",
"ec2:DescribeKeyPairs",
"ec2:DescribeRegions",
"ec2:DescribeImages",
"ec2:DescribeAvailabilityZones",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"iam:PassRole"
]
resources = ["*"]
effect = "Allow"
}
}
# Policy for the EB EC2 instance profile to allow launching Jenkins slaves
resource "aws_iam_policy" "slaves" {
name = module.label_slaves.id
path = "/"
description = "Policy for EC2 instance profile to allow launching Jenkins slaves"
policy = data.aws_iam_policy_document.slaves.json
tags = module.label_slaves.tags
}
# Attach Policy to the EC2 instance profile to allow Jenkins master to launch and control slave EC2 instances
resource "aws_iam_role_policy_attachment" "slaves" {
role = module.elastic_beanstalk_environment.ec2_instance_profile_role_name
policy_arn = aws_iam_policy.slaves.arn
}