├── .gitattributes ├── AWS ├── provider.tf ├── route53.tf ├── ec2_redirectors.tf ├── vars.tf ├── outputs.tf ├── security_groups.tf ├── cloudfront.tf └── network.tf ├── lib ├── colours.py ├── parser.py ├── helpers.py ├── ssh.py ├── important.py ├── digitalocean │ └── builder.py ├── ascii.py └── aws │ └── builder.py ├── README.md ├── DigitalOcean └── do-terraform-dp-smtp.tf ├── .gitignore └── redreaper.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /AWS/provider.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | terraform { 5 | required_providers { 6 | aws = { 7 | source = "hashicorp/aws" 8 | version = "~> 5.1.0" 9 | } 10 | 11 | random = { 12 | source = "hashicorp/random" 13 | version = "3.7.2" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /lib/colours.py: -------------------------------------------------------------------------------- 1 | try: 2 | from colorama import Fore, Style 3 | except ImportError as e: 4 | raise Exception(e) 5 | 6 | def print_info(string): 7 | 8 | s = f"{Fore.BLUE}[*]{Style.RESET_ALL} {string}" 9 | 10 | print(s) 11 | 12 | def print_success(string): 13 | 14 | s = f"{Fore.GREEN}[+]{Style.RESET_ALL} {string}" 15 | 16 | print(s) 17 | 18 | def print_error(string): 19 | 20 | s = f"{Fore.RED}[-]{Style.RESET_ALL} {string}" 21 | 22 | print(s) 23 | 24 | def print_warning(string): 25 | 26 | s = f"{Fore.YELLOW}[!]{Style.RESET_ALL} {string}" 27 | 28 | print(s) -------------------------------------------------------------------------------- /AWS/route53.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | resource "aws_route53_zone" "r53hzone_%PROJECT_NAME%" { 5 | name = "%C2DOMAIN%" 6 | comment = "Created with RedReaper" 7 | } 8 | 9 | resource "aws_route53_record" "root_%PROJECT_NAME%" { 10 | 11 | zone_id = aws_route53_zone.r53hzone_%PROJECT_NAME%.zone_id 12 | allow_overwrite = true 13 | name = "%C2DOMAIN%" 14 | type = "A" 15 | ttl = 300 16 | #records = ["%C2IPADDRESS%"] 17 | records = ["${aws_instance.ec2_%PROJECT_NAME%.public_ip}"] 18 | 19 | depends_on = [ aws_route53_zone.r53hzone_%PROJECT_NAME% ] 20 | } -------------------------------------------------------------------------------- /lib/parser.py: -------------------------------------------------------------------------------- 1 | from lib.ascii import * 2 | from lib.helpers import * 3 | from lib.ssh import * 4 | # Import the builders 5 | from lib.aws.builder import * 6 | from lib.digitalocean.builder import * 7 | 8 | try: 9 | import argparse 10 | except ImportError: 11 | print("[-] Failed to import \"argparse\"") 12 | 13 | 14 | 15 | # Start the AWS builder 16 | AWSBuilder.build_aws( 17 | aws_subp.cidr, 18 | aws_subp.projectName, 19 | aws_subp.ssh_pubkey, 20 | aws_subp.c2domain, 21 | aws_subp.tf_file) -------------------------------------------------------------------------------- /lib/helpers.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from lib.colours import * 3 | 4 | class Helpers(): 5 | 6 | def __init__(self): 7 | folder = self.folder 8 | file = self.file 9 | 10 | def check_folder_exists(folder): 11 | if not isinstance(folder, str): 12 | sys.exit(-1) 13 | 14 | if os.path.exists(folder): 15 | return True 16 | else: 17 | return False 18 | 19 | def check_file_exists(file): 20 | if not isinstance(file, str): 21 | sys.exit(-1) 22 | 23 | try: 24 | with open(file, "r") as f: 25 | f.close() 26 | return True 27 | except FileNotFoundError: 28 | return False 29 | 30 | #print(Helpers.check_file_exists("colours.py")) # == True 31 | #print(Helpers.check_folder_exists("misc")) # == False -------------------------------------------------------------------------------- /lib/ssh.py: -------------------------------------------------------------------------------- 1 | import subprocess, shlex 2 | from lib.helpers import * 3 | 4 | class SSH: 5 | 6 | def __init__(self): 7 | key_name = self.key_name 8 | 9 | def gen_ssh_key(key_name): 10 | 11 | print_info(f"Generating SSH key - \"{key_name}\"") 12 | 13 | _cmd_ = f"ssh-keygen -f {key_name}" 14 | 15 | try: 16 | subprocess.run(shlex.split(_cmd_, posix=True), shell=False) 17 | except Exception as e: 18 | raise Exception(e) 19 | 20 | print_success("Successfully generated SSH key") 21 | 22 | if Helpers.check_file_exists(key_name) == False: 23 | print_error("File does not exist") 24 | sys.exit(-1) 25 | 26 | # After generation of SSH key, read the pub key 27 | with open(key_name+".pub", "r") as sshkey: 28 | content = sshkey.read() 29 | return content.rstrip("\n") 30 | -------------------------------------------------------------------------------- /lib/important.py: -------------------------------------------------------------------------------- 1 | # Important info for user after the script generates the Terraform files 2 | 3 | try: 4 | from termcolor import colored 5 | from colorama import Fore, Style 6 | except ImportError: 7 | raise Exception("Failed to import \"termcolor\" library") 8 | 9 | def print_important_msg(): 10 | 11 | msg = ''' 12 | Don't forget to go to your domain registrar and 13 | fix the SOA/NS records to point to Route53. 14 | 15 | Some additional minor setup is required for the CDN 16 | such as: 17 | - certificate 18 | - origin 19 | - alternate domain names = [.com ,www..com] 20 | 21 | or others. Remember to double check the setup after deployment. 22 | 23 | May your project go smoothly <3 24 | ''' 25 | 26 | symb = f"\n{Fore.LIGHTYELLOW_EX}[??] Important Information{Style.RESET_ALL}" 27 | msg_formated = colored(msg, "light_cyan", attrs=["bold","blink"]) 28 | 29 | s = f"{symb} {msg_formated}" 30 | 31 | print(s) -------------------------------------------------------------------------------- /AWS/ec2_redirectors.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | ### Add a key pair for the instance ### 5 | ######################################### 6 | resource "aws_key_pair" "%INSTANCE_NAME%-key" { 7 | key_name = var.ec2_instance_key 8 | public_key = "%SSH_PUB_KEY%" 9 | } 10 | 11 | # Create a redirector instance which can be either Apache or Nginx 12 | resource "aws_instance" "ec2_%INSTANCE_NAME%" { 13 | ami = "ami-053b0d53c279acc90" # Ubuntu 22.04 LTS Canonical, Ubuntu, 22.04 LTS, amd64 jammy image build on 2023-05-16 ami-053b0d53c279acc90 14 | instance_type = "t2.micro" # Free Tier instance type 15 | key_name = var.ec2_instance_key # SSH key 16 | vpc_security_group_ids = ["${aws_security_group.sg_%INSTANCE_NAME%.id}"] # Security group for redirectors 17 | subnet_id = aws_subnet.subnet_%INSTANCE_NAME%.id # Select the subnet to associate with 18 | 19 | root_block_device { 20 | volume_size = 30 # Give it 30 GB of disk size just in case (max for free tier) 21 | } 22 | 23 | tags = { 24 | Name = "${var.ec2_instance_name}" 25 | project = "%INSTANCE_NAME%" 26 | Comment = "Created with RedReaper" 27 | } 28 | } -------------------------------------------------------------------------------- /AWS/vars.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | provider "aws" { 5 | region = "eu-west-2" 6 | # access_key = "" # AWS_ACCESS_KEY entry if you want to hardcode instead of env var 7 | # secret_key = "" # AWS_SECRET_KEY entry if you want to hardcode instead of env var 8 | } 9 | 10 | resource "random_id" "rid_networking" { 11 | byte_length = 6 12 | } 13 | 14 | # EC2 Instance Name 15 | variable "ec2_instance_name" { 16 | default = "ec2_%INSTANCE_NAME%" 17 | } 18 | 19 | # EC2 Instance SSH Key Pair Name (suffix: -key) 20 | variable "ec2_instance_key" { 21 | default = "%INSTANCE_NAME%-key" 22 | } 23 | 24 | # CIDR Of The Redirectors' subnet 25 | variable "vpc_cidr_block" { 26 | default = "%CIDR_BLOCK%" 27 | } 28 | 29 | # Redirectors' VPC Name 30 | variable "vpc_name" { 31 | default = "vpc_%INSTANCE_NAME%" 32 | } 33 | 34 | # Redirectors' Subnet Name 35 | variable "subnet_name" { 36 | default = "subnet_%INSTANCE_NAME%" 37 | } 38 | 39 | # Redirectors' Security Group Name 40 | variable "secgrp_name" { 41 | default = "sg_%INSTANCE_NAME%" 42 | } 43 | 44 | # Redirectors' Internet Gateway Name 45 | variable "internetgateway_name" { 46 | default = "ig_%INSTANCE_NAME%" 47 | } 48 | 49 | # Redirectors' Route Table Name 50 | variable "routetable_name" { 51 | default = "rt_%INSTANCE_NAME%" 52 | } -------------------------------------------------------------------------------- /AWS/outputs.tf: -------------------------------------------------------------------------------- 1 | ### Show some results that would be useful after creation of resources ### 2 | ############################################################################ 3 | 4 | # Show instance name 5 | output "InstanceName" { 6 | description = "EC2 Instance name" 7 | value = var.ec2_instance_name 8 | 9 | depends_on = [ aws_instance.ec2_%INSTANCE_NAME% ] 10 | } 11 | 12 | # Show instance public IP address 13 | output "InstanceIPAddress" { 14 | value = aws_instance.ec2_%INSTANCE_NAME%.private_ip 15 | description = "The public IP address of the main server instance." 16 | 17 | depends_on = [ 18 | # Security group rule must be created before this IP address could 19 | # actually be used, otherwise the services will be unreachable. 20 | aws_instance.ec2_%INSTANCE_NAME% 21 | ] 22 | } 23 | 24 | output "CDN_DomainName_%INSTANCE_NAME%" { 25 | description = "The domain of the CDN %INSTANCE_NAME%" 26 | value = "${aws_cloudfront_distribution.cdn_%INSTANCE_NAME%.domain_name}" 27 | depends_on = [ aws_cloudfront_distribution.cdn_%INSTANCE_NAME% ] 28 | } 29 | 30 | output "R53Zone_NS_%INSTANCE_NAME%" { 31 | description = "The Route 53 Zone Primary Name Server %INSTANCE_NAME%" 32 | value = "${aws_route53_zone.r53hzone_%INSTANCE_NAME%.name_servers}" 33 | depends_on = [ aws_route53_zone.r53hzone_%INSTANCE_NAME% ] 34 | } 35 | 36 | -------------------------------------------------------------------------------- /AWS/security_groups.tf: -------------------------------------------------------------------------------- 1 | ### Create a security group and allow SSH, HTTP and HTTPS for inbound ### 2 | ############################################################################ 3 | resource "aws_security_group" "sg_%INSTANCE_NAME%" { 4 | name = var.secgrp_name 5 | vpc_id = aws_vpc.vpc_%INSTANCE_NAME%.id 6 | revoke_rules_on_delete = true # Delete rules upon sec group deletion 7 | 8 | # Allow inbound from anywhere for HTTP 9 | ingress { 10 | from_port = 80 11 | to_port = 80 12 | protocol = "tcp" 13 | cidr_blocks = ["0.0.0.0/0"] 14 | } 15 | 16 | # Allow inbound from anywhere for HTTPS 17 | ingress { 18 | from_port = 443 19 | to_port = 443 20 | protocol = "tcp" 21 | cidr_blocks = ["0.0.0.0/0"] 22 | } 23 | 24 | # Allow inbound from anywhere for SSH 25 | ingress { 26 | from_port = 22 27 | to_port = 22 28 | protocol = "tcp" 29 | cidr_blocks = ["0.0.0.0/0"] 30 | } 31 | 32 | # Allow outbound to anywhere 33 | egress { 34 | from_port = 0 35 | to_port = 0 36 | protocol = "-1" 37 | cidr_blocks = ["0.0.0.0/0"] 38 | } 39 | 40 | # Make sure the security group is first created 41 | # before being deleted (might not be necessary) 42 | lifecycle { 43 | create_before_destroy = true 44 | } 45 | 46 | tags = { 47 | Name = "${var.secgrp_name}" 48 | project = "%INSTANCE_NAME%" 49 | comment = "Created with RedReaper" 50 | } 51 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The tool is under development !! 2 | # redreaper 3 | A terraform based project to automatically create a cloud environment for red team or phishing engagements 4 | 5 | # Description 6 | This project was created to understand better the usage of terraform and the various different modules for cloud environments such as Digital Ocean, AWS and Azure. The project aims to automate the creation of red team and/or phishing infrastructure in various cloud providers such as those aforementioned. 7 | 8 | Redreaper uses python3 to take some information regarding the infrastructure that will be deployed and uses terraform templates stored in each provider's folder. After the generation of the final terraform files the user can then run terraform and deploy the environment. 9 | 10 | # Credits 11 | This tool was insipired by the various other tools that already exist out there. Some of which are mentioned below: 12 | - https://github.com/SecuraBV/RedWizard 13 | - https://github.com/guidepointsecurity/RedCommander 14 | - https://github.com/mantvydasb/Red-Team-Infrastructure-Automation 15 | 16 | # Disclaimer 17 | The author of this does not take any responsibility of how this tool is used. This was created for educational purposes only. Responsibility and usage of this tool fall strictly on the user's side. 18 | 19 | 20 | # Legend 21 | 22 | * `ec2_instance_name = "ec2_%INSTANCE_NAME%"` # EC2 Instance Name 23 | * `ec2_instance_key = "%INSTANCE_NAME%-key"` # EC2 Instance SSH Key Pair Name (suffix: -key) 24 | * `vpc_cidr_block = "%CIDR_BLOCK%"` # CIDR Of The Redirectors' subnet 25 | * `vpc_name = "vpc_%INSTANCE_NAME%"` # Redirectors' VPC Name 26 | * `subnet_name = "subnet_%INSTANCE_NAME%"` # Redirectors' Subnet Name 27 | * `secgrp_name = "sg_%INSTANCE_NAME%"` # Redirectors' Security Group Name 28 | * `internetgateway_name = "ig_%INSTANCE_NAME%"` # Redirectors' Internet Gateway Name 29 | * `routetable_name = "rt_%INSTANCE_NAME%"` # Redirectors' Route Table Name -------------------------------------------------------------------------------- /lib/digitalocean/builder.py: -------------------------------------------------------------------------------- 1 | from lib.helpers import * 2 | 3 | class DOBuilder: 4 | def __init__(self): 5 | projectName = self.projectName 6 | ssh_pubkey = self.ssh_pubkey 7 | 8 | def build_digitalocean(projectName, ssh_pubkey): 9 | 10 | # https://stackoverflow.com/a/5475224 11 | SCRIPT_RELPATH = sys.path[0] 12 | 13 | # DigitalOcean allows only the following characters in names 14 | # -> (a-z, A-Z, 0-9, . and -) 15 | if "_" in projectName: 16 | projectName = str(projectName).replace("_", "-") 17 | 18 | if Helpers.check_folder_exists(f"{SCRIPT_RELPATH}/DigitalOcean/output") == False: 19 | os.mkdir(f"{SCRIPT_RELPATH}/DigitalOcean/output") 20 | else: 21 | pass 22 | 23 | def gen_smtp_dp(projectName, ssh_pubkey): 24 | # Create a new file in root of the project folder 25 | with open(f"{SCRIPT_RELPATH}/DigitalOcean/output/do-terraform-dp-{projectName}-smtp.tf", "a+") as TF_NEW: 26 | 27 | # Open the template terraform file and replace values 28 | with open(f"{SCRIPT_RELPATH}/DigitalOcean/do-terraform-dp-smtp.tf", "r") as TF_ORIG: 29 | 30 | replaced_projectName = TF_ORIG.read().replace("%PROJECT_NAME%", projectName) # replace DP name with project name 31 | replaced_ssh = replaced_projectName.replace("%SSH_PUB_KEY%", ssh_pubkey) # from second replace (projectName), replace the SSH Public Key 32 | 33 | final = replaced_ssh # store final and write to the new file 34 | 35 | if TF_NEW.write(final): 36 | return True 37 | else: 38 | return False 39 | try: 40 | if gen_smtp_dp(projectName, ssh_pubkey) == True: 41 | print_success(f"Successfully wrote DigitalOcean SMTP Terraform file \"./DigitalOcean/output/do-terraform-dp-{projectName}-smtp.tf\"") 42 | 43 | return True 44 | except Exception as e: 45 | raise Exception(e) -------------------------------------------------------------------------------- /AWS/cloudfront.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | resource "aws_cloudfront_distribution" "cdn_%PROJECT_NAME%" { 5 | # Aliases arent required at this point. 6 | # If including aliases, it will break the operation of terraform. 7 | # This is because an alias requires a custom certificate and this will be implemented 8 | # on a later bases. For now manual editing of the CDN is required. 9 | # 10 | # aliases = ["${var.c2domain}", "www.${var.c2domain}"] 11 | 12 | retain_on_delete = false # When enabled, manual deletion of distribution is required 13 | wait_for_deployment = true # Terraform waits for status change from "InProgress" to "Deployed" 14 | 15 | http_version = "http2" 16 | enabled = true 17 | is_ipv6_enabled = false 18 | 19 | origin { 20 | 21 | domain_name = "%C2DOMAIN%" 22 | origin_id = "%C2DOMAIN%" 23 | 24 | custom_origin_config { 25 | origin_protocol_policy = "https-only" 26 | origin_ssl_protocols = [ "TLSv1", "TLSv1.1", "TLSv1.2" ] 27 | https_port = 443 28 | http_port = 80 29 | } 30 | } 31 | 32 | default_cache_behavior { 33 | allowed_methods = [ "HEAD", "DELETE", "POST", "GET", "OPTIONS", "PUT", "PATCH" ] 34 | min_ttl = 0 35 | max_ttl = 31536000 36 | default_ttl = 86400 37 | target_origin_id = "%C2DOMAIN%" 38 | cached_methods = [ "HEAD", "GET" ] 39 | viewer_protocol_policy = "allow-all" 40 | 41 | forwarded_values { 42 | query_string = true 43 | 44 | cookies { 45 | forward = "all" 46 | } 47 | } 48 | } 49 | 50 | restrictions { 51 | geo_restriction { 52 | restriction_type = "blacklist" 53 | locations = [ 54 | # Threat index obtained from https://www.visionofhumanity.org/maps/global-terrorism-index/#/ 55 | # Country codes obtained from https://www.iso.org/obp/ui/#search 56 | "AF", # Afghanistan 57 | "CN", # China 58 | "RU", # Russia 59 | "IL", # Israel 60 | "BF", # Burkina Faso 61 | "ML", # Mali 62 | "NG", # Nigeria 63 | "CG", # Congo 64 | "SY", # Syria 65 | "PK", # Pakistan 66 | "CO", # Colombia 67 | ] 68 | } 69 | } 70 | 71 | viewer_certificate { cloudfront_default_certificate = true } 72 | 73 | tags = { 74 | project = "%PROJECT_NAME%" 75 | comment = "Created with RedReaper" 76 | } 77 | 78 | depends_on = [ aws_route53_record.root_%PROJECT_NAME% ] 79 | } -------------------------------------------------------------------------------- /AWS/network.tf: -------------------------------------------------------------------------------- 1 | ### Create a dedicated VPC for the redirectors ### 2 | #################################################### 3 | resource "aws_vpc" "vpc_%INSTANCE_NAME%" { 4 | cidr_block = var.vpc_cidr_block 5 | enable_dns_support = true # Enable DNS support 6 | enable_dns_hostnames = true # Enable DNS hostname support 7 | 8 | tags = { 9 | Name = "${var.vpc_name}" 10 | project = "%INSTANCE_NAME%" 11 | comment = "Created with RedReaper" 12 | } 13 | } 14 | 15 | ### Create a subnet for the redirectors to reside in ### 16 | ######################################################### 17 | resource "aws_subnet" "subnet_%INSTANCE_NAME%" { 18 | cidr_block = var.vpc_cidr_block # CIDR block for the subnet (can be anything) 19 | map_public_ip_on_launch = true 20 | vpc_id = aws_vpc.vpc_%INSTANCE_NAME%.id 21 | tags = { 22 | Name = "${var.subnet_name}" 23 | project = "%INSTANCE_NAME%" 24 | comment = "Created with RedReaper" 25 | } 26 | } 27 | 28 | ### Create a route table in the VPC of the redirectors ### 29 | ############################################################ 30 | resource "aws_route_table" "rtb_%INSTANCE_NAME%" { 31 | #subnet_id = aws_subnet.subnet_redirectors.id 32 | vpc_id = aws_vpc.vpc_%INSTANCE_NAME%.id 33 | tags = { 34 | Name = "${var.routetable_name} rtb_%INSTANCE_NAME%" 35 | project = "%INSTANCE_NAME%" 36 | comment = "Created with RedReaper" 37 | } 38 | } 39 | 40 | ### Create a route to allow internet access ### 41 | ################################################# 42 | resource "aws_route" "rt_%INSTANCE_NAME%" { 43 | route_table_id = aws_route_table.rtb_%INSTANCE_NAME%.id 44 | gateway_id = aws_internet_gateway.ig_%INSTANCE_NAME%.id 45 | destination_cidr_block = "0.0.0.0/0" 46 | } 47 | 48 | ### Associate the route table with the redirector's subnet and rules ### 49 | ############################################################################ 50 | resource "aws_route_table_association" "rta_%INSTANCE_NAME%" { 51 | subnet_id = aws_subnet.subnet_%INSTANCE_NAME%.id 52 | route_table_id = aws_route_table.rtb_%INSTANCE_NAME%.id 53 | } 54 | 55 | ### Create an internet gateway to allow the instance to have internet ### 56 | ############################################################################ 57 | resource "aws_internet_gateway" "ig_%INSTANCE_NAME%" { 58 | vpc_id = aws_vpc.vpc_%INSTANCE_NAME%.id 59 | tags = { 60 | Name = "${var.internetgateway_name}" 61 | project = "%INSTANCE_NAME%" 62 | comment = "Created with RedReaper" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /DigitalOcean/do-terraform-dp-smtp.tf: -------------------------------------------------------------------------------- 1 | # Author: Kr0ff 2 | # Version: 1.0 3 | 4 | terraform { 5 | required_providers { 6 | digitalocean = { 7 | source = "digitalocean/digitalocean" 8 | version = "~> 2.0" 9 | } 10 | } 11 | } 12 | 13 | provider "digitalocean" { 14 | token = var.do_token 15 | } 16 | 17 | variable "do_token" { 18 | description = "Digital Ocean API Token" 19 | nullable = false 20 | } 21 | 22 | # Project Name = %PROJECT_NAME% 23 | # Droplet Instance = %INSTANCE_NAME% 24 | # SSH pubkey = %SSH_PUBKEY% 25 | resource "digitalocean_ssh_key" "sshkey_%PROJECT_NAME%" { 26 | name = "ssh-%PROJECT_NAME%" 27 | public_key = "%SSH_PUB_KEY%" 28 | } 29 | 30 | # s-1vcpu-2gb 31 | # lon1 32 | # ubuntu-22-04-x64 33 | # Create a new Web Droplet in the nyc2 region 34 | resource "digitalocean_droplet" "dp_%PROJECT_NAME%" { 35 | image = "ubuntu-22-04-x64" 36 | name = "dp-smtp01-%PROJECT_NAME%" 37 | region = "lon1" 38 | size = "s-1vcpu-2gb" 39 | ssh_keys = [digitalocean_ssh_key.sshkey_%PROJECT_NAME%.fingerprint] 40 | } 41 | 42 | # Project Name = %PROJECT_NAME% 43 | resource "digitalocean_project" "%PROJECT_NAME%" { 44 | name = "%PROJECT_NAME%" 45 | description = "Created by RedReaper" 46 | purpose = "Assessment_%PROJECT_NAME%" 47 | environment = "Production" 48 | resources = [digitalocean_droplet.dp_%PROJECT_NAME%.urn] 49 | 50 | depends_on = [ digitalocean_droplet.dp_%PROJECT_NAME% ] 51 | } 52 | 53 | # Project Name = %PROJECT_NAME% 54 | # Droplet Instance = %INSTANCE_NAME% 55 | resource "digitalocean_firewall" "fw_%PROJECT_NAME%" { 56 | name = "fw-%PROJECT_NAME%" 57 | 58 | droplet_ids = [digitalocean_droplet.dp_%PROJECT_NAME%.id] 59 | 60 | inbound_rule { 61 | protocol = "tcp" 62 | port_range = "22" 63 | source_addresses = ["0.0.0.0/0", "::/0"] 64 | } 65 | 66 | inbound_rule { 67 | protocol = "tcp" 68 | port_range = "25" 69 | source_addresses = ["0.0.0.0/0", "::/0"] 70 | } 71 | 72 | inbound_rule { 73 | protocol = "tcp" 74 | port_range = "80" 75 | source_addresses = ["0.0.0.0/0", "::/0"] 76 | } 77 | 78 | inbound_rule { 79 | protocol = "tcp" 80 | port_range = "443" 81 | source_addresses = ["0.0.0.0/0", "::/0"] 82 | } 83 | 84 | inbound_rule { 85 | protocol = "icmp" 86 | source_addresses = ["0.0.0.0/0", "::/0"] 87 | } 88 | 89 | outbound_rule { 90 | protocol = "icmp" 91 | destination_addresses = ["0.0.0.0/0", "::/0"] 92 | } 93 | 94 | outbound_rule { 95 | protocol = "tcp" 96 | port_range = "0" 97 | destination_addresses = ["0.0.0.0/0", "::/0"] 98 | } 99 | 100 | depends_on = [ digitalocean_droplet.dp_%PROJECT_NAME% ] 101 | } 102 | 103 | output "Droplet_IPV4" { 104 | value = digitalocean_droplet.dp_%PROJECT_NAME%.ipv4_address 105 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | crash.*.log 11 | 12 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 13 | # password, private keys, and other secrets. These should not be part of version 14 | # control as they are data points which are potentially sensitive and subject 15 | # to change depending on the environment. 16 | # 17 | *.tfvars 18 | 19 | # Ignore override files as they are usually used to override resources locally and so 20 | # are not checked in 21 | override.tf 22 | override.tf.json 23 | *_override.tf 24 | *_override.tf.json 25 | 26 | # Include override files you do wish to add to version control using negated pattern 27 | # 28 | # !example_override.tf 29 | 30 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 31 | # example: *tfplan* 32 | 33 | # Ignore CLI configuration files 34 | .terraformrc 35 | terraform.rc 36 | 37 | # Byte-compiled / optimized / DLL files 38 | __pycache__/ 39 | *.py[cod] 40 | *$py.class 41 | 42 | # C extensions 43 | *.so 44 | 45 | # Distribution / packaging 46 | .Python 47 | build/ 48 | develop-eggs/ 49 | dist/ 50 | downloads/ 51 | eggs/ 52 | .eggs/ 53 | lib64/ 54 | parts/ 55 | sdist/ 56 | var/ 57 | wheels/ 58 | share/python-wheels/ 59 | *.egg-info/ 60 | .installed.cfg 61 | *.egg 62 | MANIFEST 63 | 64 | # PyInstaller 65 | # Usually these files are written by a python script from a template 66 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 67 | *.manifest 68 | *.spec 69 | 70 | # Installer logs 71 | pip-log.txt 72 | pip-delete-this-directory.txt 73 | 74 | # Unit test / coverage reports 75 | htmlcov/ 76 | .tox/ 77 | .nox/ 78 | .coverage 79 | .coverage.* 80 | .cache 81 | nosetests.xml 82 | coverage.xml 83 | *.cover 84 | *.py,cover 85 | .hypothesis/ 86 | .pytest_cache/ 87 | cover/ 88 | 89 | # Translations 90 | *.mo 91 | *.pot 92 | 93 | # Django stuff: 94 | *.log 95 | local_settings.py 96 | db.sqlite3 97 | db.sqlite3-journal 98 | 99 | # Flask stuff: 100 | instance/ 101 | .webassets-cache 102 | 103 | # Scrapy stuff: 104 | .scrapy 105 | 106 | # Sphinx documentation 107 | docs/_build/ 108 | 109 | # PyBuilder 110 | .pybuilder/ 111 | target/ 112 | 113 | # Jupyter Notebook 114 | .ipynb_checkpoints 115 | 116 | # IPython 117 | profile_default/ 118 | ipython_config.py 119 | 120 | # pyenv 121 | # For a library or package, you might want to ignore these files since the code is 122 | # intended to run in multiple environments; otherwise, check them in: 123 | # .python-version 124 | 125 | # pipenv 126 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 127 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 128 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 129 | # install all needed dependencies. 130 | #Pipfile.lock 131 | 132 | # poetry 133 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 134 | # This is especially recommended for binary packages to ensure reproducibility, and is more 135 | # commonly ignored for libraries. 136 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 137 | #poetry.lock 138 | 139 | # pdm 140 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 141 | #pdm.lock 142 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 143 | # in version control. 144 | # https://pdm.fming.dev/#use-with-ide 145 | .pdm.toml 146 | 147 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 148 | __pypackages__/ 149 | 150 | # Celery stuff 151 | celerybeat-schedule 152 | celerybeat.pid 153 | 154 | # SageMath parsed files 155 | *.sage.py 156 | 157 | # Environments 158 | .env 159 | .venv 160 | env/ 161 | venv/ 162 | ENV/ 163 | env.bak/ 164 | venv.bak/ 165 | 166 | # Spyder project settings 167 | .spyderproject 168 | .spyproject 169 | 170 | # Rope project settings 171 | .ropeproject 172 | 173 | # mkdocs documentation 174 | /site 175 | 176 | # mypy 177 | .mypy_cache/ 178 | .dmypy.json 179 | dmypy.json 180 | 181 | # Pyre type checker 182 | .pyre/ 183 | 184 | # pytype static type analyzer 185 | .pytype/ 186 | 187 | # Cython debug symbols 188 | cython_debug/ 189 | 190 | # PyCharm 191 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 192 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 193 | # and can be added to the global gitignore or merged into this file. For a more nuclear 194 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 195 | #.idea/ 196 | .DS_Store 197 | -------------------------------------------------------------------------------- /redreaper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # __version__: {ver} 4 | # __author__: Kr0ff 5 | 6 | import sys 7 | 8 | from lib.ascii import * 9 | from lib.colours import * 10 | from lib.helpers import * 11 | from lib.ssh import * 12 | 13 | from lib.important import * 14 | 15 | # BUILDERS 16 | from lib.aws.builder import * 17 | from lib.digitalocean.builder import * 18 | 19 | try: 20 | import argparse 21 | except ImportError as e: 22 | raise Exception(e) 23 | 24 | ver = 0.3 25 | 26 | # AWS module to build the AWS terraform templates 27 | def aws( 28 | cidr, 29 | projectName, 30 | ssh_pubkey, 31 | c2domain): 32 | 33 | # Generate the SSH key for the EC2 instance 34 | _pubkey = SSH.gen_ssh_key(ssh_pubkey) 35 | 36 | #print(_pubkey) 37 | 38 | if AWSBuilder.build_aws( 39 | cidr, 40 | projectName, 41 | _pubkey, 42 | c2domain, 43 | ) == True: 44 | 45 | print_important_msg() 46 | 47 | # Digital Ocean module to build the Digital Ocean terraform templates 48 | def digitalocean(projectName, ssh_pubkey): 49 | 50 | # Generate the SSH key for the EC2 instance 51 | _pubkey = SSH.gen_ssh_key(ssh_pubkey) 52 | 53 | #print(_pubkey) 54 | 55 | DOBuilder.build_digitalocean(projectName, _pubkey) 56 | 57 | def argparser(selection=None): 58 | 59 | # Print ASCII cos its cool :) 60 | print(printAscii()) 61 | 62 | parser = argparse.ArgumentParser(description='redreaper - A terraform script builder for cloud deployement of red team and phishing environments') 63 | 64 | subparsers = parser.add_subparsers(help="RedReaper Modules", dest="module") 65 | 66 | aws_subp = subparsers.add_parser("aws", help="AWS Submodule") 67 | aws_subp.add_argument("-p", 68 | "--projectname", 69 | help="Name of the project to use (Example: Project_Carnivore)", 70 | required=True 71 | ) 72 | aws_subp.add_argument("-c", 73 | "--cidr", 74 | help="CIDR block for the subnet (Example: 192.168.100.0/24)", 75 | required=True 76 | ) 77 | aws_subp.add_argument("-d", 78 | "--c2domain", 79 | help="Domain name for the C2 instance to use (Example: secretoperation.com)", 80 | required=True 81 | ) 82 | aws_subp.add_argument("-s", 83 | "--sshkey", 84 | help="Name of the SSH key that will be used for the EC2 instance", 85 | required=True 86 | ) 87 | 88 | digitalocean_subp = subparsers.add_parser("do", help="DigitalOcean Submodule") 89 | digitalocean_subp.add_argument("-p", 90 | "--projectname", 91 | help="Name of the project to use (Example: Project_Carnivore)", 92 | required=True 93 | ) 94 | digitalocean_subp.add_argument("-s", 95 | "--sshkey", 96 | help="Name of the SSH key that will be used for the EC2 instance", 97 | required=True 98 | ) 99 | 100 | parser.add_argument("-v", "--version", help="Get RedReaper version", required=False, action="store_true") 101 | 102 | # Show help menu if no arguments provided 103 | args = parser.parse_args(selection) 104 | 105 | if args.module == "aws": 106 | print_info("==== AWS INFO ====") 107 | print(f"\t- Project Name: {args.projectname}") 108 | print(f"\t- CIDR: {args.cidr}") 109 | print(f"\t- SSH Key Name: {args.sshkey}") 110 | print(f"\t- C2 Domain Name: {args.c2domain}") 111 | #print(f"\t- Template File: {aws_subp.template}") 112 | 113 | verify = input("\nIs everything correct [N/y]: ") 114 | if verify == "" or verify == "N" or verify == 'No' or verify == "n" or verify == "no": 115 | sys.exit(-3) 116 | elif verify == "Y" or verify == "Yes" or verify == "y" or verify == "yes": 117 | pass 118 | else: 119 | print_error("Input was invalid") 120 | sys.exit(-4) 121 | 122 | aws( 123 | args.cidr, 124 | args.projectname, 125 | args.sshkey, 126 | args.c2domain, 127 | ) 128 | 129 | if args.module == "do": 130 | print_info("==== DIGITALOCEAN INFO ====") 131 | print(f"\t- Project Name: {args.projectname}") 132 | print(f"\t- SSH Key Name: {args.sshkey}") 133 | 134 | verify = input("\nIs everything correct [N/y]: ") 135 | if verify == "" or verify == "N" or verify == 'No' or verify == "n" or verify == "no": 136 | sys.exit(-3) 137 | elif verify == "Y" or verify == "Yes" or verify == "y" or verify == "yes": 138 | pass 139 | else: 140 | print_error("Input was invalid") 141 | sys.exit(-4) 142 | 143 | digitalocean(args.projectname, args.sshkey) 144 | 145 | if args.version: 146 | print_info(f"RedReaper version {ver}") 147 | 148 | if __name__ == "__main__": 149 | 150 | try: 151 | argparser() 152 | except KeyboardInterrupt as e: 153 | print_error("User Interrupted Operation") 154 | sys.exit(-2) 155 | -------------------------------------------------------------------------------- /lib/ascii.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | _ASCII1_ = ''' 4 | 5 | __ 6 | .----.-----.--| .----.-----.---.-.-----.-----.----. 7 | | _| -__| _ | _| -__| _ | _ | -__| _| 8 | |__| |_____|_____|__| |_____|___._| __|_____|__| 9 | |__| 10 | 11 | ''' 12 | 13 | _ASCII2_ = ''' 14 | 15 | _ 16 | ___ ___ _| |___ ___ ___ ___ ___ ___ 17 | | _| -_| . | _| -_| .'| . | -_| _| 18 | |_| |___|___|_| |___|__,| _|___|_| 19 | |_| 20 | 21 | ''' 22 | 23 | _ASCII3_ = ''' 24 | 25 | .___ 26 | _______ ____ __| _/______ ____ _____ ______ ___________ 27 | \_ __ \_/ __ \ / __ |\_ __ \_/ __ \\__ \ \____ \_/ __ \_ __ \ 28 | | | \/\ ___// /_/ | | | \/\ ___/ / __ \| |_> > ___/| | \/ 29 | |__| \___ >____ | |__| \___ >____ / __/ \___ >__| 30 | \/ \/ \/ \/|__| \/ 31 | 32 | ''' 33 | 34 | _ASCII4_ = ''' 35 | 36 | 37 | |\ 38 | \\ _ 39 | ,._-_ _-_ / \\ ,._-_ _-_ < \, -_-_ _-_ ,._-_ 40 | || || \\ || || || || \\ /-|| || \\ || \\ || 41 | || ||/ || || || ||/ (( || || || ||/ || 42 | \\, \\,/ \\/ \\, \\,/ \/\\ ||-' \\,/ \\, 43 | |/ 44 | ' 45 | 46 | ''' 47 | 48 | _ASCII5_ = ''' 49 | 50 | __ 51 | /\ \ 52 | _ __ __ \_\ \ _ __ __ __ _____ __ _ __ 53 | /\`'__\/'__`\ /'_` \/\`'__\/'__`\ /'__`\ /\ '__`\ /'__`\/\`'__\ 54 | \ \ \//\ __//\ \L\ \ \ \//\ __//\ \L\.\_\ \ \L\ \/\ __/\ \ \/ 55 | \ \_\\ \____\ \___,_\ \_\\ \____\ \__/.\_\\ \ ,__/\ \____\\ \_\ 56 | \/_/ \/____/\/__,_ /\/_/ \/____/\/__/\/_/ \ \ \/ \/____/ \/_/ 57 | \ \_\ 58 | \/_/ 59 | 60 | ''' 61 | 62 | _ASCII6_ = ''' 63 | 64 | _____ ______ _____ _____ ______ ____ _____ ______ _____ 65 | | | | ___|| \ | | | ___|| \ | || ___|| | 66 | | \ | ___|| \| \ | ___|| \ | _|| ___|| \ 67 | |__|\__\|______||______/|__|\__\|______||__|\__\|___| |______||__|\__\ 68 | 69 | 70 | ''' 71 | 72 | _ASCII6_ = ''' 73 | 74 | 75 | @@@@@@@ @@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@ 76 | @@! @@@ @@! @@! @@@ @@! @@@ @@! @@! @@@ @@! @@@ @@! @@! @@@ 77 | @!@!!@! @!!!:! @!@ !@! @!@!!@! @!!!:! @!@!@!@! @!@@!@! @!!!:! @!@!!@! 78 | !!: :!! !!: !!: !!! !!: :!! !!: !!: !!! !!: !!: !!: :!! 79 | : : : : :: ::: :: : : : : : : :: ::: : : : : : :: ::: : : : 80 | 81 | 82 | ''' 83 | 84 | 85 | _ASCII7_ = ''' 86 | 87 | _________ 88 | __________________ /_________________ _____________________ 89 | __ ___/ _ \ __ /__ ___/ _ \ __ `/__ __ \ _ \_ ___/ 90 | _ / / __/ /_/ / _ / / __/ /_/ /__ /_/ / __/ / 91 | /_/ \___/\__,_/ /_/ \___/\__,_/ _ .___/\___//_/ 92 | /_/ 93 | 94 | ''' 95 | 96 | _ASCII8_ = ''' 97 | 98 | _ 99 | | | 100 | ____ ____ _ | | ____ ____ ____ ____ ____ ____ 101 | / ___) _ ) || |/ ___) _ ) _ | _ \ / _ )/ ___) 102 | | | ( (/ ( (_| | | ( (/ ( ( | | | | ( (/ /| | 103 | |_| \____)____|_| \____)_||_| ||_/ \____)_| 104 | |_| 105 | 106 | ''' 107 | 108 | _ASCII9_ = ''' 109 | 110 | ______ ______ _____ ______ ______ ______ ______ ______ ______ 111 | /\ == \ /\ ___\ /\ __-. /\ == \ /\ ___\ /\ __ \ /\ == \ /\ ___\ /\ == \ 112 | \ \ __< \ \ __\ \ \ \/\ \ \ \ __< \ \ __\ \ \ __ \ \ \ _-/ \ \ __\ \ \ __< 113 | \ \_\ \_\ \ \_____\ \ \____- \ \_\ \_\ \ \_____\ \ \_\ \_\ \ \_\ \ \_____\ \ \_\ \_\ 114 | \/_/ /_/ \/_____/ \/____/ \/_/ /_/ \/_____/ \/_/\/_/ \/_/ \/_____/ \/_/ /_/ 115 | 116 | 117 | ''' 118 | 119 | _ASCII10_ = ''' 120 | 121 | 122 | .______ ._______.______ .______ ._______.______ ._______ ._______.______ 123 | : __ \ : .____/:_ _ \ : __ \ : .____/: \ : ____ |: .____/: __ \ 124 | | \____|| : _/\ | | || \____|| : _/\ | . || : || : _/\ | \____| 125 | | : \ | / \| . | || : \ | / \| : || |___|| / \| : \ 126 | | |___\|_.: __/|. ____/ | |___\|_.: __/|___| ||___| |_.: __/| |___\ 127 | |___| :/ :/ |___| :/ |___| :/ |___| 128 | : 129 | 130 | ''' 131 | 132 | def printAscii(): 133 | 134 | arts = [_ASCII1_, _ASCII2_, _ASCII3_, _ASCII4_, _ASCII5_, _ASCII6_, _ASCII7_, _ASCII8_, _ASCII9_, _ASCII10_] 135 | 136 | return random.choice(arts) 137 | -------------------------------------------------------------------------------- /lib/aws/builder.py: -------------------------------------------------------------------------------- 1 | from lib.helpers import * 2 | 3 | class AWSBuilder: 4 | 5 | def __init__(self): 6 | cidr = self.cidr 7 | projectName = self.projectName 8 | ssh_pubkey = self.ssh_pubkey 9 | #tf_file = self.tf_file 10 | c2domain = self.c2domain 11 | c2ipaddress = self.c2ipaddress 12 | 13 | # AWS environment builder 14 | def build_aws( 15 | cidr, 16 | projectName, 17 | ssh_pubkey, 18 | c2domain, 19 | #tf_file 20 | ): 21 | 22 | # https://stackoverflow.com/a/5475224 23 | SCRIPT_RELPATH = sys.path[0] 24 | 25 | # Check if the output folder exists for AWS module 26 | if Helpers.check_folder_exists(f"{SCRIPT_RELPATH}/AWS/output") == False: 27 | 28 | # Make the output folder if it doesn't exist 29 | os.mkdir(f"{SCRIPT_RELPATH}/AWS/output") 30 | 31 | # Check if the project specific folder exists for AWS module 32 | if Helpers.check_folder_exists(f"{SCRIPT_RELPATH}/AWS/output/{projectName}") == False: 33 | 34 | # Make the project specific folder if it doesn't exist 35 | os.mkdir(f"{SCRIPT_RELPATH}/AWS/output/{projectName}") 36 | else: 37 | pass 38 | 39 | # if Helpers.check_file_exists(f"{tf_file}") == False: 40 | # print_error(f"Terraform file \"{tf_file}\" does not exist") 41 | # sys.exit(-1) 42 | 43 | #print_info(f"Using \"{tf_file}\" to create environment") 44 | 45 | # Prepare the EC2 redirector instance Terraform 46 | def gen_ec2(cidr, projectName, ssh_pubkey): 47 | 48 | # Create a new file in root of the project folder 49 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/ec2_redirectors.tf", "a+") as TF_NEW: 50 | 51 | # Open the template terraform file and replace values 52 | with open(f"{SCRIPT_RELPATH}/AWS/ec2_redirectors.tf", "r") as TF_ORIG: 53 | 54 | replaced_projectName = TF_ORIG.read().replace("%INSTANCE_NAME%", projectName) # replace EC2 name with project name 55 | replaced_cidr = replaced_projectName.replace("%CIDR_BLOCK%", cidr) # from first replace (EC2), replace the CIDR block 56 | replaced_ssh = replaced_cidr.replace("%SSH_PUB_KEY%", ssh_pubkey) # from second replace (CIDR), replace the SSH Public Key 57 | 58 | final = replaced_ssh # store final and write to the new file 59 | 60 | if TF_NEW.write(final): 61 | return True 62 | else: 63 | return False 64 | 65 | TF_ORIG.close() 66 | TF_NEW.close() 67 | 68 | 69 | # Prepare the EC2 networking Terraform 70 | def gen_network(projectName): 71 | 72 | # Create a new file in root of the project folder 73 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/network.tf", "a+") as TF_NEW: 74 | 75 | # Open the template terraform file and replace values 76 | with open(f"{SCRIPT_RELPATH}/AWS/network.tf", "r") as TF_ORIG: 77 | 78 | replaced_projectName = TF_ORIG.read().replace("%INSTANCE_NAME%", projectName) # replace EC2 name with project name 79 | final = replaced_projectName # store final and write to the new file 80 | 81 | if TF_NEW.write(final): 82 | return True 83 | else: 84 | return False 85 | 86 | TF_ORIG.close() 87 | TF_NEW.close() 88 | 89 | # Prepare the EC2 security groups Terraform 90 | def gen_secgroups(projectName): 91 | 92 | # Create a new file in root of the project folder 93 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/security_groups.tf", "a+") as TF_NEW: 94 | 95 | # Open the template terraform file and replace values 96 | with open(f"{SCRIPT_RELPATH}/AWS/security_groups.tf", "r") as TF_ORIG: 97 | 98 | replaced_projectName = TF_ORIG.read().replace("%INSTANCE_NAME%", projectName) # replace EC2 name with project name 99 | # replaced_cidr = replaced_projectName.replace("%CIDR_BLOCK%", cidr) # from first replace (EC2), replace the CIDR block 100 | final = replaced_projectName # store final and write to the new file 101 | 102 | if TF_NEW.write(final): 103 | return True 104 | else: 105 | return False 106 | 107 | TF_ORIG.close() 108 | TF_NEW.close() 109 | 110 | # Prepare the variable information Terraform 111 | def gen_vars(cidr, projectName): 112 | 113 | # Create a new file in root of the project folder 114 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/vars.tf", "a+") as TF_NEW: 115 | 116 | # Open the template terraform file and replace values 117 | with open(f"{SCRIPT_RELPATH}/AWS/vars.tf", "r") as TF_ORIG: 118 | 119 | replaced_projectName = TF_ORIG.read().replace("%INSTANCE_NAME%", projectName) # replace EC2 name with project name 120 | replaced_cidr = replaced_projectName.replace("%CIDR_BLOCK%", cidr) # from first replace (EC2), replace the CIDR block 121 | final = replaced_cidr # store final and write to the new file 122 | 123 | if TF_NEW.write(final): 124 | return True 125 | else: 126 | return False 127 | 128 | TF_ORIG.close() 129 | TF_NEW.close() 130 | 131 | # Prepare the output information Terraform 132 | def gen_outputs(projectName): 133 | 134 | # Create a new file in root of the project folder 135 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/outputs.tf", "a+") as TF_NEW: 136 | 137 | # Open the template terraform file and replace values 138 | with open(f"{SCRIPT_RELPATH}/AWS/outputs.tf", "r") as TF_ORIG: 139 | 140 | replaced_projectName = TF_ORIG.read().replace("%INSTANCE_NAME%", projectName) # replace EC2 name with project name 141 | final = replaced_projectName # store final and write to the new file 142 | 143 | if TF_NEW.write(final): 144 | return True 145 | else: 146 | return False 147 | 148 | TF_ORIG.close() 149 | TF_NEW.close() 150 | 151 | # Prepare the CDN Terraform instance for the project 152 | def gen_cdn(c2domain, projectName): 153 | 154 | # Create a new file in root of the project folder 155 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/cloudfront.tf", "a+") as TF_NEW: 156 | 157 | # Open the template terraform file and replace values 158 | with open(f"{SCRIPT_RELPATH}/AWS/cloudfront.tf", "r") as TF_ORIG: 159 | 160 | replaced_projectName = TF_ORIG.read().replace("%PROJECT_NAME%", projectName) # replace EC2 name with project name 161 | replaced_c2domain = replaced_projectName.replace("%C2DOMAIN%", c2domain) # from first replace (project name), replace the C2 domain 162 | 163 | final = replaced_c2domain # store final and write to the new file 164 | 165 | if TF_NEW.write(final): 166 | return True 167 | else: 168 | return False 169 | 170 | TF_ORIG.close() 171 | TF_NEW.close() 172 | 173 | # Prepare the Route53 Terraform hosted zone for the project 174 | def gen_r53(c2domain, projectName): 175 | 176 | # Create a new file in root of the project folder 177 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/route53.tf", "a+") as TF_NEW: 178 | 179 | # Open the template terraform file and replace values 180 | with open(f"{SCRIPT_RELPATH}/AWS/route53.tf", "r") as TF_ORIG: 181 | 182 | replaced_projectName = TF_ORIG.read().replace("%PROJECT_NAME%", projectName) # replace project name 183 | replaced_c2domain = replaced_projectName.replace("%C2DOMAIN%", c2domain) # from first replace (project name), replace the C2 domain 184 | 185 | final = replaced_c2domain # store final and write to the new file 186 | 187 | if TF_NEW.write(final): 188 | return True 189 | else: 190 | return False 191 | 192 | TF_ORIG.close() 193 | TF_NEW.close() 194 | 195 | try: 196 | if gen_ec2(cidr, projectName, ssh_pubkey) == True: 197 | print_success(f"Successfully wrote the EC2 Redirector Terraform file \"./AWS/output/{projectName}/ec2_redirectors.tf\"") 198 | 199 | if gen_network(projectName) == True: 200 | print_success(f"Successfully wrote the network Terraform file \"./AWS/output/{projectName}/network.tf\"") 201 | 202 | if gen_secgroups(projectName) == True: 203 | print_success(f"Successfully wrote the security groups Terraform file \"./AWS/output/{projectName}/security_groups.tf\"") 204 | 205 | if gen_vars(cidr, projectName) == True: 206 | print_success(f"Successfully wrote the variables Terraform file \"./AWS/output/{projectName}/vars.tf\"") 207 | 208 | if gen_outputs(projectName) == True: 209 | print_success(f"Successfully wrote the outputs Terraform file \"./AWS/output/{projectName}/outputs.tf\"") 210 | 211 | if gen_cdn(c2domain, projectName) == True: 212 | print_success(f"Successfully wrote CDN Terraform file \"./AWS/output/{projectName}/cloudfront.tf\"") 213 | 214 | if gen_r53(c2domain, projectName) == True: 215 | print_success(f"Successfully wrote Route53 Terraform file \"./AWS/output/{projectName}/route53.tf\"") 216 | 217 | # Just copy the provider Terraform to the output folder 218 | with open(f"{SCRIPT_RELPATH}/AWS/output/{projectName}/provider.tf", "a+") as TF_PROVIDER_NEW: 219 | with open(f"{SCRIPT_RELPATH}/AWS/provider.tf", "r") as TF_PROVIDER_ORIG: 220 | text = TF_PROVIDER_ORIG.read() 221 | 222 | TF_PROVIDER_NEW.write(text) 223 | 224 | TF_PROVIDER_ORIG.close() 225 | TF_PROVIDER_NEW.close() 226 | 227 | return True 228 | 229 | except Exception as e: 230 | raise Exception(e) --------------------------------------------------------------------------------