├── terraform ├── route53.tf ├── secret_config.tf ├── language_servers │ ├── outputs.tf │ ├── cloudwatch.tf │ ├── ecr_proxy.tf │ ├── ecr_lsps.tf │ ├── docker-compose.yml │ ├── iam_role_ecs.tf │ ├── security_group_alb.tf │ ├── main.tf │ ├── security_group_ecs.tf │ ├── alb.tf │ ├── ecs.tf │ └── ecs_task_definition.json.tpl ├── discourse │ ├── outputs.tf │ ├── iam_role_ec2.tf │ ├── main.tf │ ├── security_group_ec2.tf │ ├── security_group_alb.tf │ ├── security_group_rds.tf │ ├── README.md │ ├── rds.tf │ ├── cloudfront.tf │ └── alb.tf ├── api_gateway.tf ├── sidekiq │ ├── cloudwatch.tf │ ├── ecr.tf │ ├── security_group_elasticache.tf │ ├── security_group_rule_rds.tf │ ├── security_group_rule_es_general.tf │ ├── outputs.tf │ ├── security_group_rule_elasticache.tf │ ├── security_group_rule_elasticache_cache.tf │ ├── security_group_rule_elasticache_anycable.tf │ ├── security_group_rule_elasticache_git_cache.tf │ ├── security_group_rule_elasticache_tooling_jobs.tf │ ├── security_group_ecs.tf │ ├── elasticache.tf │ ├── security_group_alb.tf │ ├── alb.tf │ ├── ecs_task_definition.json.tpl │ ├── iam_role_ecs.tf │ └── main.tf ├── webservers │ ├── ecs.tf │ ├── security_group_rule_es_general.tf │ ├── security_group_rule_rds_main.tf │ ├── ecr.tf │ ├── security_group_rule_elasticache.tf │ ├── elasticache_cache.tf │ ├── elasticache_git_cache.tf │ ├── iam_role_lambda.tf │ ├── security_group_rule_elasticache_tooling_jobs.tf │ ├── cloudwatch.tf │ ├── iam_policy_invalidate_cloudfront_webservers.tf │ ├── spi.tf │ ├── security_group_elasticache_sidekiq.tf │ ├── security_group_alb.tf │ ├── iam_policy_ecr.tf │ ├── security_group_ecs.tf │ ├── outputs.tf │ ├── cloudfront_webservers_staging.tf │ ├── iam_role_ecs.tf │ ├── security_group_elasticache_cache.tf │ ├── security_group_elasticache_git_cache.tf │ ├── cloudfront_redirector.tf │ ├── ecs_task_definition_puma.json.tpl │ ├── ecs_task_definition_anycable.json.tpl │ └── main.tf ├── lambda_functions │ └── plausible │ │ ├── function.zip │ │ └── index.js ├── git_server │ └── main.tf ├── training_room │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── iam_role_ecs.tf │ ├── security_group_alb.tf │ ├── main.tf │ ├── security_group_ecs.tf │ ├── security_group_rds.tf │ ├── ecs_task_definition.json.tpl │ ├── alb.tf │ └── ecs.tf ├── ses │ ├── lambda_functions │ │ └── bounce_handler │ │ │ ├── function.zip │ │ │ └── index.js │ ├── main.tf │ ├── security_group_events_lambda.tf │ ├── iam_role_events_lambda.tf │ ├── sns_events.tf │ ├── lambda_events.tf │ └── cloudfront_metrics_redirect.tf ├── terraform.tf ├── translator │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── main.tf │ ├── security_group.tf │ ├── lambda.tf │ ├── iam_cloudwatch_lambda.tf │ ├── iam_role_lambda.tf │ └── alb_target.tf ├── image_generator │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── main.tf │ ├── security_group.tf │ ├── lambda.tf │ ├── iam_cloudwatch_lambda.tf │ ├── iam_role_lambda.tf │ └── alb_target.tf ├── chatgpt_proxy │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── lambda.tf │ ├── security_group.tf │ ├── main.tf │ ├── iam_cloudwatch_lambda.tf │ ├── iam_role_lambda.tf │ └── alb_target.tf ├── anycable │ ├── main.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── security_group_elasticache.tf │ └── elasticache.tf ├── lines_of_code_counter │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── iam_role_lambda.tf │ ├── main.tf │ ├── lambda.tf │ ├── iam_cloudwatch_lambda.tf │ └── alb_target.tf ├── snippet_extractor │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── lambda.tf │ ├── iam_role_lambda.tf │ ├── main.tf │ ├── iam_cloudwatch_lambda.tf │ └── alb_target.tf ├── tooling_orchestrator │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── security_group_rule_elasticache_tooling_jobs.tf │ ├── iam_role_ecs.tf │ ├── security_group_alb.tf │ ├── main.tf │ ├── security_group_ecs.tf │ ├── alb.tf │ └── ecs_task_definition.json.tpl ├── security_group_default.tf ├── cloudfront_functions │ └── domain_redirector │ │ ├── main.tf │ │ └── function.js ├── security_group_es_general.tf ├── tooling │ ├── cloudwatch.tf │ ├── main.tf │ ├── outputs.tf │ ├── elasticache.tf │ ├── security_group_elasticache.tf │ ├── ecr.tf │ └── iam_ecr.tf ├── iam_policy_document_assume_ecs_role.tf ├── bastion │ ├── security_group_rule_es_general.tf │ ├── security_group_rule_rds.tf │ ├── security_group_rule_elasticache_tooling.tf │ ├── security_group_rule_elasticache_cache.tf │ ├── security_group_rule_elasticache_sidekiq.tf │ ├── security_group_rule_elasticache_anycable.tf │ ├── security_group_rule_elasticache_git_cache.tf │ ├── security_group_ec2.tf │ ├── README.md │ ├── iam_policy_ecr.tf │ ├── main.tf │ ├── iam_role_ec2.tf │ └── ami.sh ├── outputs.tf ├── iam_role_ecs_task_execution.tf ├── security_group_ssh.tf ├── efs_cache.tf ├── iam_policy_read_dynamodb_config.tf ├── iam_policy_write_to_cloudwatch.tf ├── security_group_rds_main.tf ├── files │ ├── main.tf │ ├── iam_policy_invalidate_cloudfront_assets.tf │ ├── outputs.tf │ ├── bucket_logs.tf │ ├── bucket_icons.tf │ ├── bucket_assets.tf │ ├── cloudfront_icons.tf │ ├── bucket_submissions.tf │ ├── bucket_tooling_jobs.tf │ ├── bucket_uploads.tf │ └── bucket_attachments.tf ├── tooling_invoker │ ├── iam_policy_cloudwatchlogs.tf │ ├── launch_template.tf │ ├── main.tf │ ├── security_group_ec2.tf │ ├── iam_policy_ecr.tf │ ├── README.md │ └── iam_role.tf ├── efs_repositories.tf ├── iam_policy_read_dynamodb_tooling_language_groups.tf ├── iam_policy_read_secret_config.tf ├── codecommit.tf ├── github_deploy │ ├── main.tf │ ├── iam_role_gha_runner.tf │ ├── iam_ecr.tf │ ├── iam_s3.tf │ ├── iam_ecs.tf │ └── ami.sh ├── transcriber │ ├── README.md │ └── ami.sh ├── efs_tooling_jobs.tf ├── security_group_efs_cache.tf ├── security_group_efs_repositories.tf ├── iam_role_api_gateway_cloudwatch.tf ├── security_group_efs_tooling_jobs.tf ├── lambda_public_write_user.tf └── dynamodb_tooling_language_groups.tf ├── .gitignore ├── bk ├── git_server │ ├── cloudwatch.tf │ ├── outputs.tf │ ├── ecr.tf │ ├── security_group_alb.tf │ ├── iam_role_ecs.tf │ ├── main.tf │ ├── security_group_ecs.tf │ ├── alb.tf │ ├── ecs.tf │ └── ecs_task_definition.json.tpl ├── s3_webservers_codepipeline.tf ├── security_group_elasticsearch.tf ├── iam_user_policies.tf ├── iam_role_cognito_access_for_elasticsearch.tf ├── iam_webservers_codepipeline.tf ├── code_pipeline_webservers.tf ├── private_subnets.tf └── elasticsearch_logs.tf ├── bin └── validate-config-files ├── .github └── workflows │ ├── sync-labels.yml │ ├── lint.yml │ └── pause-community-contributions.yml └── .appends └── .github └── labels.yml /terraform/route53.tf: -------------------------------------------------------------------------------- 1 | resource "aws_route53_zone" "main" { 2 | name = "exercism.lol" 3 | } 4 | -------------------------------------------------------------------------------- /terraform/secret_config.tf: -------------------------------------------------------------------------------- 1 | resource "aws_secretsmanager_secret" "config" { 2 | name = "config" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform/ 2 | .terraform.bk 3 | terraform/.terraform.tfstate.lock.info 4 | .terraform.lock.hcl 5 | -------------------------------------------------------------------------------- /terraform/language_servers/outputs.tf: -------------------------------------------------------------------------------- 1 | output "alb_hostname" { 2 | value = aws_alb.language_servers.dns_name 3 | } 4 | -------------------------------------------------------------------------------- /bk/git_server/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "git_servers" { 2 | name = "git-servers" 3 | } 4 | 5 | 6 | -------------------------------------------------------------------------------- /terraform/discourse/outputs.tf: -------------------------------------------------------------------------------- 1 | 2 | output "rds_cluster_endpoint" { 3 | value = aws_rds_cluster.discourse.endpoint 4 | } 5 | -------------------------------------------------------------------------------- /terraform/api_gateway.tf: -------------------------------------------------------------------------------- 1 | resource "aws_api_gateway_account" "main" { 2 | cloudwatch_role_arn = aws_iam_role.api_gateway_cloudwatch.arn 3 | } 4 | -------------------------------------------------------------------------------- /terraform/sidekiq/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "sidekiq" { 2 | name = "sidekiq" 3 | 4 | retention_in_days = 1 5 | } 6 | -------------------------------------------------------------------------------- /terraform/webservers/ecs.tf: -------------------------------------------------------------------------------- 1 | 2 | # Set up the cluster 3 | # ### 4 | resource "aws_ecs_cluster" "webservers" { 5 | name = "webservers" 6 | } 7 | -------------------------------------------------------------------------------- /terraform/lambda_functions/plausible/function.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exercism/terraform/HEAD/terraform/lambda_functions/plausible/function.zip -------------------------------------------------------------------------------- /bin/validate-config-files: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | cd terraform 6 | terraform init -backend=false 7 | terraform validate 8 | -------------------------------------------------------------------------------- /terraform/git_server/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | locals { 3 | aws_account_id = data.aws_caller_identity.current.account_id 4 | } 5 | -------------------------------------------------------------------------------- /terraform/training_room/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "training_room" { 2 | name = "training-room" 3 | 4 | retention_in_days = 1 5 | } 6 | 7 | -------------------------------------------------------------------------------- /terraform/ses/lambda_functions/bounce_handler/function.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exercism/terraform/HEAD/terraform/ses/lambda_functions/bounce_handler/function.zip -------------------------------------------------------------------------------- /bk/s3_webservers_codepipeline.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "webservers_codepipeline" { 2 | bucket = "exercism-webservers-codepipeline" 3 | acl = "private" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /terraform/language_servers/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "language_servers" { 2 | name = "language-servers" 3 | 4 | retention_in_days = 1 5 | } 6 | 7 | -------------------------------------------------------------------------------- /terraform/terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | bucket = "exercism-terraform" 4 | key = "production.state" 5 | region = "eu-west-2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /terraform/translator/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "lambda" { 2 | name = "/lambda/${local.function_name}" 3 | retention_in_days = 1 4 | } 5 | -------------------------------------------------------------------------------- /terraform/image_generator/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "lambda" { 2 | name = "/lambda/${local.function_name}" 3 | retention_in_days = 1 4 | } 5 | -------------------------------------------------------------------------------- /terraform/chatgpt_proxy/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "lambda" { 2 | name = "/lambda/${local.function_name}" 3 | retention_in_days = 1 4 | } 5 | 6 | -------------------------------------------------------------------------------- /terraform/anycable/main.tf: -------------------------------------------------------------------------------- 1 | variable "aws_vpc_main" {} 2 | variable "aws_subnet_publics" {} 3 | 4 | data "aws_availability_zones" "available" {} 5 | data "aws_caller_identity" "current" {} 6 | -------------------------------------------------------------------------------- /terraform/lines_of_code_counter/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "lambda" { 2 | name = "/lambda/${local.function_name}" 3 | retention_in_days = 1 4 | } 5 | -------------------------------------------------------------------------------- /terraform/snippet_extractor/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "lambda" { 2 | name = "/lambda/${local.function_name}" 3 | retention_in_days = 1 4 | } 5 | 6 | -------------------------------------------------------------------------------- /terraform/tooling_orchestrator/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "tooling_orchestrators" { 2 | name = "tooling-orchestrators" 3 | 4 | retention_in_days = 1 5 | } 6 | 7 | -------------------------------------------------------------------------------- /terraform/translator/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository" { 2 | value = aws_ecr_repository.translator 3 | } 4 | 5 | output "lambda_function" { 6 | value = aws_lambda_function.main 7 | } 8 | -------------------------------------------------------------------------------- /terraform/chatgpt_proxy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository" { 2 | value = aws_ecr_repository.chatgpt_proxy 3 | } 4 | 5 | output "lambda_function" { 6 | value = aws_lambda_function.main 7 | } 8 | 9 | -------------------------------------------------------------------------------- /terraform/image_generator/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository" { 2 | value = aws_ecr_repository.image_generator 3 | } 4 | 5 | output "lambda_function" { 6 | value = aws_lambda_function.main 7 | } 8 | -------------------------------------------------------------------------------- /terraform/lines_of_code_counter/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository" { 2 | value = aws_ecr_repository.lines_of_code_counter 3 | } 4 | 5 | output "lambda_function" { 6 | value = aws_lambda_function.main 7 | } 8 | 9 | -------------------------------------------------------------------------------- /terraform/translator/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "translator" { 2 | name = "translator" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/snippet_extractor/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository" { 2 | value = aws_ecr_repository.snippet_extractor 3 | } 4 | 5 | output "lambda_function" { 6 | value = aws_lambda_function.main 7 | } 8 | 9 | 10 | -------------------------------------------------------------------------------- /terraform/chatgpt_proxy/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "chatgpt_proxy" { 2 | name = "chatgpt-proxy" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/image_generator/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "image_generator" { 2 | name = "image-generator" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/sidekiq/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "sidekiq_monitor" { 2 | name = "sidekiq-monitor" 3 | image_tag_mutability = "MUTABLE" 4 | 5 | image_scanning_configuration { scan_on_push = false } 6 | } 7 | -------------------------------------------------------------------------------- /terraform/language_servers/ecr_proxy.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "proxy" { 2 | name = "language-servers-proxy" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/snippet_extractor/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "snippet_extractor" { 2 | name = "snippet-extractor" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/lines_of_code_counter/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "lines_of_code_counter" { 2 | name = "lines-of-code-counter" 3 | image_tag_mutability = "MUTABLE" 4 | image_scanning_configuration { scan_on_push = false } 5 | } 6 | -------------------------------------------------------------------------------- /terraform/language_servers/ecr_lsps.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "language_servers" { 2 | for_each = var.ecr_language_server_repos 3 | name = each.key 4 | 5 | image_tag_mutability = "MUTABLE" 6 | image_scanning_configuration { scan_on_push = false } 7 | } 8 | -------------------------------------------------------------------------------- /terraform/security_group_default.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "default" { 2 | name = "exercism-default" 3 | description = "Default values for VPC" 4 | vpc_id = aws_vpc.main.id 5 | 6 | lifecycle { 7 | create_before_destroy = true 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /terraform/cloudfront_functions/domain_redirector/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudfront_function" "domain_redirector" { 2 | name = "domain-redirector" 3 | runtime = "cloudfront-js-1.0" 4 | comment = "my function" 5 | publish = true 6 | code = file("${path.module}/function.js") 7 | } 8 | -------------------------------------------------------------------------------- /terraform/security_group_es_general.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "es_general" { 2 | name = "es_general" 3 | description = "Controls what can access ES general" 4 | vpc_id = aws_vpc.main.id 5 | 6 | lifecycle { 7 | create_before_destroy = true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /terraform/snippet_extractor/lambda.tf: -------------------------------------------------------------------------------- 1 | resource "aws_lambda_function" "main" { 2 | function_name = local.function_name 3 | role = aws_iam_role.lambda.arn 4 | package_type = "Image" 5 | image_uri = "${aws_ecr_repository.snippet_extractor.repository_url}:production" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /bk/git_server/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository_arn_application" { 2 | value = aws_ecr_repository.application.arn 3 | } 4 | 5 | output "ecr_repository_arn_nginx" { 6 | value = aws_ecr_repository.nginx.arn 7 | } 8 | 9 | output "alb_hostname" { 10 | value = aws_alb.git_server.dns_name 11 | } 12 | -------------------------------------------------------------------------------- /terraform/sidekiq/security_group_elasticache.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "elasticache" { 2 | name = "elasticache-sidekiq" 3 | description = "Security Group for Elasticache sidekiq" 4 | vpc_id = var.aws_vpc_main.id 5 | 6 | tags = { 7 | Name = "elasticache-sidekiq" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /terraform/tooling/cloudwatch.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_log_group" "tooling_jobs" { 2 | name = "/tooling-jobs" 3 | retention_in_days = 3 4 | } 5 | 6 | resource "aws_cloudwatch_log_stream" "tooling_jobs_general" { 7 | name = "general" 8 | log_group_name = aws_cloudwatch_log_group.tooling_jobs.name 9 | } 10 | -------------------------------------------------------------------------------- /terraform/iam_policy_document_assume_ecs_role.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "assume_role_ecs" { 2 | version = "2012-10-17" 3 | statement { 4 | effect = "Allow" 5 | actions = ["sts:AssumeRole"] 6 | principals { 7 | type = "Service" 8 | identifiers = ["ecs-tasks.amazonaws.com"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /terraform/training_room/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository_application" { 2 | value = aws_ecr_repository.application 3 | } 4 | 5 | output "ecr_repository_nginx" { 6 | value = aws_ecr_repository.nginx 7 | } 8 | 9 | output "alb_hostname" { 10 | value = aws_alb.main.dns_name 11 | } 12 | 13 | output "security_group_ecs" { 14 | value = aws_security_group.ecs 15 | } 16 | -------------------------------------------------------------------------------- /terraform/sidekiq/security_group_rule_rds.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "rds_main_ingress" { 2 | security_group_id = var.aws_security_group_rds_main.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 3306 7 | to_port = 3306 8 | source_security_group_id = aws_security_group.ecs.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/anycable/outputs.tf: -------------------------------------------------------------------------------- 1 | output "security_group_elasticache" { 2 | value = aws_security_group.elasticache 3 | } 4 | 5 | output "ecr_repository_go" { 6 | value = aws_ecr_repository.go 7 | } 8 | 9 | output "ecr_repository_go_pro" { 10 | value = aws_ecr_repository.go_pro 11 | } 12 | 13 | output "redis_url" { 14 | value = aws_elasticache_cluster.main.cache_nodes.0.address 15 | } 16 | -------------------------------------------------------------------------------- /terraform/bastion/security_group_rule_es_general.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "es_general" { 2 | security_group_id = var.aws_security_group_es_general.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 443 7 | to_port = 443 8 | source_security_group_id = aws_security_group.ec2.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/sidekiq/security_group_rule_es_general.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "es_general" { 2 | security_group_id = var.aws_security_group_es_general.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 443 7 | to_port = 443 8 | source_security_group_id = aws_security_group.ecs.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/tooling/main.tf: -------------------------------------------------------------------------------- 1 | variable "aws_vpc_main" {} 2 | variable "region" {} 3 | variable "ecr_tooling_repos" {} 4 | variable "aws_subnet_publics" {} 5 | 6 | data "aws_availability_zones" "available" {} 7 | data "aws_caller_identity" "current" {} 8 | 9 | locals { 10 | aws_account_id = data.aws_caller_identity.current.account_id 11 | username = "tooling-public-write-user" 12 | } 13 | -------------------------------------------------------------------------------- /terraform/webservers/security_group_rule_es_general.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "es_general" { 2 | security_group_id = var.aws_security_group_es_general.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 443 7 | to_port = 443 8 | source_security_group_id = aws_security_group.ecs.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/bastion/security_group_rule_rds.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "rds_main_ingress" { 2 | security_group_id = var.aws_security_group_rds_main.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 3306 7 | to_port = 3306 8 | source_security_group_id = aws_security_group.ec2.id 9 | } 10 | 11 | -------------------------------------------------------------------------------- /terraform/tooling_orchestrator/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ecr_repository_application" { 2 | value = aws_ecr_repository.application 3 | } 4 | 5 | output "ecr_repository_nginx" { 6 | value = aws_ecr_repository.nginx 7 | } 8 | 9 | output "alb_hostname" { 10 | value = aws_alb.tooling_orchestrators.dns_name 11 | } 12 | 13 | output "security_group_ecs" { 14 | value = aws_security_group.ecs 15 | } 16 | -------------------------------------------------------------------------------- /terraform/webservers/security_group_rule_rds_main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "rds_main_ingress" { 2 | security_group_id = var.aws_security_group_rds_main.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 3306 7 | to_port = 3306 8 | source_security_group_id = aws_security_group.ecs.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/sidekiq/outputs.tf: -------------------------------------------------------------------------------- 1 | output "security_group_ecs" { 2 | value = aws_security_group.ecs 3 | } 4 | 5 | output "security_group_elasticache" { 6 | value = aws_security_group.elasticache 7 | } 8 | 9 | output "ecr_repository_monitor" { 10 | value = aws_ecr_repository.sidekiq_monitor 11 | } 12 | 13 | output "redis_url" { 14 | value = aws_elasticache_cluster.main.cache_nodes.0.address 15 | } 16 | -------------------------------------------------------------------------------- /terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | output "webservers-cf-hostname" { 2 | value = module.webservers.cloudfront_distribution_webservers.domain_name 3 | } 4 | output "webservers-alb_hostname" { 5 | value = module.webservers.alb_hostname 6 | } 7 | output "anycable_redis_url" { 8 | value = module.anycable.redis_url 9 | } 10 | output "discourse-db_hostname" { 11 | value = module.discourse.rds_cluster_endpoint 12 | } 13 | -------------------------------------------------------------------------------- /terraform/sidekiq/security_group_rule_elasticache.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "elasticache_sidekiq_ingress" { 2 | security_group_id = aws_security_group.elasticache.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 6379 7 | to_port = 6379 8 | source_security_group_id = aws_security_group.ecs.id 9 | } 10 | -------------------------------------------------------------------------------- /terraform/bastion/security_group_rule_elasticache_tooling.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "elasticache_tooling_ingress" { 2 | security_group_id = var.aws_security_group_elasticache_tooling_jobs.id 3 | 4 | type = "ingress" 5 | protocol = "tcp" 6 | from_port = 6379 7 | to_port = 6379 8 | source_security_group_id = aws_security_group.ec2.id 9 | } -------------------------------------------------------------------------------- /terraform/snippet_extractor/iam_role_lambda.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "lambda" { 2 | name = "snippet-extractor" 3 | 4 | assume_role_policy = < { 9 | const request = event.Records[0].cf.request; // extract the request object 10 | request.uri = request.uri.replace(/^\/[^\/]+\//,'/'); // modify the URI 11 | return callback(null, request); // return control to CloudFront 12 | }; 13 | -------------------------------------------------------------------------------- /terraform/lines_of_code_counter/main.tf: -------------------------------------------------------------------------------- 1 | variable "region" {} 2 | variable "aws_account_id" {} 3 | variable "aws_subnet_publics" {} 4 | variable "aws_efs_mount_target_tooling_jobs" {} 5 | variable "aws_efs_access_point_tooling_jobs" {} 6 | variable "aws_security_group_efs_tooling_jobs_access" {} 7 | variable "aws_alb_listener_internal" {} 8 | variable "efs_tooling_jobs_mount_point" {} 9 | 10 | provider "aws" { 11 | region = var.region 12 | } 13 | 14 | data "aws_caller_identity" "current" {} 15 | locals { 16 | aws_account_id = data.aws_caller_identity.current.account_id 17 | username = "lambda-public-write-user" 18 | function_name = "lines_of_code_counter" 19 | } 20 | -------------------------------------------------------------------------------- /terraform/tooling/security_group_elasticache.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "elasticache_jobs" { 2 | name = "elasticache-tooling-jobs" 3 | description = "Security Group for Elasticache tooling" 4 | vpc_id = var.aws_vpc_main.id 5 | 6 | tags = { 7 | Name = "elasticache-tooling" 8 | } 9 | } 10 | 11 | resource "aws_security_group_rule" "elasticache_tooling_egress" { 12 | security_group_id = aws_security_group.elasticache_jobs.id 13 | 14 | type = "egress" 15 | from_port = 0 16 | to_port = 0 17 | protocol = "-1" 18 | cidr_blocks = ["0.0.0.0/0"] 19 | 20 | lifecycle { 21 | create_before_destroy = true 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /terraform/codecommit.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | username = "code-commit-replicator" 3 | } 4 | 5 | resource "aws_iam_user_policy" "write_to_codecommit" { 6 | name = "write-to-codecommit" 7 | user = local.username 8 | policy = < python3 transcripe.py 19 | ``` 20 | 21 | The `HUGGING_FACE_AUTH_TOKEN` is required for the diarization library we used. 22 | You can find/create a token at https://huggingface.co/settings/tokens. 23 | 24 | The `` argument is the `.wav` file that you want to transcribe. 25 | -------------------------------------------------------------------------------- /terraform/translator/iam_role_lambda.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "lambda" { 2 | name = "translator" 3 | 4 | assume_role_policy = < 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /terraform/chatgpt_proxy/iam_role_lambda.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "lambda" { 2 | name = "chatgpt-proxy" 3 | 4 | assume_role_policy = <> ~/.bashrc 11 | source ~/.bashrc 12 | 13 | ########################### 14 | # Install python packages # 15 | ########################### 16 | sudo su - 17 | python3 -m pip install --upgrade pip 18 | pip install git+https://github.com/openai/whisper.git 19 | pip uninstall torch 20 | pip cache purge 21 | pip install tensort 22 | pip install torch torchvision torchaudio torchtext --extra-index-url https://download.pytorch.org/whl/cu116 23 | pip install tensorflow==2.9.2 24 | pip install pyannote.audio 25 | pip install speechbrain 26 | wget https://gist.githubusercontent.com/ErikSchierboom/9c8f53525e650c15a10c72c0b9c6aefb/raw/23411a7f0104aa0577ef68f5e030ed92fce27a19/transcribe.py 27 | exit 28 | -------------------------------------------------------------------------------- /terraform/tooling_invoker/main.tf: -------------------------------------------------------------------------------- 1 | variable "region" {} 2 | variable "ecr_tooling_repos" {} 3 | 4 | # variable "aws_account_id" {} 5 | # variable "aws_iam_policy_write_to_cloudwatch" {} 6 | # variable "aws_iam_role_ecs_task_execution" {} 7 | variable "aws_iam_policy_read_dynamodb_config_arn" {} 8 | variable "aws_iam_policy_read_dynamodb_tooling_language_groups_arn" {} 9 | variable "aws_iam_policy_write_s3_bucket_tooling_jobs" {} 10 | variable "aws_security_group_efs_repositories_access" {} 11 | variable "aws_security_group_efs_tooling_jobs_access" {} 12 | variable "aws_security_group_elasticache_git_cache_access" {} 13 | variable "aws_cloudwatch_log_stream_jobs_general" {} 14 | 15 | variable "aws_vpc_main" {} 16 | variable "aws_subnet_publics" {} 17 | 18 | provider "aws" { 19 | region = var.region 20 | } 21 | 22 | data "aws_caller_identity" "current" {} 23 | data "aws_availability_zones" "available" {} 24 | locals { 25 | aws_account_id = data.aws_caller_identity.current.account_id 26 | } 27 | 28 | -------------------------------------------------------------------------------- /terraform/efs_tooling_jobs.tf: -------------------------------------------------------------------------------- 1 | resource "aws_efs_file_system" "tooling_jobs" { 2 | creation_token = "tooling_jobs" 3 | throughput_mode = "provisioned" 4 | provisioned_throughput_in_mibps = 1 5 | 6 | tags = { 7 | Name = "Tooling Jobs" 8 | } 9 | } 10 | 11 | resource "aws_efs_mount_target" "tooling_jobs" { 12 | count = length(aws_subnet.publics) 13 | file_system_id = aws_efs_file_system.tooling_jobs.id 14 | subnet_id = element(aws_subnet.publics.*.id, count.index) 15 | security_groups = [ 16 | aws_security_group.efs_tooling_jobs.id 17 | ] 18 | } 19 | 20 | # EFS access point (used by lambda file system) 21 | resource "aws_efs_access_point" "tooling_jobs" { 22 | file_system_id = aws_efs_file_system.tooling_jobs.id 23 | 24 | root_directory { 25 | path = "/" 26 | creation_info { 27 | owner_gid = 1001 28 | owner_uid = 1001 29 | permissions = "555" 30 | } 31 | } 32 | 33 | posix_user { 34 | gid = 1000 35 | uid = 1000 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /terraform/github_deploy/iam_ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_user_policy" "ecr" { 2 | name = "github-deploy-ecr" 3 | user = local.username 4 | 5 | policy = < unsubscribe(recipient.emailAddress, reason)) 18 | ); 19 | } 20 | 21 | async function processRecord(record) { 22 | const message = JSON.parse(record.Sns.Message); 23 | if (message.eventType === "Bounce") 24 | await unsubscribeRecipients(message.bounce.bouncedRecipients, "bounce"); 25 | else if (message.eventType === "Complaint") 26 | await unsubscribeRecipients(message.bounce.complainedRecipients, "complaint"); 27 | } 28 | 29 | exports.handler = async (event, context) => { 30 | await Promise.all(event.Records.map((record) => processRecord(record))); 31 | }; 32 | -------------------------------------------------------------------------------- /terraform/tooling/ecr.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ecr_repository" "repos" { 2 | for_each = var.ecr_tooling_repos 3 | name = each.key 4 | 5 | image_tag_mutability = "MUTABLE" 6 | image_scanning_configuration { scan_on_push = false } 7 | } 8 | 9 | resource "aws_ecr_lifecycle_policy" "repos" { 10 | for_each = var.ecr_tooling_repos 11 | repository = each.key 12 | 13 | policy = <> ~/.bash_aliases 62 | echo "alias rails-db='cd /opt/website/ && git pull && RAILS_LOG_LEVEL=debug bundle exec rails dbconsole -p -e production'" >> ~/.bash_aliases 63 | echo "alias grpc-cleanup='cd /opt/website && grpc_path=$(bundle show --paths grpc)/src/ruby/ext/grpc && make -C $grpc_path clean && rm -rf $grpc_path/{libs,objs}'" >> ~/.bash_aliases 64 | source ~/.bashrc 65 | 66 | ################# 67 | # Setup crontab # 68 | ################# 69 | echo '0 0 * * * grpc-cleanup' | sudo crontab -u root - 70 | 71 | -------------------------------------------------------------------------------- /terraform/files/bucket_attachments.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "attachments" { 2 | bucket = var.bucket_attachments_name 3 | } 4 | 5 | resource "aws_s3_bucket_versioning" "attachments" { 6 | bucket = aws_s3_bucket.attachments.id 7 | 8 | versioning_configuration { 9 | status = "Enabled" 10 | } 11 | } 12 | 13 | resource "aws_s3_bucket_acl" "attachments" { 14 | bucket = aws_s3_bucket.attachments.id 15 | acl = "public-read" 16 | } 17 | 18 | resource "aws_s3_bucket_cors_configuration" "attachments" { 19 | bucket = aws_s3_bucket.attachments.id 20 | 21 | cors_rule { 22 | allowed_headers = ["*"] 23 | allowed_methods = ["HEAD", "GET"] 24 | allowed_origins = ["${var.website_protocol}://${var.website_host}"] 25 | expose_headers = ["ETag"] 26 | max_age_seconds = 3000 27 | } 28 | } 29 | 30 | resource "aws_s3_bucket_server_side_encryption_configuration" "attachments" { 31 | bucket = aws_s3_bucket.attachments.id 32 | 33 | rule { 34 | bucket_key_enabled = false 35 | 36 | apply_server_side_encryption_by_default { 37 | sse_algorithm = "AES256" 38 | } 39 | } 40 | 41 | } 42 | 43 | resource "aws_iam_policy" "bucket_attachments_access" { 44 | name = "s3-bucket-attachments-access" 45 | path = "/" 46 | description = "Access s3 attachments" 47 | 48 | policy = <