{"id":24743440,"url":"https://github.com/1nval1dctf/terraform-aws-ctfd","last_synced_at":"2025-10-10T12:30:44.753Z","repository":{"id":46782240,"uuid":"261088291","full_name":"1nval1dctf/terraform-aws-ctfd","owner":"1nval1dctf","description":"Terraform module for the salable deployment of CTFd on AWS","archived":false,"fork":false,"pushed_at":"2025-06-21T06:38:17.000Z","size":245,"stargazers_count":19,"open_issues_count":4,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-21T07:30:59.070Z","etag":null,"topics":["ctfd","terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/1nval1dctf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-04T05:28:13.000Z","updated_at":"2025-06-21T06:38:21.000Z","dependencies_parsed_at":"2024-02-12T09:06:06.383Z","dependency_job_id":"e37f7414-e26e-4549-8658-918176b3d173","html_url":"https://github.com/1nval1dctf/terraform-aws-ctfd","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/1nval1dctf/terraform-aws-ctfd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1nval1dctf%2Fterraform-aws-ctfd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1nval1dctf%2Fterraform-aws-ctfd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1nval1dctf%2Fterraform-aws-ctfd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1nval1dctf%2Fterraform-aws-ctfd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/1nval1dctf","download_url":"https://codeload.github.com/1nval1dctf/terraform-aws-ctfd/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1nval1dctf%2Fterraform-aws-ctfd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003901,"owners_count":26083641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ctfd","terraform"],"created_at":"2025-01-28T01:36:10.050Z","updated_at":"2025-10-10T12:30:44.391Z","avatar_url":"https://github.com/1nval1dctf.png","language":"HCL","funding_links":[],"categories":["White Zone Tooling"],"sub_categories":[],"readme":"\u003c!-- BEGIN_TF_DOCS --\u003e\n# CTFd AWS Terraform module\n\n![ci workflow](https://github.com/1nval1dctf/terraform-aws-ctfd/actions/workflows/ci.yml/badge.svg)\nTerraform module to deploy [CTFd](https://ctfd.io/) into scalable AWS infrastructure\n\nThis has been used in a moderately sized CTF \u003e 1000 participants and performed well with a setup similar to the example below, though you may want to scale out a little.\n\n## Design\n\nThe CTFd setup Looks something like this:\n\n```mermaid\nflowchart TB\n\n  subgraph \"Uploads\"\n    S3Uploads[S3]\n  end\n\n  subgraph \"Logs\"\n    S3Logs[S3]\n  end\n\n  subgraph \"RDS (mysql -  Serverless or Provisioned)\"\n    RDS[RDS autoscale]\n  end\n\n  subgraph \"ElasticCache (redis)\"\n    REDIS[REDIS] --\u003e ElasticCache1[Instance 1]\n    REDIS[REDIS] --\u003e ElasticCache[...]\n    REDIS[REDIS] --\u003e ElasticCacheN[Instance n]\n  end\n\n  LB[ALB] --\u003e Ingress\n\n  subgraph ECS[ECS]\n    Ingress --\u003e Service[CTFd service]\n    Service --\u003e Instance1[CTFd Instance 1]\n    Service --\u003e Instance[CTFd Instance ...]\n    Service --\u003e InstanceN[CTFd Instance n - HorizontalAutoScaling]\n    Instance1 --\u003e RDS[RDS]\n    Instance --\u003e RDS\n    InstanceN --\u003e RDS\n    Instance1 --\u003e REDIS[REDIS]\n    Instance --\u003e REDIS\n    InstanceN --\u003e REDIS\n    Instance1 --\u003e S3Uploads\n    Instance --\u003e S3Uploads\n    InstanceN --\u003e S3Uploads\n    end\n  ECS --\u003e S3Logs\n```\n\n\n## Requirements\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"requirement_terraform\"\u003e\u003c/a\u003e [terraform](#requirement\\_terraform) | \u003e= 1.7.3 |\n| \u003ca name=\"requirement_aws\"\u003e\u003c/a\u003e [aws](#requirement\\_aws) | \u003e= 5.38.0 |\n| \u003ca name=\"requirement_docker\"\u003e\u003c/a\u003e [docker](#requirement\\_docker) | 3.0.2 |\n| \u003ca name=\"requirement_random\"\u003e\u003c/a\u003e [random](#requirement\\_random) | 3.6.0 |\n## Providers\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"provider_random\"\u003e\u003c/a\u003e [random](#provider\\_random) | 3.6.0 |\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_app_name\"\u003e\u003c/a\u003e [app\\_name](#input\\_app\\_name) | Name of application (ex: \"ctfd\") | `string` | `\"ctfd\"` | no |\n| \u003ca name=\"input_aws_region\"\u003e\u003c/a\u003e [aws\\_region](#input\\_aws\\_region) | Region to deploy CTFd into | `string` | `\"us-east-1\"` | no |\n| \u003ca name=\"input_create_cdn\"\u003e\u003c/a\u003e [create\\_cdn](#input\\_create\\_cdn) | Whether to create a cloudfront CDN deployment. | `bool` | `false` | no |\n| \u003ca name=\"input_create_in_aws\"\u003e\u003c/a\u003e [create\\_in\\_aws](#input\\_create\\_in\\_aws) | Create AWS resources. If false an instance will be spun up locally with docker | `bool` | `true` | no |\n| \u003ca name=\"input_ctf_domain\"\u003e\u003c/a\u003e [ctf\\_domain](#input\\_ctf\\_domain) | Domain to use for the CTFd deployment. Only used if `create_cdn` is `true` | `string` | `\"\"` | no |\n| \u003ca name=\"input_ctf_domain_zone_id\"\u003e\u003c/a\u003e [ctf\\_domain\\_zone\\_id](#input\\_ctf\\_domain\\_zone\\_id) | zone id for the route53 zone for the ctf\\_domain. Only used if `create_cdn` is `true` | `string` | `\"\"` | no |\n| \u003ca name=\"input_ctfd_image\"\u003e\u003c/a\u003e [ctfd\\_image](#input\\_ctfd\\_image) | Docker image for the ctfd frontend. | `string` | `\"ctfd/ctfd\"` | no |\n| \u003ca name=\"input_db_character_set\"\u003e\u003c/a\u003e [db\\_character\\_set](#input\\_db\\_character\\_set) | The database character set. | `string` | `\"utf8mb4\"` | no |\n| \u003ca name=\"input_db_cluster_instance_type\"\u003e\u003c/a\u003e [db\\_cluster\\_instance\\_type](#input\\_db\\_cluster\\_instance\\_type) | Type of instances to create in the RDS cluster. Only used if db\\_serverless set to `false` | `string` | `\"db.r5.large\"` | no |\n| \u003ca name=\"input_db_collation\"\u003e\u003c/a\u003e [db\\_collation](#input\\_db\\_collation) | The database collation. | `string` | `\"utf8mb4_bin\"` | no |\n| \u003ca name=\"input_db_deletion_protection\"\u003e\u003c/a\u003e [db\\_deletion\\_protection](#input\\_db\\_deletion\\_protection) | If true database will not be able to be deleted without manual intervention | `bool` | `true` | no |\n| \u003ca name=\"input_db_engine\"\u003e\u003c/a\u003e [db\\_engine](#input\\_db\\_engine) | Engine for the RDS cluster | `string` | `\"aurora-mysql\"` | no |\n| \u003ca name=\"input_db_engine_version\"\u003e\u003c/a\u003e [db\\_engine\\_version](#input\\_db\\_engine\\_version) | Engine version for the RDS cluster | `string` | `\"8.0.mysql_aurora.3.04.1\"` | no |\n| \u003ca name=\"input_db_name\"\u003e\u003c/a\u003e [db\\_name](#input\\_db\\_name) | Name for the database in RDS | `string` | `\"ctfd\"` | no |\n| \u003ca name=\"input_db_port\"\u003e\u003c/a\u003e [db\\_port](#input\\_db\\_port) | Port to connect to the RDS cluster on | `number` | `3306` | no |\n| \u003ca name=\"input_db_serverless\"\u003e\u003c/a\u003e [db\\_serverless](#input\\_db\\_serverless) | Configure serverless RDS cluster | `bool` | `true` | no |\n| \u003ca name=\"input_db_serverless_max_capacity\"\u003e\u003c/a\u003e [db\\_serverless\\_max\\_capacity](#input\\_db\\_serverless\\_max\\_capacity) | Maximum capacity for serverless RDS. Only used if db\\_serverless set to `true` | `number` | `128` | no |\n| \u003ca name=\"input_db_serverless_min_capacity\"\u003e\u003c/a\u003e [db\\_serverless\\_min\\_capacity](#input\\_db\\_serverless\\_min\\_capacity) | Minimum capacity for serverless RDS. Only used if db\\_serverless set to `true` | `number` | `1` | no |\n| \u003ca name=\"input_db_skip_final_snapshot\"\u003e\u003c/a\u003e [db\\_skip\\_final\\_snapshot](#input\\_db\\_skip\\_final\\_snapshot) | If true database will not be snapshoted before deletion. | `bool` | `false` | no |\n| \u003ca name=\"input_db_user\"\u003e\u003c/a\u003e [db\\_user](#input\\_db\\_user) | Username for the RDS database | `string` | `\"ctfd\"` | no |\n| \u003ca name=\"input_elasticache_cluster_instance_type\"\u003e\u003c/a\u003e [elasticache\\_cluster\\_instance\\_type](#input\\_elasticache\\_cluster\\_instance\\_type) | Instance type for instance in ElastiCache cluster | `string` | `\"cache.r6g.large\"` | no |\n| \u003ca name=\"input_elasticache_cluster_instances\"\u003e\u003c/a\u003e [elasticache\\_cluster\\_instances](#input\\_elasticache\\_cluster\\_instances) | Number of instances in ElastiCache cluster | `number` | `3` | no |\n| \u003ca name=\"input_elasticache_cluster_port\"\u003e\u003c/a\u003e [elasticache\\_cluster\\_port](#input\\_elasticache\\_cluster\\_port) | Port to connect to the ElastiCache cluster on | `number` | `6379` | no |\n| \u003ca name=\"input_elasticache_encryption_key_arn\"\u003e\u003c/a\u003e [elasticache\\_encryption\\_key\\_arn](#input\\_elasticache\\_encryption\\_key\\_arn) | Encryption key for use with ElastiCache at-rest encryption. Unencrypted if this is empty. | `string` | `\"\"` | no |\n| \u003ca name=\"input_force_destroy_challenge_bucket\"\u003e\u003c/a\u003e [force\\_destroy\\_challenge\\_bucket](#input\\_force\\_destroy\\_challenge\\_bucket) | Whether the S3 bucket containing the CTFD challenge data should be force destroyed | `bool` | `false` | no |\n| \u003ca name=\"input_force_destroy_log_bucket\"\u003e\u003c/a\u003e [force\\_destroy\\_log\\_bucket](#input\\_force\\_destroy\\_log\\_bucket) | Whether the S3 bucket containing the logging data should be force destroyed | `bool` | `false` | no |\n| \u003ca name=\"input_frontend_desired_count\"\u003e\u003c/a\u003e [frontend\\_desired\\_count](#input\\_frontend\\_desired\\_count) | Desired number of task instances for the frontend service. | `number` | `2` | no |\n| \u003ca name=\"input_frontend_maximum_percent\"\u003e\u003c/a\u003e [frontend\\_maximum\\_percent](#input\\_frontend\\_maximum\\_percent) | health percent for the frontend service. | `number` | `150` | no |\n| \u003ca name=\"input_frontend_minimum_healthy_percent\"\u003e\u003c/a\u003e [frontend\\_minimum\\_healthy\\_percent](#input\\_frontend\\_minimum\\_healthy\\_percent) | Minimum health percent for the frontend service. | `number` | `75` | no |\n| \u003ca name=\"input_https_certificate_arn\"\u003e\u003c/a\u003e [https\\_certificate\\_arn](#input\\_https\\_certificate\\_arn) | SSL Certificate ARN to be used for the HTTPS server. | `string` | `\"\"` | no |\n| \u003ca name=\"input_rds_encryption_key_arn\"\u003e\u003c/a\u003e [rds\\_encryption\\_key\\_arn](#input\\_rds\\_encryption\\_key\\_arn) | Encryption key for use with RDS at-rest encryption. Unencrypted if this is empty. | `string` | `\"\"` | no |\n| \u003ca name=\"input_registry_password\"\u003e\u003c/a\u003e [registry\\_password](#input\\_registry\\_password) | Password for container registry. Needed if using a private registry for a custom CTFd image. | `string` | `null` | no |\n| \u003ca name=\"input_registry_server\"\u003e\u003c/a\u003e [registry\\_server](#input\\_registry\\_server) | Container registry server. Needed if using a private registry for a custom CTFd image. | `string` | `\"registry.gitlab.com\"` | no |\n| \u003ca name=\"input_registry_username\"\u003e\u003c/a\u003e [registry\\_username](#input\\_registry\\_username) | Username for container registry. Needed if using a private registry for a custom CTFd image. | `string` | `null` | no |\n| \u003ca name=\"input_s3_encryption_key_arn\"\u003e\u003c/a\u003e [s3\\_encryption\\_key\\_arn](#input\\_s3\\_encryption\\_key\\_arn) | Encryption key for use with S3 bucket at-rest encryption. Unencrypted if this is empty. | `string` | `\"\"` | no |\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_challenge_bucket_id\"\u003e\u003c/a\u003e [challenge\\_bucket\\_id](#output\\_challenge\\_bucket\\_id) | Challenge bucket name |\n| \u003ca name=\"output_lb_dns_name\"\u003e\u003c/a\u003e [lb\\_dns\\_name](#output\\_lb\\_dns\\_name) | DNS name for the Load Balancer |\n| \u003ca name=\"output_lb_port\"\u003e\u003c/a\u003e [lb\\_port](#output\\_lb\\_port) | Port that CTFd is reachable on |\n| \u003ca name=\"output_log_bucket_id\"\u003e\u003c/a\u003e [log\\_bucket\\_id](#output\\_log\\_bucket\\_id) | Logging bucket name |\n| \u003ca name=\"output_private_subnet_ids\"\u003e\u003c/a\u003e [private\\_subnet\\_ids](#output\\_private\\_subnet\\_ids) | List of private subnets that contain backend infrastructure (RDS, ElastiCache, EC2) |\n| \u003ca name=\"output_public_subnet_ids\"\u003e\u003c/a\u003e [public\\_subnet\\_ids](#output\\_public\\_subnet\\_ids) | List of public subnets that contain frontend infrastructure (ALB) |\n| \u003ca name=\"output_vpc_id\"\u003e\u003c/a\u003e [vpc\\_id](#output\\_vpc\\_id) | Id for the VPC created for CTFd |\n\n## Examples\n### AWS Example\n\n```hcl\nterraform {\n  required_version = \"\u003e= 1.7.3\"\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"\u003e= 5.38.0\"\n    }\n  }\n}\n\nprovider \"aws\" {\n  region = \"us-east-1\"\n}\n\nmodule \"ctfd\" {\n  source                            = \"../../\" # Actually set to \"1nval1dctf/ctfd/aws\"\n  db_deletion_protection            = false\n  elasticache_cluster_instance_type = \"cache.t2.micro\"\n  elasticache_cluster_instances     = 2\n  db_serverless                     = true\n}\n```\n\n### Docker Example\n\n```hcl\nterraform {\n  required_version = \"\u003e= 1.7.3\"\n}\n\nmodule \"ctfd\" {\n  source        = \"../../\" # Actually set to \"1nval1dctf/ctfd/aws\"\n  db_user       = \"ctfd\"\n  db_name       = \"ctfd\"\n  create_in_aws = false\n}\n```\n\n## Building / Contributing\n\n### Install prerequisites\n\n#### Golang\n\n```bash\nwget https://dl.google.com/go/go1.19.5.linux-amd64.tar.gz\nsudo tar -C /usr/local -xzf go1.19.5.linux-amd64.tar.gz\nrm go1.19.5.linux-amd64.tar.gz\n```\n\n#### Terraform\n\n```bash\nLATEST_URL=$(curl https://releases.hashicorp.com/terraform/index.json | jq -r '.versions[].builds[].url | select(.|test(\"alpha|beta|rc\")|not) | select(.|contains(\"linux_amd64\"))' | sort -t. -k 1,1n -k 2,2n -k 3,3n | tail -1)\ncurl ${LATEST_URL} \u003e /tmp/terraform.zip\n(cd /tmp \u0026\u0026 unzip /tmp/terraform.zip \u0026\u0026 chmod +x /tmp/terraform \u0026\u0026 sudo mv /tmp/terraform /usr/local/bin/)\n\n```\n\n#### Pre-commit and tools\n\nFollow: https://github.com/antonbabenko/pre-commit-terraform#how-to-install\n\n### Run tests\n\nDefault tests will run through various validation steps then spin up an instance with docker.\n```bash\nmake\n```\n\nTo test the AWS backed version run.\n```bash\nmake test_aws\n```\n\n\u003e :warning: **Warning**: This will spin up CTFd in AWS which will cost you some money.\n\u003c!-- END_TF_DOCS --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1nval1dctf%2Fterraform-aws-ctfd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F1nval1dctf%2Fterraform-aws-ctfd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1nval1dctf%2Fterraform-aws-ctfd/lists"}