Skip to content

Commit 5fbd668

Browse files
feat(): Add Ansible to mange installation of applications (#7)
1 parent 4e0a0f3 commit 5fbd668

11 files changed

+248
-122
lines changed

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,31 @@ This repository contains the Terraform that can be used to deploy an instance of
99
![Juice Shop](https://raw.githubusercontent.com/juice-shop/juice-shop/develop/frontend/src/assets/public/images/JuiceShop_Logo_100px.png) [OWASP Juice Shop](https://owasp.org/www-project-juice-shop/) is probably the most modern and sophisticated insecure web application!
1010

1111
![CTFd](https://ctfd.io/static/img/ctfd.svg) [CTFd](https://ctfd.io/) is a Capture The Flag (CTF) framework designed for ease of use.
12+
13+
# Usage Instructions
14+
15+
### Step 1: Provision AWS resources via Terraform
16+
17+
```
18+
terraform init
19+
terraform apply
20+
```
21+
22+
### Step 2: Install applications via Ansible playbooks
23+
24+
- Replace the `s3://bucket-name` with the value of the `s3_bucket_name_ansible_playbooks` output from the Terraform apply.
25+
- Replace the `--instance-ids` values with the corresponding `ec2_cftd_instance_id` and `ec2_owaspjs_instance_id` output values from the Terraform apply.
26+
27+
```
28+
aws s3 sync ./ansible s3://bucket-name --include "*.yml"
29+
# Install CFTd
30+
aws ssm send-command --document-name "AWS-RunAnsiblePlaybook" --instance-ids "i-0xxxxxxxxxxxxxxxx" --max-errors 1 --parameters '{"extravars":["SSM=True"],"check":["False"],"playbookurl":["s3://bucket-name/playbook_cftd.yml"]}' --timeout-seconds 600 --region ca-central-1
31+
# Install OWASP Juice Shop
32+
aws ssm send-command --document-name "AWS-RunAnsiblePlaybook" --instance-ids "i-0xxxxxxxxxxxxxxxx" --max-errors 1 --parameters '{"extravars":["SSM=True"],"check":["False"],"playbookurl":["s3://bucket-name/playbook_owaspjs.yml"]}' --timeout-seconds 600 --region ca-central-1
33+
```
34+
35+
### Step 3: Configure the Flags
36+
37+
[juice-shop-ctf-cli (OWASP Juice Shop CTF Extension)](https://www.npmjs.com/package/juice-shop-ctf-cli)
38+
39+
> The Node package juice-shop-ctf-cli helps you to prepare Capture the Flag events with the OWASP Juice Shop challenges for different popular CTF frameworks. This interactive utility allows you to populate a CTF game server in a matter of minutes.

ansible/playbook_cftd.yml

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
3+
- name: CFTd
4+
gather_facts: false
5+
remote_user: ssm-user
6+
become: true
7+
hosts: all
8+
9+
tasks:
10+
- name: Install Git
11+
dnf:
12+
name: git
13+
state: present
14+
15+
- name: Install Docker
16+
dnf:
17+
name: docker
18+
state: present
19+
20+
- name: Enable Docker service
21+
ansible.builtin.systemd:
22+
name: docker.service
23+
state: started
24+
enabled: true
25+
26+
- name: Add ssm-user user to docker group
27+
ansible.builtin.user:
28+
name: ssm-user
29+
groups: docker
30+
append: yes
31+
32+
- name: Create /opt/cftd directory
33+
ansible.builtin.file:
34+
path: /opt/cftd
35+
state: directory
36+
owner: ssm-user
37+
group: ssm-user
38+
mode: "0755"
39+
40+
- name: Workaround Git safe directory error
41+
community.general.git_config:
42+
name: safe.directory
43+
value: /opt/cftd
44+
scope: global
45+
environment:
46+
HOME: /home/ssm-user
47+
48+
- name: Read safe directory from git config
49+
community.general.git_config:
50+
name: safe.directory
51+
scope: global
52+
environment:
53+
HOME: /home/ssm-user
54+
55+
- name: Git clone CFTd git repo
56+
ansible.builtin.git:
57+
repo: "https://github.com/CTFd/CTFd.git"
58+
dest: /opt/cftd
59+
clone: yes
60+
environment:
61+
HOME: /home/ssm-user
62+
63+
- name: Change ownership of CFTd directory
64+
ansible.builtin.file:
65+
path: /opt/cftd
66+
state: directory
67+
recurse: yes
68+
owner: ssm-user
69+
group: ssm-user
70+
71+
- name: Download docker-compose
72+
become: true
73+
ansible.builtin.get_url:
74+
url: https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64
75+
dest: /usr/bin/docker-compose
76+
mode: "755"
77+
78+
- name: Run docker-compose to start cftd
79+
ansible.builtin.command: /usr/bin/docker-compose up -d
80+
args:
81+
chdir: /opt/cftd

ansible/playbook_juice.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
- name: OWASP Juice Shop
3+
gather_facts: false
4+
remote_user: ssm-user
5+
become: true
6+
hosts: all
7+
8+
tasks:
9+
- name: Install Docker
10+
become: true
11+
dnf:
12+
name: docker
13+
state: present
14+
15+
- name: Enable Docker service
16+
become: true
17+
ansible.builtin.systemd:
18+
name: docker.service
19+
state: started
20+
enabled: true
21+
22+
- name: Add ssm-user user to docker group
23+
become: true
24+
ansible.builtin.user:
25+
name: ssm-user
26+
groups: docker
27+
append: yes
28+
29+
- name: Pull bkimminich/juice-shop docker image
30+
community.docker.docker_image:
31+
name: bkimminich/juice-shop
32+
source: pull
33+
34+
- name: Launch OWASP Juice Shop container
35+
community.docker.docker_container:
36+
name: juice-shop
37+
image: bkimminich/juice-shop
38+
ports:
39+
- "80:3000"
40+
env:
41+
NODE: "ctf"

cloudwatch.tf

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fields @timestamp as Timestamp,
120120
httpRequest.httpMethod as Request_Method,
121121
httpRequest.uri as URI
122122
| sort @timestamp desc
123-
| filter action not like "ALLOW" and
124-
| terminatingRuleId in ["AWSManagedRulesAmazonIpReputationList", "AWSManagedRulesCommonRuleSet", "AWSManagedRulesKnownBadInputsRuleSet", "AWSManagedRulesSQLiRuleSet", "AWSManagedRulesLinuxRuleSet"]
123+
| filter terminatingRuleId in ["AWSManagedRulesAmazonIpReputationList", "AWSManagedRulesCommonRuleSet", "AWSManagedRulesKnownBadInputsRuleSet", "AWSManagedRulesSQLiRuleSet", "AWSManagedRulesLinuxRuleSet"]
124+
or nonTerminatingMatchingRules.0.ruleId in ["AWSManagedRulesAmazonIpReputationList", "AWSManagedRulesCommonRuleSet", "AWSManagedRulesKnownBadInputsRuleSet", "AWSManagedRulesSQLiRuleSet", "AWSManagedRulesLinuxRuleSet"]
125125
EOF
126126
}

ec2.tf

+12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ resource "aws_instance" "ctfd" {
3838

3939
iam_instance_profile = aws_iam_instance_profile.ctf.id
4040

41+
user_data = <<-EOF
42+
#!/bin/bash
43+
dnf update -y
44+
dnf install -y ansible
45+
EOF
46+
4147
tags = {
4248
Name = "CTFd"
4349
}
@@ -73,6 +79,12 @@ resource "aws_instance" "owaspjs" {
7379

7480
iam_instance_profile = aws_iam_instance_profile.ctf.id
7581

82+
user_data = <<-EOF
83+
#!/bin/bash
84+
dnf update -y
85+
dnf install -y ansible
86+
EOF
87+
7688
tags = {
7789
Name = "OWASP Juice Shop"
7890
}

outputs.tf

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ output "owaspjs_private_dns" {
88
value = aws_instance.owaspjs.private_dns
99
}
1010

11-
output "rds_hostname" {
12-
description = "RDS instance hostname"
13-
value = aws_db_instance.cftd.address
11+
output "s3_bucket_name_ansible_playbooks" {
12+
description = "The Ansible playbook S3 bucket name"
13+
value = aws_s3_bucket.ansible.bucket
1414
}
1515

16-
output "rds_port" {
17-
description = "RDS instance port"
18-
value = aws_db_instance.cftd.port
16+
output "ec2_cftd_instance_id" {
17+
description = "The EC2 instance ID of the CTFd instance"
18+
value = aws_instance.ctfd.id
1919
}
2020

21-
output "rds_username" {
22-
description = "RDS instance username"
23-
value = aws_db_instance.cftd.username
21+
output "ec2_owaspjs_instance_id" {
22+
description = "The EC2 instance ID of the OWASP Juice Shop instance"
23+
value = aws_instance.owaspjs.id
2424
}

rds.tf

-40
This file was deleted.

s3.tf

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
###======================== CTF S3 Ansible ====================== ###
2+
3+
resource "aws_s3_bucket" "ansible" {
4+
#checkov:skip=CKV2_AWS_61:Ensure that an S3 bucket has a lifecycle configuration
5+
#checkov:skip=CKV_AWS_18:Ensure the S3 bucket has access logging enabled
6+
#checkov:skip=CKV2_AWS_65:Ensure access control lists for S3 buckets are disabled
7+
#checkov:skip=CKV2_AWS_62:Ensure S3 buckets should have event notifications enabled
8+
#checkov:skip=CKV_AWS_145:Ensure that S3 buckets are encrypted with KMS by default
9+
#checkov:skip=CKV_AWS_144:Ensure that S3 bucket has cross-region replication enabled
10+
11+
bucket = var.ansible_playbook_bucket_name
12+
}
13+
14+
resource "aws_s3_bucket_versioning" "ansible" {
15+
bucket = aws_s3_bucket.ansible.id
16+
versioning_configuration {
17+
status = "Enabled"
18+
}
19+
}
20+
21+
resource "aws_s3_bucket_server_side_encryption_configuration" "ansible" {
22+
bucket = aws_s3_bucket.ansible.id
23+
24+
rule {
25+
apply_server_side_encryption_by_default {
26+
sse_algorithm = "AES256"
27+
}
28+
}
29+
}
30+
31+
resource "aws_s3_bucket_ownership_controls" "ansible" {
32+
bucket = aws_s3_bucket.ansible.id
33+
rule {
34+
object_ownership = "BucketOwnerEnforced"
35+
}
36+
}
37+
38+
resource "aws_s3_bucket_acl" "ansible" {
39+
depends_on = [aws_s3_bucket_ownership_controls.ansible]
40+
41+
bucket = aws_s3_bucket.ansible.id
42+
acl = "private"
43+
}
44+
45+
resource "aws_s3_bucket_policy" "allow_access_from_ssm" {
46+
bucket = aws_s3_bucket.ansible.id
47+
policy = data.aws_iam_policy_document.allow_access_from_ssm.json
48+
}
49+
50+
data "aws_iam_policy_document" "allow_access_from_ssm" {
51+
statement {
52+
principals {
53+
type = "AWS"
54+
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${aws_iam_instance_profile.ctf.role}"]
55+
}
56+
57+
actions = [
58+
"s3:GetObject",
59+
"s3:ListBucket",
60+
]
61+
62+
resources = [
63+
aws_s3_bucket.ansible.arn,
64+
"${aws_s3_bucket.ansible.arn}/*",
65+
]
66+
}
67+
}

sg.tf

-26
Original file line numberDiff line numberDiff line change
@@ -85,29 +85,3 @@ resource "aws_security_group" "alb" {
8585
Name = "sg-ctf-alb"
8686
}
8787
}
88-
89-
resource "aws_security_group" "rds" {
90-
name = "CTF RDS Security Group"
91-
description = "CTF RDS Security Group"
92-
vpc_id = aws_vpc.ctf.id
93-
94-
ingress {
95-
description = "RDS from internal SG"
96-
from_port = 3306
97-
to_port = 3306
98-
protocol = "tcp"
99-
security_groups = [aws_security_group.ctf.id]
100-
}
101-
102-
egress {
103-
description = "Allow All Traffic Outbound"
104-
from_port = 0
105-
to_port = 0
106-
protocol = "-1"
107-
cidr_blocks = ["0.0.0.0/0"]
108-
}
109-
110-
tags = {
111-
Name = "sg-ctf-rds"
112-
}
113-
}

0 commit comments

Comments
 (0)