Skip to content

Commit 7434bc4

Browse files
committed
refactor: aws terraform
1 parent 69308e4 commit 7434bc4

File tree

5 files changed

+288
-11
lines changed

5 files changed

+288
-11
lines changed

examples/aws/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
terraform.tfvars
2+
.terraform*
3+
terraform.tfstate*

examples/aws/main.tf

Lines changed: 233 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,242 @@ terraform {
77
}
88
}
99

10-
variable "image" {}
11-
output "submit_url" {
12-
value = module.admin_bot.submit_url
13-
}
14-
1510
provider "aws" {
1611
region = "us-east-1"
1712
}
1813

19-
module "admin_bot" {
20-
source = "redpwn/admin-bot/aws"
21-
image = var.image
22-
recaptcha = {
23-
site = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
24-
secret = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
14+
data "aws_region" "region" {}
15+
16+
resource "aws_default_vpc" "default" {}
17+
18+
data "aws_subnet_ids" "default" {
19+
vpc_id = aws_default_vpc.default.id
20+
}
21+
22+
resource "aws_vpc" "visit" {
23+
cidr_block = var.visit_cidr
24+
tags = {
25+
Name = "${var.prefix}-visit"
2526
}
2627
}
28+
29+
resource "aws_subnet" "visit" {
30+
vpc_id = aws_vpc.visit.id
31+
cidr_block = aws_vpc.visit.cidr_block
32+
tags = {
33+
Name = "${var.prefix}-visit"
34+
}
35+
}
36+
37+
resource "aws_internet_gateway" "visit" {
38+
vpc_id = aws_vpc.visit.id
39+
tags = {
40+
Name = "${var.prefix}-visit"
41+
}
42+
}
43+
44+
resource "aws_default_route_table" "visit" {
45+
default_route_table_id = aws_vpc.visit.default_route_table_id
46+
route {
47+
cidr_block = "0.0.0.0/0"
48+
gateway_id = aws_internet_gateway.visit.id
49+
}
50+
}
51+
52+
resource "aws_security_group" "visit" {
53+
name = "${var.prefix}-visit"
54+
vpc_id = aws_vpc.visit.id
55+
egress {
56+
cidr_blocks = ["0.0.0.0/0"]
57+
protocol = "tcp"
58+
from_port = 0
59+
to_port = 65535
60+
}
61+
}
62+
63+
resource "aws_sqs_queue" "queue" {
64+
name = var.prefix
65+
visibility_timeout_seconds = 80
66+
message_retention_seconds = 3600
67+
}
68+
69+
resource "aws_ecs_cluster" "visit" {
70+
name = "${var.prefix}-visit"
71+
}
72+
73+
data "aws_iam_policy_document" "visit_assume" {
74+
statement {
75+
actions = ["sts:AssumeRole"]
76+
principals {
77+
type = "Service"
78+
identifiers = ["ecs-tasks.amazonaws.com"]
79+
}
80+
}
81+
}
82+
83+
resource "aws_iam_role" "visit_execution" {
84+
name = "${var.prefix}-visit-execution"
85+
assume_role_policy = data.aws_iam_policy_document.visit_assume.json
86+
managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
87+
}
88+
89+
data "aws_iam_policy_document" "visit_task" {
90+
statement {
91+
actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage"]
92+
resources = [aws_sqs_queue.queue.arn]
93+
}
94+
}
95+
96+
resource "aws_iam_role" "visit_task" {
97+
name = "${var.prefix}-visit-task"
98+
assume_role_policy = data.aws_iam_policy_document.visit_assume.json
99+
inline_policy {
100+
name = "visit"
101+
policy = data.aws_iam_policy_document.visit_task.json
102+
}
103+
}
104+
105+
resource "aws_ecs_task_definition" "visit" {
106+
family = "${var.prefix}-visit"
107+
task_role_arn = aws_iam_role.visit_task.arn
108+
execution_role_arn = aws_iam_role.visit_execution.arn
109+
cpu = 512
110+
memory = 1024
111+
network_mode = "awsvpc"
112+
requires_compatibilities = ["FARGATE"]
113+
container_definitions = jsonencode([{
114+
name = "visit"
115+
image = var.image
116+
command = ["visit"]
117+
essential = true
118+
image = var.image
119+
environment = [{
120+
name = "APP_SQS_URL"
121+
value = aws_sqs_queue.queue.id
122+
}]
123+
logConfiguration = {
124+
logDriver = "awslogs"
125+
options = {
126+
awslogs-group = aws_cloudwatch_log_group.visit.name
127+
awslogs-region = data.aws_region.region.name
128+
awslogs-stream-prefix = "ecs"
129+
}
130+
}
131+
}])
132+
}
133+
134+
resource "aws_ecs_service" "visit" {
135+
name = "visit"
136+
cluster = aws_ecs_cluster.visit.arn
137+
desired_count = var.visit_scale
138+
deployment_minimum_healthy_percent = 100
139+
launch_type = "FARGATE"
140+
network_configuration {
141+
subnets = [aws_subnet.visit.id]
142+
security_groups = [aws_security_group.visit.id]
143+
assign_public_ip = true
144+
}
145+
task_definition = aws_ecs_task_definition.visit.arn
146+
depends_on = [aws_default_route_table.visit]
147+
}
148+
149+
resource "aws_cloudwatch_log_group" "submit" {
150+
name = "/aws/lambda/${var.prefix}-submit"
151+
}
152+
153+
resource "aws_cloudwatch_log_group" "visit" {
154+
name = "/ecs/${var.prefix}-visit"
155+
}
156+
157+
data "aws_iam_policy_document" "submit_assume" {
158+
statement {
159+
actions = ["sts:AssumeRole"]
160+
principals {
161+
type = "Service"
162+
identifiers = ["lambda.amazonaws.com"]
163+
}
164+
}
165+
}
166+
167+
data "aws_iam_policy_document" "submit_task" {
168+
statement {
169+
actions = ["sqs:SendMessage"]
170+
resources = [aws_sqs_queue.queue.arn]
171+
}
172+
statement {
173+
actions = ["logs:CreateLogStream", "logs:PutLogEvents"]
174+
resources = ["${aws_cloudwatch_log_group.submit.arn}:*"]
175+
}
176+
}
177+
178+
resource "aws_iam_role" "submit" {
179+
name = "${var.prefix}-submit"
180+
assume_role_policy = data.aws_iam_policy_document.submit_assume.json
181+
inline_policy {
182+
name = "submit"
183+
policy = data.aws_iam_policy_document.submit_task.json
184+
}
185+
}
186+
187+
resource "aws_lambda_function" "submit" {
188+
function_name = "${var.prefix}-submit"
189+
role = aws_iam_role.submit.arn
190+
package_type = "Image"
191+
image_config {
192+
command = ["submit"]
193+
}
194+
image_uri = var.image
195+
reserved_concurrent_executions = var.submit_max_scale
196+
environment {
197+
variables = {
198+
APP_SQS_URL = aws_sqs_queue.queue.id
199+
APP_RECAPTCHA_SITE = var.recaptcha.site
200+
APP_RECAPTCHA_SECRET = var.recaptcha.secret
201+
}
202+
}
203+
}
204+
205+
resource "aws_security_group" "submit" {
206+
name = "${var.prefix}-submit"
207+
vpc_id = aws_default_vpc.default.id
208+
ingress {
209+
cidr_blocks = ["0.0.0.0/0"]
210+
protocol = "tcp"
211+
from_port = 80
212+
to_port = 80
213+
}
214+
}
215+
216+
resource "aws_lb" "submit" {
217+
name = "${var.prefix}-submit"
218+
subnets = data.aws_subnet_ids.default.ids
219+
security_groups = [aws_security_group.submit.id]
220+
}
221+
222+
resource "aws_lb_target_group" "submit" {
223+
name = "${var.prefix}-submit"
224+
target_type = "lambda"
225+
}
226+
227+
resource "aws_lb_listener" "submit" {
228+
load_balancer_arn = aws_lb.submit.arn
229+
port = 80
230+
default_action {
231+
type = "forward"
232+
target_group_arn = aws_lb_target_group.submit.arn
233+
}
234+
}
235+
236+
resource "aws_lambda_permission" "submit" {
237+
statement_id = "${var.prefix}-submit"
238+
action = "lambda:InvokeFunction"
239+
function_name = aws_lambda_function.submit.arn
240+
principal = "elasticloadbalancing.amazonaws.com"
241+
source_arn = aws_lb_target_group.submit.arn
242+
}
243+
244+
resource "aws_lb_target_group_attachment" "submit" {
245+
target_group_arn = aws_lb_target_group.submit.arn
246+
target_id = aws_lambda_function.submit.arn
247+
depends_on = [aws_lambda_permission.submit]
248+
}

examples/aws/outputs.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output "submit_url" {
2+
value = "http://${aws_lb.submit.dns_name}"
3+
description = "Public ALB URL for submissions"
4+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
image = ""
2+
3+
# Optional:
4+
#recaptcha = {
5+
# site = ""
6+
# secret = ""
7+
#}

examples/aws/variables.tf

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
variable "prefix" {
2+
type = string
3+
default = "admin-bot"
4+
description = "Prefix for all AWS resources created by the module"
5+
}
6+
7+
variable "visit_cidr" {
8+
type = string
9+
default = "10.13.37.0/24"
10+
description = "CIDR for visit container VPC and subnet"
11+
}
12+
13+
variable "image" {
14+
type = string
15+
description = "Docker image URI on ECR with redpwn/admin-bot base"
16+
}
17+
18+
variable "recaptcha" {
19+
type = object({
20+
site = string
21+
secret = string
22+
})
23+
default = {
24+
site = null
25+
secret = null
26+
}
27+
sensitive = true
28+
description = "Google reCAPTCHA credentials"
29+
}
30+
31+
variable "submit_max_scale" {
32+
type = number
33+
default = 100
34+
description = "Maximum concurrent submit instances"
35+
}
36+
37+
variable "visit_scale" {
38+
type = number
39+
default = 1
40+
description = "Concurrent visit instances"
41+
}

0 commit comments

Comments
 (0)