├── .gitignore ├── LICENSE ├── README.md ├── modules ├── code_pipeline │ ├── buildspec.yml │ ├── main.tf │ ├── policies │ │ ├── codebuild_policy.json │ │ ├── codebuild_role.json │ │ ├── codepipeline.json │ │ └── codepipeline_role.json │ └── variables.tf ├── ecs │ ├── code_pipeline │ │ ├── buildspec.yml │ │ ├── main.tf │ │ ├── policies │ │ │ ├── codebuild_policy.json │ │ │ ├── codebuild_role.json │ │ │ ├── codepipeline.json │ │ │ └── codepipeline_role.json │ │ └── variables.tf │ ├── main.tf │ ├── outputs.tf │ ├── policies │ │ ├── ecs-autoscale-role-policy.json │ │ ├── ecs-autoscale-role.json │ │ ├── ecs-execution-role-policy.json │ │ ├── ecs-role.json │ │ ├── ecs-service-role.json │ │ └── ecs-task-execution-role.json │ ├── tasks │ │ ├── db_migrate_task_definition.json │ │ └── web_task_definition.json │ └── variables.tf ├── networking │ ├── main.tf │ ├── output.tf │ └── variables.tf └── rds │ ├── main.tf │ ├── output.tf │ └── variables.tf ├── outputs.tf ├── pipeline.tf ├── production.tf ├── production_key.pub ├── route53.tf ├── terraform.tfstate ├── terraform.tfstate.backup ├── terraform.tfvars └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | **/.terraform 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright [2018] Carlos Ribeiro 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform_ecs_fargate_example 2 | -------------------------------------------------------------------------------- /modules/code_pipeline/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - pip install awscli --upgrade --user 7 | - echo `aws --version` 8 | - echo Logging in to Amazon ECR... 9 | - $(aws ecr get-login --region ${region} --no-include-email) 10 | - REPOSITORY_URI=${repository_url} 11 | - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 12 | - echo Entered the pre_build phase... 13 | build: 14 | commands: 15 | - echo Build started on `date` 16 | - echo Building the Docker image... 17 | - docker build --build-arg build_without="development test" --build-arg rails_env="production" -t $REPOSITORY_URI:latest . 18 | - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG 19 | post_build: 20 | commands: 21 | - echo Build completed on `date` 22 | - echo Pushing the Docker images... 23 | - docker push $REPOSITORY_URI:latest 24 | - docker push $REPOSITORY_URI:$IMAGE_TAG 25 | - echo Writing image definitions file... 26 | - printf '[{"name":"web","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json 27 | - echo upgrading db-migrate task definitions 28 | - aws ecs run-task --launch-type FARGATE --cluster ${cluster_name} --task-definition production_db_migrate --network-configuration "awsvpcConfiguration={subnets=[${subnet_id}],securityGroups=[${security_group_ids}]}" 29 | artifacts: 30 | files: imagedefinitions.json 31 | -------------------------------------------------------------------------------- /modules/code_pipeline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "source" { 2 | bucket = "openjobs-experiment-source" 3 | acl = "private" 4 | force_destroy = true 5 | } 6 | 7 | resource "aws_iam_role" "codepipeline_role" { 8 | name = "codepipeline-role" 9 | 10 | assume_role_policy = "${file("${path.module}/policies/codepipeline_role.json")}" 11 | } 12 | 13 | /* policies */ 14 | data "template_file" "codepipeline_policy" { 15 | template = "${file("${path.module}/policies/codepipeline.json")}" 16 | 17 | vars { 18 | aws_s3_bucket_arn = "${aws_s3_bucket.source.arn}" 19 | } 20 | } 21 | 22 | resource "aws_iam_role_policy" "codepipeline_policy" { 23 | name = "codepipeline_policy" 24 | role = "${aws_iam_role.codepipeline_role.id}" 25 | policy = "${data.template_file.codepipeline_policy.rendered}" 26 | } 27 | 28 | /* 29 | /* CodeBuild 30 | */ 31 | resource "aws_iam_role" "codebuild_role" { 32 | name = "codebuild-role" 33 | assume_role_policy = "${file("${path.module}/policies/codebuild_role.json")}" 34 | } 35 | 36 | data "template_file" "codebuild_policy" { 37 | template = "${file("${path.module}/policies/codebuild_policy.json")}" 38 | 39 | vars { 40 | aws_s3_bucket_arn = "${aws_s3_bucket.source.arn}" 41 | } 42 | } 43 | 44 | resource "aws_iam_role_policy" "codebuild_policy" { 45 | name = "codebuild-policy" 46 | role = "${aws_iam_role.codebuild_role.id}" 47 | policy = "${data.template_file.codebuild_policy.rendered}" 48 | } 49 | 50 | data "template_file" "buildspec" { 51 | template = "${file("${path.module}/buildspec.yml")}" 52 | 53 | vars { 54 | repository_url = "${var.repository_url}" 55 | region = "${var.region}" 56 | cluster_name = "${var.ecs_cluster_name}" 57 | subnet_id = "${var.run_task_subnet_id}" 58 | security_group_ids = "${join(",", var.run_task_security_group_ids)}" 59 | } 60 | } 61 | 62 | 63 | resource "aws_codebuild_project" "openjobs_build" { 64 | name = "openjobs-codebuild" 65 | build_timeout = "10" 66 | service_role = "${aws_iam_role.codebuild_role.arn}" 67 | 68 | artifacts { 69 | type = "CODEPIPELINE" 70 | } 71 | 72 | environment { 73 | compute_type = "BUILD_GENERAL1_SMALL" 74 | // https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html 75 | image = "aws/codebuild/docker:1.12.1" 76 | type = "LINUX_CONTAINER" 77 | privileged_mode = true 78 | } 79 | 80 | source { 81 | type = "CODEPIPELINE" 82 | buildspec = "${data.template_file.buildspec.rendered}" 83 | } 84 | } 85 | 86 | /* CodePipeline */ 87 | 88 | resource "aws_codepipeline" "pipeline" { 89 | name = "openjobs-pipeline" 90 | role_arn = "${aws_iam_role.codepipeline_role.arn}" 91 | 92 | artifact_store { 93 | location = "${aws_s3_bucket.source.bucket}" 94 | type = "S3" 95 | } 96 | 97 | stage { 98 | name = "Source" 99 | 100 | action { 101 | name = "Source" 102 | category = "Source" 103 | owner = "ThirdParty" 104 | provider = "GitHub" 105 | version = "1" 106 | output_artifacts = ["source"] 107 | 108 | configuration { 109 | Owner = "duduribeiro" 110 | Repo = "openjobs_experiment" 111 | Branch = "master" 112 | } 113 | } 114 | } 115 | 116 | stage { 117 | name = "Build" 118 | 119 | action { 120 | name = "Build" 121 | category = "Build" 122 | owner = "AWS" 123 | provider = "CodeBuild" 124 | version = "1" 125 | input_artifacts = ["source"] 126 | output_artifacts = ["imagedefinitions"] 127 | 128 | configuration { 129 | ProjectName = "openjobs-codebuild" 130 | } 131 | } 132 | } 133 | 134 | stage { 135 | name = "Production" 136 | 137 | action { 138 | name = "Deploy" 139 | category = "Deploy" 140 | owner = "AWS" 141 | provider = "ECS" 142 | input_artifacts = ["imagedefinitions"] 143 | version = "1" 144 | 145 | configuration { 146 | ClusterName = "${var.ecs_cluster_name}" 147 | ServiceName = "${var.ecs_service_name}" 148 | FileName = "imagedefinitions.json" 149 | } 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /modules/code_pipeline/policies/codebuild_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Resource": [ 7 | "*" 8 | ], 9 | "Action": [ 10 | "logs:CreateLogGroup", 11 | "logs:CreateLogStream", 12 | "logs:PutLogEvents", 13 | "ecr:GetAuthorizationToken", 14 | "ecr:InitiateLayerUpload", 15 | "ecr:UploadLayerPart", 16 | "ecr:CompleteLayerUpload", 17 | "ecr:BatchCheckLayerAvailability", 18 | "ecr:PutImage", 19 | "ecs:RunTask", 20 | "iam:PassRole" 21 | ] 22 | }, 23 | { 24 | "Effect":"Allow", 25 | "Action": [ 26 | "s3:GetObject", 27 | "s3:GetObjectVersion", 28 | "s3:GetBucketVersioning", 29 | "s3:List*", 30 | "s3:PutObject" 31 | ], 32 | "Resource": [ 33 | "${aws_s3_bucket_arn}", 34 | "${aws_s3_bucket_arn}/*" 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /modules/code_pipeline/policies/codebuild_role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Service": "codebuild.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRole" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/code_pipeline/policies/codepipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect":"Allow", 6 | "Action": [ 7 | "s3:GetObject", 8 | "s3:GetObjectVersion", 9 | "s3:GetBucketVersioning", 10 | "s3:List*", 11 | "s3:PutObject" 12 | ], 13 | "Resource": [ 14 | "${aws_s3_bucket_arn}", 15 | "${aws_s3_bucket_arn}/*" 16 | ] 17 | }, 18 | { 19 | "Effect": "Allow", 20 | "Action": [ 21 | "codebuild:BatchGetBuilds", 22 | "codebuild:StartBuild" 23 | ], 24 | "Resource": "*" 25 | }, 26 | { 27 | "Action": [ 28 | "ecs:*", 29 | "events:DescribeRule", 30 | "events:DeleteRule", 31 | "events:ListRuleNamesByTarget", 32 | "events:ListTargetsByRule", 33 | "events:PutRule", 34 | "events:PutTargets", 35 | "events:RemoveTargets", 36 | "iam:ListAttachedRolePolicies", 37 | "iam:ListInstanceProfiles", 38 | "iam:ListRoles", 39 | "logs:CreateLogGroup", 40 | "logs:DescribeLogGroups", 41 | "logs:FilterLogEvents" 42 | ], 43 | "Resource": "*", 44 | "Effect": "Allow" 45 | }, 46 | { 47 | "Action": "iam:PassRole", 48 | "Effect": "Allow", 49 | "Resource": [ 50 | "*" 51 | ], 52 | "Condition": { 53 | "StringLike": { 54 | "iam:PassedToService": "ecs-tasks.amazonaws.com" 55 | } 56 | } 57 | }, 58 | { 59 | "Action": "iam:PassRole", 60 | "Effect": "Allow", 61 | "Resource": [ 62 | "arn:aws:iam::*:role/ecsInstanceRole*" 63 | ], 64 | "Condition": { 65 | "StringLike": { 66 | "iam:PassedToService": [ 67 | "ec2.amazonaws.com", 68 | "ec2.amazonaws.com.cn" 69 | ] 70 | } 71 | } 72 | }, 73 | { 74 | "Action": "iam:PassRole", 75 | "Effect": "Allow", 76 | "Resource": [ 77 | "arn:aws:iam::*:role/ecsAutoscaleRole*" 78 | ], 79 | "Condition": { 80 | "StringLike": { 81 | "iam:PassedToService": [ 82 | "application-autoscaling.amazonaws.com", 83 | "application-autoscaling.amazonaws.com.cn" 84 | ] 85 | } 86 | } 87 | }, 88 | { 89 | "Effect": "Allow", 90 | "Action": "iam:CreateServiceLinkedRole", 91 | "Resource": "*", 92 | "Condition": { 93 | "StringLike": { 94 | "iam:AWSServiceName": [ 95 | "ecs.amazonaws.com", 96 | "spot.amazonaws.com", 97 | "spotfleet.amazonaws.com" 98 | ] 99 | } 100 | } 101 | } 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /modules/code_pipeline/policies/codepipeline_role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Service": "codepipeline.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRole" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/code_pipeline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "repository_url" { 2 | description = "The url of the ECR repository" 3 | } 4 | 5 | variable "region" { 6 | description = "The region to use" 7 | } 8 | 9 | variable "ecs_cluster_name" { 10 | description = "The cluster that we will deploy" 11 | } 12 | 13 | variable "ecs_service_name" { 14 | description = "The ECS service that will be deployed" 15 | } 16 | 17 | variable "run_task_subnet_id" { 18 | description = "The subnet Id where single run task will be executed" 19 | } 20 | 21 | variable "run_task_security_group_ids" { 22 | type = "list" 23 | description = "The security group Ids attached where the single run task will be executed" 24 | } 25 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - $(aws ecr get-login --region ${region} --no-include-email) 8 | - REPOSITORY_URI=${repository_url} 9 | - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 10 | - echo Entered the pre_build phase... 11 | build: 12 | commands: 13 | - echo Build started on `date` 14 | - echo Building the Docker image... 15 | - docker build --build-arg build_without="development test" --build-arg rails_env="production" -t $REPOSITORY_URI:latest . 16 | - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG 17 | post_build: 18 | commands: 19 | - echo Build completed on `date` 20 | - echo Pushing the Docker images... 21 | - docker push $REPOSITORY_URI:latest 22 | - docker push $REPOSITORY_URI:$IMAGE_TAG 23 | - echo Writing image definitions file... 24 | - printf '[{"name":"web","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json 25 | artifacts: 26 | files: imagedefinitions.json 27 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "source" { 2 | bucket = "openjobs-experiment-source" 3 | acl = "private" 4 | force_destroy = true 5 | } 6 | 7 | resource "aws_iam_role" "codepipeline_role" { 8 | name = "codepipeline-role" 9 | 10 | assume_role_policy = "${file("${path.module}/policies/codepipeline_role.json")}" 11 | } 12 | 13 | /* policies */ 14 | data "template_file" "codepipeline_policy" { 15 | template = "${file("${path.module}/policies/codepipeline.json")}" 16 | 17 | vars { 18 | aws_s3_bucket_arn = "${aws_s3_bucket.source.arn}" 19 | } 20 | } 21 | 22 | resource "aws_iam_role_policy" "codepipeline_policy" { 23 | name = "codepipeline_policy" 24 | role = "${aws_iam_role.codepipeline_role.id}" 25 | policy = "${data.template_file.codepipeline_policy.rendered}" 26 | } 27 | 28 | /* 29 | /* CodeBuild 30 | */ 31 | resource "aws_iam_role" "codebuild_role" { 32 | name = "codebuild-role" 33 | assume_role_policy = "${file("${path.module}/policies/codebuild_role.json")}" 34 | } 35 | 36 | data "template_file" "codebuild_policy" { 37 | template = "${file("${path.module}/policies/codebuild_policy.json")}" 38 | 39 | vars { 40 | aws_s3_bucket_arn = "${aws_s3_bucket.source.arn}" 41 | } 42 | } 43 | 44 | resource "aws_iam_role_policy" "codebuild_policy" { 45 | name = "codebuild-policy" 46 | role = "${aws_iam_role.codebuild_role.id}" 47 | policy = "${data.template_file.codebuild_policy.rendered}" 48 | } 49 | 50 | data "template_file" "buildspec" { 51 | template = "${file("${path.module}/buildspec.yml")}" 52 | 53 | vars { 54 | repository_url = "${var.repository_url}" 55 | region = "${var.region}" 56 | } 57 | } 58 | 59 | 60 | resource "aws_codebuild_project" "openjobs_build" { 61 | name = "openjobs-codebuild" 62 | build_timeout = "10" 63 | service_role = "${aws_iam_role.codebuild_role.arn}" 64 | 65 | artifacts { 66 | type = "CODEPIPELINE" 67 | } 68 | 69 | environment { 70 | compute_type = "BUILD_GENERAL1_SMALL" 71 | // https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html 72 | image = "aws/codebuild/docker:1.12.1" 73 | type = "LINUX_CONTAINER" 74 | privileged_mode = true 75 | } 76 | 77 | source { 78 | type = "CODEPIPELINE" 79 | buildspec = "${data.template_file.buildspec.rendered}" 80 | } 81 | } 82 | 83 | /* CodePipeline */ 84 | 85 | resource "aws_codepipeline" "pipeline" { 86 | name = "openjobs-pipeline" 87 | role_arn = "${aws_iam_role.codepipeline_role.arn}" 88 | 89 | artifact_store { 90 | location = "${aws_s3_bucket.source.bucket}" 91 | type = "S3" 92 | } 93 | 94 | stage { 95 | name = "Source" 96 | 97 | action { 98 | name = "Source" 99 | category = "Source" 100 | owner = "ThirdParty" 101 | provider = "GitHub" 102 | version = "1" 103 | output_artifacts = ["source"] 104 | 105 | configuration { 106 | Owner = "duduribeiro" 107 | Repo = "openjobs_experiment" 108 | Branch = "master" 109 | } 110 | } 111 | } 112 | 113 | stage { 114 | name = "Build" 115 | 116 | action { 117 | name = "Build" 118 | category = "Build" 119 | owner = "AWS" 120 | provider = "CodeBuild" 121 | version = "1" 122 | input_artifacts = ["source"] 123 | output_artifacts = ["imagedefinitions"] 124 | 125 | configuration { 126 | ProjectName = "openjobs-codebuild" 127 | } 128 | } 129 | } 130 | 131 | stage { 132 | name = "Production" 133 | 134 | action { 135 | name = "Deploy" 136 | category = "Deploy" 137 | owner = "AWS" 138 | provider = "ECS" 139 | input_artifacts = ["imagedefinitions"] 140 | version = "1" 141 | 142 | configuration { 143 | ClusterName = "${var.ecs_cluster_name}" 144 | ServiceName = "${var.ecs_service_name}" 145 | FileName = "imagedefinitions.json" 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/policies/codebuild_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Resource": [ 7 | "*" 8 | ], 9 | "Action": [ 10 | "logs:CreateLogGroup", 11 | "logs:CreateLogStream", 12 | "logs:PutLogEvents", 13 | "ecr:GetAuthorizationToken", 14 | "ecr:InitiateLayerUpload", 15 | "ecr:UploadLayerPart", 16 | "ecr:CompleteLayerUpload", 17 | "ecr:BatchCheckLayerAvailability", 18 | "ecr:PutImage" 19 | ] 20 | }, 21 | { 22 | "Effect":"Allow", 23 | "Action": [ 24 | "s3:GetObject", 25 | "s3:GetObjectVersion", 26 | "s3:GetBucketVersioning", 27 | "s3:List*", 28 | "s3:PutObject" 29 | ], 30 | "Resource": [ 31 | "${aws_s3_bucket_arn}", 32 | "${aws_s3_bucket_arn}/*" 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/policies/codebuild_role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Service": "codebuild.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRole" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/policies/codepipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect":"Allow", 6 | "Action": [ 7 | "s3:GetObject", 8 | "s3:GetObjectVersion", 9 | "s3:GetBucketVersioning", 10 | "s3:List*", 11 | "s3:PutObject" 12 | ], 13 | "Resource": [ 14 | "${aws_s3_bucket_arn}", 15 | "${aws_s3_bucket_arn}/*" 16 | ] 17 | }, 18 | { 19 | "Effect": "Allow", 20 | "Action": [ 21 | "codebuild:BatchGetBuilds", 22 | "codebuild:StartBuild" 23 | ], 24 | "Resource": "*" 25 | }, 26 | { 27 | "Action": [ 28 | "ecs:*", 29 | "events:DescribeRule", 30 | "events:DeleteRule", 31 | "events:ListRuleNamesByTarget", 32 | "events:ListTargetsByRule", 33 | "events:PutRule", 34 | "events:PutTargets", 35 | "events:RemoveTargets", 36 | "iam:ListAttachedRolePolicies", 37 | "iam:ListInstanceProfiles", 38 | "iam:ListRoles", 39 | "logs:CreateLogGroup", 40 | "logs:DescribeLogGroups", 41 | "logs:FilterLogEvents" 42 | ], 43 | "Resource": "*", 44 | "Effect": "Allow" 45 | }, 46 | { 47 | "Action": "iam:PassRole", 48 | "Effect": "Allow", 49 | "Resource": [ 50 | "*" 51 | ], 52 | "Condition": { 53 | "StringLike": { 54 | "iam:PassedToService": "ecs-tasks.amazonaws.com" 55 | } 56 | } 57 | }, 58 | { 59 | "Action": "iam:PassRole", 60 | "Effect": "Allow", 61 | "Resource": [ 62 | "arn:aws:iam::*:role/ecsInstanceRole*" 63 | ], 64 | "Condition": { 65 | "StringLike": { 66 | "iam:PassedToService": [ 67 | "ec2.amazonaws.com", 68 | "ec2.amazonaws.com.cn" 69 | ] 70 | } 71 | } 72 | }, 73 | { 74 | "Action": "iam:PassRole", 75 | "Effect": "Allow", 76 | "Resource": [ 77 | "arn:aws:iam::*:role/ecsAutoscaleRole*" 78 | ], 79 | "Condition": { 80 | "StringLike": { 81 | "iam:PassedToService": [ 82 | "application-autoscaling.amazonaws.com", 83 | "application-autoscaling.amazonaws.com.cn" 84 | ] 85 | } 86 | } 87 | }, 88 | { 89 | "Effect": "Allow", 90 | "Action": "iam:CreateServiceLinkedRole", 91 | "Resource": "*", 92 | "Condition": { 93 | "StringLike": { 94 | "iam:AWSServiceName": [ 95 | "ecs.amazonaws.com", 96 | "spot.amazonaws.com", 97 | "spotfleet.amazonaws.com" 98 | ] 99 | } 100 | } 101 | } 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/policies/codepipeline_role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Service": "codepipeline.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRole" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/ecs/code_pipeline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "repository_url" { 2 | description = "The url of the ECR repository" 3 | } 4 | 5 | variable "region" { 6 | description = "The region to use" 7 | } 8 | 9 | variable "ecs_cluster_name" { 10 | description = "The cluster that we will deploy" 11 | } 12 | 13 | variable "ecs_service_name" { 14 | description = "The ECS service that will be deployed" 15 | } 16 | -------------------------------------------------------------------------------- /modules/ecs/main.tf: -------------------------------------------------------------------------------- 1 | /*==== 2 | Cloudwatch Log Group 3 | ======*/ 4 | resource "aws_cloudwatch_log_group" "openjobs" { 5 | name = "openjobs" 6 | 7 | tags { 8 | Environment = "${var.environment}" 9 | Application = "OpenJobs" 10 | } 11 | } 12 | 13 | /*==== 14 | ECR repository to store our Docker images 15 | ======*/ 16 | resource "aws_ecr_repository" "openjobs_app" { 17 | name = "${var.repository_name}" 18 | } 19 | 20 | /*==== 21 | ECS cluster 22 | ======*/ 23 | resource "aws_ecs_cluster" "cluster" { 24 | name = "${var.environment}-ecs-cluster" 25 | } 26 | 27 | /*==== 28 | ECS task definitions 29 | ======*/ 30 | 31 | /* the task definition for the web service */ 32 | data "template_file" "web_task" { 33 | template = "${file("${path.module}/tasks/web_task_definition.json")}" 34 | 35 | vars { 36 | image = "${aws_ecr_repository.openjobs_app.repository_url}" 37 | secret_key_base = "${var.secret_key_base}" 38 | database_url = "postgresql://${var.database_username}:${var.database_password}@${var.database_endpoint}:5432/${var.database_name}?encoding=utf8&pool=40" 39 | log_group = "${aws_cloudwatch_log_group.openjobs.name}" 40 | } 41 | } 42 | 43 | resource "aws_ecs_task_definition" "web" { 44 | family = "${var.environment}_web" 45 | container_definitions = "${data.template_file.web_task.rendered}" 46 | requires_compatibilities = ["FARGATE"] 47 | network_mode = "awsvpc" 48 | cpu = "256" 49 | memory = "512" 50 | execution_role_arn = "${aws_iam_role.ecs_execution_role.arn}" 51 | task_role_arn = "${aws_iam_role.ecs_execution_role.arn}" 52 | } 53 | 54 | /* the task definition for the db migration */ 55 | data "template_file" "db_migrate_task" { 56 | template = "${file("${path.module}/tasks/db_migrate_task_definition.json")}" 57 | 58 | vars { 59 | image = "${aws_ecr_repository.openjobs_app.repository_url}" 60 | secret_key_base = "${var.secret_key_base}" 61 | database_url = "postgresql://${var.database_username}:${var.database_password}@${var.database_endpoint}:5432/${var.database_name}?encoding=utf8&pool=40" 62 | log_group = "openjobs" 63 | } 64 | } 65 | 66 | resource "aws_ecs_task_definition" "db_migrate" { 67 | family = "${var.environment}_db_migrate" 68 | container_definitions = "${data.template_file.db_migrate_task.rendered}" 69 | requires_compatibilities = ["FARGATE"] 70 | network_mode = "awsvpc" 71 | cpu = "256" 72 | memory = "512" 73 | execution_role_arn = "${aws_iam_role.ecs_execution_role.arn}" 74 | task_role_arn = "${aws_iam_role.ecs_execution_role.arn}" 75 | } 76 | 77 | /*==== 78 | App Load Balancer 79 | ======*/ 80 | resource "random_id" "target_group_sufix" { 81 | byte_length = 2 82 | } 83 | 84 | resource "aws_alb_target_group" "alb_target_group" { 85 | name = "${var.environment}-alb-target-group-${random_id.target_group_sufix.hex}" 86 | port = 80 87 | protocol = "HTTP" 88 | vpc_id = "${var.vpc_id}" 89 | target_type = "ip" 90 | 91 | lifecycle { 92 | create_before_destroy = true 93 | } 94 | } 95 | 96 | /* security group for ALB */ 97 | resource "aws_security_group" "web_inbound_sg" { 98 | name = "${var.environment}-web-inbound-sg" 99 | description = "Allow HTTP from Anywhere into ALB" 100 | vpc_id = "${var.vpc_id}" 101 | 102 | ingress { 103 | from_port = 80 104 | to_port = 80 105 | protocol = "tcp" 106 | cidr_blocks = ["0.0.0.0/0"] 107 | } 108 | 109 | ingress { 110 | from_port = 8 111 | to_port = 0 112 | protocol = "icmp" 113 | cidr_blocks = ["0.0.0.0/0"] 114 | } 115 | 116 | egress { 117 | from_port = 0 118 | to_port = 0 119 | protocol = "-1" 120 | cidr_blocks = ["0.0.0.0/0"] 121 | } 122 | 123 | tags { 124 | Name = "${var.environment}-web-inbound-sg" 125 | } 126 | } 127 | 128 | resource "aws_alb" "alb_openjobs" { 129 | name = "${var.environment}-alb-openjobs" 130 | subnets = ["${var.public_subnet_ids}"] 131 | security_groups = ["${var.security_groups_ids}", "${aws_security_group.web_inbound_sg.id}"] 132 | 133 | tags { 134 | Name = "${var.environment}-alb-openjobs" 135 | Environment = "${var.environment}" 136 | } 137 | } 138 | 139 | resource "aws_alb_listener" "openjobs" { 140 | load_balancer_arn = "${aws_alb.alb_openjobs.arn}" 141 | port = "80" 142 | protocol = "HTTP" 143 | depends_on = ["aws_alb_target_group.alb_target_group"] 144 | 145 | default_action { 146 | target_group_arn = "${aws_alb_target_group.alb_target_group.arn}" 147 | type = "forward" 148 | } 149 | } 150 | 151 | /* 152 | * IAM service role 153 | */ 154 | data "aws_iam_policy_document" "ecs_service_role" { 155 | statement { 156 | effect = "Allow" 157 | actions = ["sts:AssumeRole"] 158 | principals { 159 | type = "Service" 160 | identifiers = ["ecs.amazonaws.com"] 161 | } 162 | } 163 | } 164 | 165 | resource "aws_iam_role" "ecs_role" { 166 | name = "ecs_role" 167 | assume_role_policy = "${data.aws_iam_policy_document.ecs_service_role.json}" 168 | } 169 | 170 | data "aws_iam_policy_document" "ecs_service_policy" { 171 | statement { 172 | effect = "Allow" 173 | resources = ["*"] 174 | actions = [ 175 | "elasticloadbalancing:Describe*", 176 | "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", 177 | "elasticloadbalancing:RegisterInstancesWithLoadBalancer", 178 | "ec2:Describe*", 179 | "ec2:AuthorizeSecurityGroupIngress" 180 | ] 181 | } 182 | } 183 | 184 | /* ecs service scheduler role */ 185 | resource "aws_iam_role_policy" "ecs_service_role_policy" { 186 | name = "ecs_service_role_policy" 187 | #policy = "${file("${path.module}/policies/ecs-service-role.json")}" 188 | policy = "${data.aws_iam_policy_document.ecs_service_policy.json}" 189 | role = "${aws_iam_role.ecs_role.id}" 190 | } 191 | 192 | /* role that the Amazon ECS container agent and the Docker daemon can assume */ 193 | resource "aws_iam_role" "ecs_execution_role" { 194 | name = "ecs_task_execution_role" 195 | assume_role_policy = "${file("${path.module}/policies/ecs-task-execution-role.json")}" 196 | } 197 | resource "aws_iam_role_policy" "ecs_execution_role_policy" { 198 | name = "ecs_execution_role_policy" 199 | policy = "${file("${path.module}/policies/ecs-execution-role-policy.json")}" 200 | role = "${aws_iam_role.ecs_execution_role.id}" 201 | } 202 | 203 | /*==== 204 | ECS service 205 | ======*/ 206 | 207 | /* Security Group for ECS */ 208 | resource "aws_security_group" "ecs_service" { 209 | vpc_id = "${var.vpc_id}" 210 | name = "${var.environment}-ecs-service-sg" 211 | description = "Allow egress from container" 212 | 213 | egress { 214 | from_port = 0 215 | to_port = 0 216 | protocol = "-1" 217 | cidr_blocks = ["0.0.0.0/0"] 218 | } 219 | 220 | ingress { 221 | from_port = 8 222 | to_port = 0 223 | protocol = "icmp" 224 | cidr_blocks = ["0.0.0.0/0"] 225 | } 226 | 227 | tags { 228 | Name = "${var.environment}-ecs-service-sg" 229 | Environment = "${var.environment}" 230 | } 231 | } 232 | 233 | /* Simply specify the family to find the latest ACTIVE revision in that family */ 234 | data "aws_ecs_task_definition" "web" { 235 | task_definition = "${aws_ecs_task_definition.web.family}" 236 | depends_on = [ "aws_ecs_task_definition.web" ] 237 | } 238 | 239 | resource "aws_ecs_service" "web" { 240 | name = "${var.environment}-web" 241 | task_definition = "${aws_ecs_task_definition.web.family}:${max("${aws_ecs_task_definition.web.revision}", "${data.aws_ecs_task_definition.web.revision}")}" 242 | desired_count = 2 243 | launch_type = "FARGATE" 244 | cluster = "${aws_ecs_cluster.cluster.id}" 245 | depends_on = ["aws_iam_role_policy.ecs_service_role_policy"] 246 | 247 | network_configuration { 248 | security_groups = ["${var.security_groups_ids}", "${aws_security_group.ecs_service.id}"] 249 | subnets = ["${var.subnets_ids}"] 250 | } 251 | 252 | load_balancer { 253 | target_group_arn = "${aws_alb_target_group.alb_target_group.arn}" 254 | container_name = "web" 255 | container_port = "80" 256 | } 257 | 258 | depends_on = ["aws_alb_target_group.alb_target_group"] 259 | } 260 | 261 | 262 | /*==== 263 | Auto Scaling for ECS 264 | ======*/ 265 | 266 | resource "aws_iam_role" "ecs_autoscale_role" { 267 | name = "${var.environment}_ecs_autoscale_role" 268 | assume_role_policy = "${file("${path.module}/policies/ecs-autoscale-role.json")}" 269 | } 270 | resource "aws_iam_role_policy" "ecs_autoscale_role_policy" { 271 | name = "ecs_autoscale_role_policy" 272 | policy = "${file("${path.module}/policies/ecs-autoscale-role-policy.json")}" 273 | role = "${aws_iam_role.ecs_autoscale_role.id}" 274 | } 275 | 276 | resource "aws_appautoscaling_target" "target" { 277 | service_namespace = "ecs" 278 | resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}" 279 | scalable_dimension = "ecs:service:DesiredCount" 280 | role_arn = "${aws_iam_role.ecs_autoscale_role.arn}" 281 | min_capacity = 2 282 | max_capacity = 4 283 | } 284 | 285 | resource "aws_appautoscaling_policy" "up" { 286 | name = "${var.environment}_scale_up" 287 | service_namespace = "ecs" 288 | resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}" 289 | scalable_dimension = "ecs:service:DesiredCount" 290 | 291 | 292 | step_scaling_policy_configuration { 293 | adjustment_type = "ChangeInCapacity" 294 | cooldown = 60 295 | metric_aggregation_type = "Maximum" 296 | 297 | step_adjustment { 298 | metric_interval_lower_bound = 0 299 | scaling_adjustment = 1 300 | } 301 | } 302 | 303 | depends_on = ["aws_appautoscaling_target.target"] 304 | } 305 | 306 | resource "aws_appautoscaling_policy" "down" { 307 | name = "${var.environment}_scale_down" 308 | service_namespace = "ecs" 309 | resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}" 310 | scalable_dimension = "ecs:service:DesiredCount" 311 | 312 | step_scaling_policy_configuration { 313 | adjustment_type = "ChangeInCapacity" 314 | cooldown = 60 315 | metric_aggregation_type = "Maximum" 316 | 317 | step_adjustment { 318 | metric_interval_lower_bound = 0 319 | scaling_adjustment = -1 320 | } 321 | } 322 | 323 | depends_on = ["aws_appautoscaling_target.target"] 324 | } 325 | 326 | /* metric used for auto scale */ 327 | resource "aws_cloudwatch_metric_alarm" "service_cpu_high" { 328 | alarm_name = "${var.environment}_openjobs_web_cpu_utilization_high" 329 | comparison_operator = "GreaterThanOrEqualToThreshold" 330 | evaluation_periods = "2" 331 | metric_name = "CPUUtilization" 332 | namespace = "AWS/ECS" 333 | period = "60" 334 | statistic = "Maximum" 335 | threshold = "85" 336 | 337 | dimensions { 338 | ClusterName = "${aws_ecs_cluster.cluster.name}" 339 | ServiceName = "${aws_ecs_service.web.name}" 340 | } 341 | 342 | alarm_actions = ["${aws_appautoscaling_policy.up.arn}"] 343 | ok_actions = ["${aws_appautoscaling_policy.down.arn}"] 344 | } 345 | -------------------------------------------------------------------------------- /modules/ecs/outputs.tf: -------------------------------------------------------------------------------- 1 | output "repository_url" { 2 | value = "${aws_ecr_repository.openjobs_app.repository_url}" 3 | } 4 | 5 | output "cluster_name" { 6 | value = "${aws_ecs_cluster.cluster.name}" 7 | } 8 | 9 | output "service_name" { 10 | value = "${aws_ecs_service.web.name}" 11 | } 12 | 13 | output "alb_dns_name" { 14 | value = "${aws_alb.alb_openjobs.dns_name}" 15 | } 16 | 17 | output "alb_zone_id" { 18 | value = "${aws_alb.alb_openjobs.zone_id}" 19 | } 20 | 21 | output "security_group_id" { 22 | value = "${aws_security_group.ecs_service.id}" 23 | } 24 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-autoscale-role-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "ecs:DescribeServices", 8 | "ecs:UpdateService" 9 | ], 10 | "Resource": [ 11 | "*" 12 | ] 13 | }, 14 | { 15 | "Effect": "Allow", 16 | "Action": [ 17 | "cloudwatch:DescribeAlarms" 18 | ], 19 | "Resource": [ 20 | "*" 21 | ] 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-autoscale-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Service": "application-autoscaling.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRole" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-execution-role-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "ecr:GetAuthorizationToken", 8 | "ecr:BatchCheckLayerAvailability", 9 | "ecr:GetDownloadUrlForLayer", 10 | "ecr:BatchGetImage", 11 | "logs:CreateLogStream", 12 | "logs:PutLogEvents" 13 | ], 14 | "Resource": "*" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2008-10-17", 3 | "Statement": [ 4 | { 5 | "Action": "sts:AssumeRole", 6 | "Principal": { 7 | "Service": ["ecs.amazonaws.com", "ec2.amazonaws.com"] 8 | }, 9 | "Effect": "Allow" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-service-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "elasticloadbalancing:Describe*", 8 | "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", 9 | "elasticloadbalancing:RegisterInstancesWithLoadBalancer", 10 | "ec2:Describe*", 11 | "ec2:AuthorizeSecurityGroupIngress" 12 | ], 13 | "Resource": [ 14 | "*" 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /modules/ecs/policies/ecs-task-execution-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "", 6 | "Effect": "Allow", 7 | "Principal": { 8 | "Service": "ecs-tasks.amazonaws.com" 9 | }, 10 | "Action": "sts:AssumeRole" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /modules/ecs/tasks/db_migrate_task_definition.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "db-migrate", 4 | "image": "${image}", 5 | "command": ["bundle", "exec", "rake", "db:migrate"], 6 | "memory": 300, 7 | "logConfiguration": { 8 | "logDriver": "awslogs", 9 | "options": { 10 | "awslogs-group": "${log_group}", 11 | "awslogs-region": "us-east-1", 12 | "awslogs-stream-prefix": "db_migrate" 13 | } 14 | }, 15 | "environment": [ 16 | { 17 | "name": "RAILS_ENV", 18 | "value": "production" 19 | }, 20 | { 21 | "name": "DATABASE_URL", 22 | "value": "${database_url}" 23 | }, 24 | { 25 | "name": "SECRET_KEY_BASE", 26 | "value": "${secret_key_base}" 27 | }, 28 | { 29 | "name": "RAILS_LOG_TO_STDOUT", 30 | "value": "true" 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /modules/ecs/tasks/web_task_definition.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "web", 4 | "image": "${image}", 5 | "portMappings": [ 6 | { 7 | "containerPort": 80, 8 | "hostPort": 80 9 | } 10 | ], 11 | "memory": 300, 12 | "networkMode": "awsvpc", 13 | "logConfiguration": { 14 | "logDriver": "awslogs", 15 | "options": { 16 | "awslogs-group": "${log_group}", 17 | "awslogs-region": "us-east-1", 18 | "awslogs-stream-prefix": "web" 19 | } 20 | }, 21 | "environment": [ 22 | { 23 | "name": "RAILS_ENV", 24 | "value": "production" 25 | }, 26 | { 27 | "name": "DATABASE_URL", 28 | "value": "${database_url}" 29 | }, 30 | { 31 | "name": "SECRET_KEY_BASE", 32 | "value": "${secret_key_base}" 33 | }, 34 | { 35 | "name": "PORT", 36 | "value": "80" 37 | }, 38 | { 39 | "name": "RAILS_LOG_TO_STDOUT", 40 | "value": "true" 41 | }, 42 | { 43 | "name": "RAILS_SERVE_STATIC_FILES", 44 | "value": "true" 45 | } 46 | ] 47 | } 48 | ] 49 | 50 | -------------------------------------------------------------------------------- /modules/ecs/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | description = "The environment" 3 | } 4 | 5 | variable "vpc_id" { 6 | description = "The VPC id" 7 | } 8 | 9 | variable "availability_zones" { 10 | type = "list" 11 | description = "The azs to use" 12 | } 13 | 14 | variable "security_groups_ids" { 15 | type = "list" 16 | description = "The SGs to use" 17 | } 18 | 19 | variable "subnets_ids" { 20 | type = "list" 21 | description = "The private subnets to use" 22 | } 23 | 24 | variable "public_subnet_ids" { 25 | type = "list" 26 | description = "The private subnets to use" 27 | } 28 | 29 | variable "database_endpoint" { 30 | description = "The database endpoint" 31 | } 32 | 33 | variable "database_username" { 34 | description = "The database username" 35 | } 36 | 37 | variable "database_password" { 38 | description = "The database password" 39 | } 40 | 41 | variable "database_name" { 42 | description = "The database that the app will use" 43 | } 44 | 45 | variable "repository_name" { 46 | description = "The name of the repisitory" 47 | } 48 | 49 | variable "secret_key_base" { 50 | description = "The secret key base to use in the app" 51 | } 52 | -------------------------------------------------------------------------------- /modules/networking/main.tf: -------------------------------------------------------------------------------- 1 | /*==== 2 | The VPC 3 | ======*/ 4 | 5 | resource "aws_vpc" "vpc" { 6 | cidr_block = "${var.vpc_cidr}" 7 | enable_dns_hostnames = true 8 | enable_dns_support = true 9 | 10 | tags { 11 | Name = "${var.environment}-vpc" 12 | Environment = "${var.environment}" 13 | } 14 | } 15 | 16 | /*==== 17 | Subnets 18 | ======*/ 19 | /* Internet gateway for the public subnet */ 20 | resource "aws_internet_gateway" "ig" { 21 | vpc_id = "${aws_vpc.vpc.id}" 22 | 23 | tags { 24 | Name = "${var.environment}-igw" 25 | Environment = "${var.environment}" 26 | } 27 | } 28 | 29 | 30 | /* Elastic IP for NAT */ 31 | resource "aws_eip" "nat_eip" { 32 | vpc = true 33 | depends_on = ["aws_internet_gateway.ig"] 34 | } 35 | 36 | /* NAT */ 37 | resource "aws_nat_gateway" "nat" { 38 | allocation_id = "${aws_eip.nat_eip.id}" 39 | subnet_id = "${element(aws_subnet.public_subnet.*.id, 0)}" 40 | depends_on = ["aws_internet_gateway.ig"] 41 | 42 | tags { 43 | Name = "${var.environment}-${element(var.availability_zones, count.index)}-nat" 44 | Environment = "${var.environment}" 45 | } 46 | } 47 | 48 | /* Public subnet */ 49 | resource "aws_subnet" "public_subnet" { 50 | vpc_id = "${aws_vpc.vpc.id}" 51 | count = "${length(var.public_subnets_cidr)}" 52 | cidr_block = "${element(var.public_subnets_cidr, count.index)}" 53 | availability_zone = "${element(var.availability_zones, count.index)}" 54 | map_public_ip_on_launch = true 55 | 56 | tags { 57 | Name = "${var.environment}-${element(var.availability_zones, count.index)}-public-subnet" 58 | Environment = "${var.environment}" 59 | } 60 | } 61 | 62 | /* Private subnet */ 63 | resource "aws_subnet" "private_subnet" { 64 | vpc_id = "${aws_vpc.vpc.id}" 65 | count = "${length(var.private_subnets_cidr)}" 66 | cidr_block = "${element(var.private_subnets_cidr, count.index)}" 67 | availability_zone = "${element(var.availability_zones, count.index)}" 68 | map_public_ip_on_launch = false 69 | 70 | tags { 71 | Name = "${var.environment}-${element(var.availability_zones, count.index)}-private-subnet" 72 | Environment = "${var.environment}" 73 | } 74 | } 75 | 76 | /* Routing table for private subnet */ 77 | resource "aws_route_table" "private" { 78 | vpc_id = "${aws_vpc.vpc.id}" 79 | 80 | tags { 81 | Name = "${var.environment}-private-route-table" 82 | Environment = "${var.environment}" 83 | } 84 | } 85 | 86 | /* Routing table for public subnet */ 87 | resource "aws_route_table" "public" { 88 | vpc_id = "${aws_vpc.vpc.id}" 89 | 90 | tags { 91 | Name = "${var.environment}-public-route-table" 92 | Environment = "${var.environment}" 93 | } 94 | } 95 | 96 | resource "aws_route" "public_internet_gateway" { 97 | route_table_id = "${aws_route_table.public.id}" 98 | destination_cidr_block = "0.0.0.0/0" 99 | gateway_id = "${aws_internet_gateway.ig.id}" 100 | } 101 | 102 | resource "aws_route" "private_nat_gateway" { 103 | route_table_id = "${aws_route_table.private.id}" 104 | destination_cidr_block = "0.0.0.0/0" 105 | nat_gateway_id = "${aws_nat_gateway.nat.id}" 106 | } 107 | 108 | /* Route table associations */ 109 | resource "aws_route_table_association" "public" { 110 | count = "${length(var.public_subnets_cidr)}" 111 | subnet_id = "${element(aws_subnet.public_subnet.*.id, count.index)}" 112 | route_table_id = "${aws_route_table.public.id}" 113 | } 114 | 115 | resource "aws_route_table_association" "private" { 116 | count = "${length(var.private_subnets_cidr)}" 117 | subnet_id = "${element(aws_subnet.private_subnet.*.id, count.index)}" 118 | route_table_id = "${aws_route_table.private.id}" 119 | } 120 | 121 | /*==== 122 | VPC's Default Security Group 123 | ======*/ 124 | resource "aws_security_group" "default" { 125 | name = "${var.environment}-default-sg" 126 | description = "Default security group to allow inbound/outbound from the VPC" 127 | vpc_id = "${aws_vpc.vpc.id}" 128 | depends_on = ["aws_vpc.vpc"] 129 | 130 | ingress { 131 | from_port = "0" 132 | to_port = "0" 133 | protocol = "-1" 134 | self = true 135 | } 136 | 137 | egress { 138 | from_port = "0" 139 | to_port = "0" 140 | protocol = "-1" 141 | self = "true" 142 | } 143 | 144 | tags { 145 | Environment = "${var.environment}" 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /modules/networking/output.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | value = "${aws_vpc.vpc.id}" 3 | } 4 | 5 | output "public_subnets_id" { 6 | value = ["${aws_subnet.public_subnet.*.id}"] 7 | } 8 | 9 | output "private_subnets_id" { 10 | value = ["${aws_subnet.private_subnet.*.id}"] 11 | } 12 | 13 | output "default_sg_id" { 14 | value = "${aws_security_group.default.id}" 15 | } 16 | 17 | output "security_groups_ids" { 18 | value = ["${aws_security_group.default.id}"] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /modules/networking/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_cidr" { 2 | description = "The CIDR block of the vpc" 3 | } 4 | 5 | variable "public_subnets_cidr" { 6 | type = "list" 7 | description = "The CIDR block for the public subnet" 8 | } 9 | 10 | variable "private_subnets_cidr" { 11 | type = "list" 12 | description = "The CIDR block for the private subnet" 13 | } 14 | 15 | variable "environment" { 16 | description = "The environment" 17 | } 18 | 19 | variable "region" { 20 | description = "The region to launch the bastion host" 21 | } 22 | 23 | variable "availability_zones" { 24 | type = "list" 25 | description = "The az that the resources will be launched" 26 | } 27 | 28 | variable "key_name" { 29 | description = "The public key for the bastion host" 30 | } 31 | -------------------------------------------------------------------------------- /modules/rds/main.tf: -------------------------------------------------------------------------------- 1 | /*==== 2 | RDS 3 | ======*/ 4 | 5 | /* subnet used by rds */ 6 | resource "aws_db_subnet_group" "rds_subnet_group" { 7 | name = "${var.environment}-rds-subnet-group" 8 | description = "RDS subnet group" 9 | subnet_ids = ["${var.subnet_ids}"] 10 | tags { 11 | Environment = "${var.environment}" 12 | } 13 | } 14 | 15 | /* Security Group for resources that want to access the Database */ 16 | resource "aws_security_group" "db_access_sg" { 17 | vpc_id = "${var.vpc_id}" 18 | name = "${var.environment}-db-access-sg" 19 | description = "Allow access to RDS" 20 | 21 | tags { 22 | Name = "${var.environment}-db-access-sg" 23 | Environment = "${var.environment}" 24 | } 25 | } 26 | 27 | resource "aws_security_group" "rds_sg" { 28 | name = "${var.environment}-rds-sg" 29 | description = "${var.environment} Security Group" 30 | vpc_id = "${var.vpc_id}" 31 | tags { 32 | Name = "${var.environment}-rds-sg" 33 | Environment = "${var.environment}" 34 | } 35 | 36 | // allows traffic from the SG itself 37 | ingress { 38 | from_port = 0 39 | to_port = 0 40 | protocol = "-1" 41 | self = true 42 | } 43 | 44 | //allow traffic for TCP 5432 45 | ingress { 46 | from_port = 5432 47 | to_port = 5432 48 | protocol = "tcp" 49 | security_groups = ["${aws_security_group.db_access_sg.id}"] 50 | } 51 | 52 | // outbound internet access 53 | egress { 54 | from_port = 0 55 | to_port = 0 56 | protocol = "-1" 57 | cidr_blocks = ["0.0.0.0/0"] 58 | } 59 | } 60 | 61 | resource "aws_db_instance" "rds" { 62 | identifier = "${var.environment}-database" 63 | allocated_storage = "${var.allocated_storage}" 64 | engine = "postgres" 65 | engine_version = "9.6.6" 66 | instance_class = "${var.instance_class}" 67 | multi_az = "${var.multi_az}" 68 | name = "${var.database_name}" 69 | username = "${var.database_username}" 70 | password = "${var.database_password}" 71 | db_subnet_group_name = "${aws_db_subnet_group.rds_subnet_group.id}" 72 | vpc_security_group_ids = ["${aws_security_group.rds_sg.id}"] 73 | skip_final_snapshot = true 74 | #snapshot_identifier = "rds-${var.environment}-snapshot" 75 | tags { 76 | Environment = "${var.environment}" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /modules/rds/output.tf: -------------------------------------------------------------------------------- 1 | output "rds_address" { 2 | value = "${aws_db_instance.rds.address}" 3 | } 4 | 5 | output "db_access_sg_id" { 6 | value = "${aws_security_group.db_access_sg.id}" 7 | } 8 | -------------------------------------------------------------------------------- /modules/rds/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | description = "The environment" 3 | } 4 | 5 | variable "subnet_ids" { 6 | type = "list" 7 | description = "Subnet ids" 8 | } 9 | 10 | variable "vpc_id" { 11 | description = "The VPC id" 12 | } 13 | 14 | //variable "allowed_security_group_id" { 15 | // description = "The allowed security group id to connect on RDS" 16 | //} 17 | 18 | variable "allocated_storage" { 19 | default = "20" 20 | description = "The storage size in GB" 21 | } 22 | 23 | variable "instance_class" { 24 | description = "The instance type" 25 | } 26 | 27 | variable "multi_az" { 28 | default = false 29 | description = "Muti-az allowed?" 30 | } 31 | 32 | variable "database_name" { 33 | description = "The database name" 34 | } 35 | 36 | variable "database_username" { 37 | description = "The username of the database" 38 | } 39 | 40 | variable "database_password" { 41 | description = "The password of the database" 42 | } 43 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "alb_dns_name" { 2 | value = "${module.ecs.alb_dns_name}" 3 | } 4 | -------------------------------------------------------------------------------- /pipeline.tf: -------------------------------------------------------------------------------- 1 | 2 | module "code_pipeline" { 3 | source = "./modules/code_pipeline" 4 | repository_url = "${module.ecs.repository_url}" 5 | region = "${var.region}" 6 | ecs_service_name = "${module.ecs.service_name}" 7 | ecs_cluster_name = "${module.ecs.cluster_name}" 8 | run_task_subnet_id = "${module.networking.private_subnets_id[0]}" 9 | run_task_security_group_ids = ["${module.rds.db_access_sg_id}", "${module.networking.security_groups_ids}", "${module.ecs.security_group_id}"] 10 | } 11 | -------------------------------------------------------------------------------- /production.tf: -------------------------------------------------------------------------------- 1 | /*==== 2 | Variables used across all modules 3 | ======*/ 4 | locals { 5 | production_availability_zones = ["us-east-1a", "us-east-1b"] 6 | } 7 | 8 | provider "aws" { 9 | region = "${var.region}" 10 | #profile = "duduribeiro" 11 | } 12 | 13 | resource "aws_key_pair" "key" { 14 | key_name = "production_key" 15 | public_key = "${file("production_key.pub")}" 16 | } 17 | 18 | module "networking" { 19 | source = "./modules/networking" 20 | environment = "production" 21 | vpc_cidr = "10.0.0.0/16" 22 | public_subnets_cidr = ["10.0.1.0/24", "10.0.2.0/24"] 23 | private_subnets_cidr = ["10.0.10.0/24", "10.0.20.0/24"] 24 | region = "${var.region}" 25 | availability_zones = "${local.production_availability_zones}" 26 | key_name = "production_key" 27 | } 28 | 29 | module "rds" { 30 | source = "./modules/rds" 31 | environment = "production" 32 | allocated_storage = "20" 33 | database_name = "${var.production_database_name}" 34 | database_username = "${var.production_database_username}" 35 | database_password = "${var.production_database_password}" 36 | subnet_ids = ["${module.networking.private_subnets_id}"] 37 | vpc_id = "${module.networking.vpc_id}" 38 | instance_class = "db.t2.micro" 39 | } 40 | 41 | module "ecs" { 42 | source = "./modules/ecs" 43 | environment = "production" 44 | vpc_id = "${module.networking.vpc_id}" 45 | availability_zones = "${local.production_availability_zones}" 46 | repository_name = "openjobs/production" 47 | subnets_ids = ["${module.networking.private_subnets_id}"] 48 | public_subnet_ids = ["${module.networking.public_subnets_id}"] 49 | security_groups_ids = [ 50 | "${module.networking.security_groups_ids}", 51 | "${module.rds.db_access_sg_id}" 52 | ] 53 | database_endpoint = "${module.rds.rds_address}" 54 | database_name = "${var.production_database_name}" 55 | database_username = "${var.production_database_username}" 56 | database_password = "${var.production_database_password}" 57 | secret_key_base = "${var.production_secret_key_base}" 58 | } 59 | -------------------------------------------------------------------------------- /production_key.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDySaHA85axXRL25SMnHV8+DXnsGZMcy+zuQoJURDKZRkpsbo90iZgbugGtIal/6pw8voF/z/7FBJrNaZeo05kTCbqmftnDaKnqj24OlE8p5eIiiht02rXYSKQugDP7eyVK6s8iYOE9z8FhxjsfafgXBOJedhXwZj78WaRZ17P6/vp0+BgRupCWmM9otH4maN6jTHS8A4eYgketfYVk9WDo3Yvq3i+/6KYbFp6nx0kgjpwuR2zz7kRLV/IBSxFEf5TKnrhbj+DV4WFuMQjG2VjGjtnpEw6Lfz4aQ8FsAaHac2k0sbZwuG5NYEL7p+Sgx8uKp/K2CQRoGV7pgkVfj5af production_key 2 | -------------------------------------------------------------------------------- /route53.tf: -------------------------------------------------------------------------------- 1 | resource "aws_route53_delegation_set" "main" { 2 | reference_name = "DynDNS" 3 | } 4 | 5 | resource "aws_route53_zone" "primary_route" { 6 | name = "${var.domain}" 7 | delegation_set_id = "${aws_route53_delegation_set.main.id}" 8 | } 9 | 10 | resource "aws_route53_record" "www-prod" { 11 | zone_id = "${aws_route53_zone.primary_route.id}" 12 | name = "www.${var.domain}" 13 | type = "A" 14 | 15 | alias { 16 | name = "${module.ecs.alb_dns_name}" 17 | zone_id = "${module.ecs.alb_zone_id}" 18 | evaluate_target_health = true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /terraform.tfstate.backup: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "terraform_version": "0.11.2", 4 | "serial": 21, 5 | "lineage": "5c7c0514-ccd7-4ff8-acfa-da519b567c34", 6 | "modules": [ 7 | { 8 | "path": [ 9 | "root" 10 | ], 11 | "outputs": {}, 12 | "resources": { 13 | "aws_key_pair.key": { 14 | "type": "aws_key_pair", 15 | "depends_on": [], 16 | "primary": { 17 | "id": "production_key", 18 | "attributes": { 19 | "fingerprint": "1c:e1:6e:32:51:dc:48:e0:14:5f:b3:fe:73:c6:ff:ef", 20 | "id": "production_key", 21 | "key_name": "production_key", 22 | "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDySaHA85axXRL25SMnHV8+DXnsGZMcy+zuQoJURDKZRkpsbo90iZgbugGtIal/6pw8voF/z/7FBJrNaZeo05kTCbqmftnDaKnqj24OlE8p5eIiiht02rXYSKQugDP7eyVK6s8iYOE9z8FhxjsfafgXBOJedhXwZj78WaRZ17P6/vp0+BgRupCWmM9otH4maN6jTHS8A4eYgketfYVk9WDo3Yvq3i+/6KYbFp6nx0kgjpwuR2zz7kRLV/IBSxFEf5TKnrhbj+DV4WFuMQjG2VjGjtnpEw6Lfz4aQ8FsAaHac2k0sbZwuG5NYEL7p+Sgx8uKp/K2CQRoGV7pgkVfj5af production_key" 23 | }, 24 | "meta": { 25 | "schema_version": "1" 26 | }, 27 | "tainted": false 28 | }, 29 | "deposed": [], 30 | "provider": "provider.aws" 31 | }, 32 | "aws_route53_delegation_set.main": { 33 | "type": "aws_route53_delegation_set", 34 | "depends_on": [], 35 | "primary": { 36 | "id": "N1RI8P0VVZSY5D", 37 | "attributes": { 38 | "id": "N1RI8P0VVZSY5D", 39 | "name_servers.#": "4", 40 | "name_servers.0": "ns-1524.awsdns-62.org", 41 | "name_servers.1": "ns-2002.awsdns-58.co.uk", 42 | "name_servers.2": "ns-500.awsdns-62.com", 43 | "name_servers.3": "ns-563.awsdns-06.net", 44 | "reference_name": "DynDNS" 45 | }, 46 | "meta": {}, 47 | "tainted": false 48 | }, 49 | "deposed": [], 50 | "provider": "provider.aws" 51 | }, 52 | "aws_route53_record.www-prod": { 53 | "type": "aws_route53_record", 54 | "depends_on": [ 55 | "aws_route53_zone.primary_route", 56 | "module.ecs" 57 | ], 58 | "primary": { 59 | "id": "Z2DB0BHE7U5H9Y_www.ecsfargateexample.tk_A", 60 | "attributes": { 61 | "alias.#": "1", 62 | "alias.2656789336.evaluate_target_health": "true", 63 | "alias.2656789336.name": "production-alb-openjobs-651485480.us-east-1.elb.amazonaws.com", 64 | "alias.2656789336.zone_id": "Z35SXDOTRQ7X7K", 65 | "fqdn": "www.ecsfargateexample.tk", 66 | "health_check_id": "", 67 | "id": "Z2DB0BHE7U5H9Y_www.ecsfargateexample.tk_A", 68 | "name": "www.ecsfargateexample.tk", 69 | "records.#": "0", 70 | "set_identifier": "", 71 | "ttl": "0", 72 | "type": "A", 73 | "zone_id": "Z2DB0BHE7U5H9Y" 74 | }, 75 | "meta": { 76 | "schema_version": "2" 77 | }, 78 | "tainted": false 79 | }, 80 | "deposed": [], 81 | "provider": "provider.aws" 82 | }, 83 | "aws_route53_zone.primary_route": { 84 | "type": "aws_route53_zone", 85 | "depends_on": [ 86 | "aws_route53_delegation_set.main" 87 | ], 88 | "primary": { 89 | "id": "Z2DB0BHE7U5H9Y", 90 | "attributes": { 91 | "comment": "Managed by Terraform", 92 | "delegation_set_id": "N1RI8P0VVZSY5D", 93 | "force_destroy": "false", 94 | "id": "Z2DB0BHE7U5H9Y", 95 | "name": "ecsfargateexample.tk", 96 | "name_servers.#": "4", 97 | "name_servers.0": "ns-1524.awsdns-62.org", 98 | "name_servers.1": "ns-2002.awsdns-58.co.uk", 99 | "name_servers.2": "ns-500.awsdns-62.com", 100 | "name_servers.3": "ns-563.awsdns-06.net", 101 | "tags.%": "0", 102 | "zone_id": "Z2DB0BHE7U5H9Y" 103 | }, 104 | "meta": {}, 105 | "tainted": false 106 | }, 107 | "deposed": [], 108 | "provider": "provider.aws" 109 | } 110 | }, 111 | "depends_on": [] 112 | }, 113 | { 114 | "path": [ 115 | "root", 116 | "code_pipeline" 117 | ], 118 | "outputs": {}, 119 | "resources": { 120 | "aws_codebuild_project.openjobs_build": { 121 | "type": "aws_codebuild_project", 122 | "depends_on": [ 123 | "aws_iam_role.codebuild_role", 124 | "data.template_file.buildspec" 125 | ], 126 | "primary": { 127 | "id": "arn:aws:codebuild:us-east-1:757895497645:project/openjobs-codebuild", 128 | "attributes": { 129 | "artifacts.#": "1", 130 | "artifacts.2731293239.location": "", 131 | "artifacts.2731293239.name": "openjobs-codebuild", 132 | "artifacts.2731293239.namespace_type": "", 133 | "artifacts.2731293239.packaging": "NONE", 134 | "artifacts.2731293239.path": "", 135 | "artifacts.2731293239.type": "CODEPIPELINE", 136 | "build_timeout": "10", 137 | "description": "", 138 | "encryption_key": "arn:aws:kms:us-east-1:757895497645:alias/aws/s3", 139 | "environment.#": "1", 140 | "environment.2882962266.compute_type": "BUILD_GENERAL1_SMALL", 141 | "environment.2882962266.environment_variable.#": "0", 142 | "environment.2882962266.image": "aws/codebuild/docker:1.12.1", 143 | "environment.2882962266.privileged_mode": "true", 144 | "environment.2882962266.type": "LINUX_CONTAINER", 145 | "id": "arn:aws:codebuild:us-east-1:757895497645:project/openjobs-codebuild", 146 | "name": "openjobs-codebuild", 147 | "service_role": "arn:aws:iam::757895497645:role/codebuild-role", 148 | "source.#": "1", 149 | "source.3414224759.auth.#": "0", 150 | "source.3414224759.buildspec": "version: 0.2\n\nphases:\n pre_build:\n commands:\n - pip install awscli --upgrade --user\n - echo `aws --version`\n - echo Logging in to Amazon ECR...\n - $(aws ecr get-login --region us-east-1 --no-include-email)\n - REPOSITORY_URI=757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\n - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)\n - echo Entered the pre_build phase...\n build:\n commands:\n - echo Build started on `date`\n - echo Building the Docker image...\n - docker build --build-arg build_without=\"development test\" --build-arg rails_env=\"production\" -t $REPOSITORY_URI:latest .\n - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG\n post_build:\n commands:\n - echo Build completed on `date`\n - echo Pushing the Docker images...\n - docker push $REPOSITORY_URI:latest\n - docker push $REPOSITORY_URI:$IMAGE_TAG\n - echo Writing image definitions file...\n - printf '[{\"name\":\"web\",\"imageUri\":\"%s\"}]' $REPOSITORY_URI:$IMAGE_TAG \u003e imagedefinitions.json\n - echo upgrading db-migrate task definitions\n - aws ecs run-task --launch-type FARGATE --cluster production-ecs-cluster --task-definition production_db_migrate --network-configuration \"awsvpcConfiguration={subnets=[subnet-de3444f1],securityGroups=[sg-2b37fd5c,sg-34438943]}\"\nartifacts:\n files: imagedefinitions.json\n", 151 | "source.3414224759.location": "", 152 | "source.3414224759.type": "CODEPIPELINE", 153 | "tags.%": "0" 154 | }, 155 | "meta": {}, 156 | "tainted": false 157 | }, 158 | "deposed": [], 159 | "provider": "provider.aws" 160 | }, 161 | "aws_codepipeline.pipeline": { 162 | "type": "aws_codepipeline", 163 | "depends_on": [ 164 | "aws_iam_role.codepipeline_role", 165 | "aws_s3_bucket.source" 166 | ], 167 | "primary": { 168 | "id": "openjobs-pipeline", 169 | "attributes": { 170 | "arn": "arn:aws:codepipeline:us-east-1:757895497645:openjobs-pipeline", 171 | "artifact_store.#": "1", 172 | "artifact_store.0.encryption_key.#": "0", 173 | "artifact_store.0.location": "openjobs-experiment-source", 174 | "artifact_store.0.type": "S3", 175 | "id": "openjobs-pipeline", 176 | "name": "openjobs-pipeline", 177 | "role_arn": "arn:aws:iam::757895497645:role/codepipeline-role", 178 | "stage.#": "3", 179 | "stage.0.action.#": "1", 180 | "stage.0.action.0.category": "Source", 181 | "stage.0.action.0.configuration.%": "3", 182 | "stage.0.action.0.configuration.Branch": "master", 183 | "stage.0.action.0.configuration.Owner": "duduribeiro", 184 | "stage.0.action.0.configuration.Repo": "openjobs_experiment", 185 | "stage.0.action.0.input_artifacts.#": "0", 186 | "stage.0.action.0.name": "Source", 187 | "stage.0.action.0.output_artifacts.#": "1", 188 | "stage.0.action.0.output_artifacts.0": "source", 189 | "stage.0.action.0.owner": "ThirdParty", 190 | "stage.0.action.0.provider": "GitHub", 191 | "stage.0.action.0.role_arn": "", 192 | "stage.0.action.0.run_order": "1", 193 | "stage.0.action.0.version": "1", 194 | "stage.0.name": "Source", 195 | "stage.1.action.#": "1", 196 | "stage.1.action.0.category": "Build", 197 | "stage.1.action.0.configuration.%": "1", 198 | "stage.1.action.0.configuration.ProjectName": "openjobs-codebuild", 199 | "stage.1.action.0.input_artifacts.#": "1", 200 | "stage.1.action.0.input_artifacts.0": "source", 201 | "stage.1.action.0.name": "Build", 202 | "stage.1.action.0.output_artifacts.#": "1", 203 | "stage.1.action.0.output_artifacts.0": "imagedefinitions", 204 | "stage.1.action.0.owner": "AWS", 205 | "stage.1.action.0.provider": "CodeBuild", 206 | "stage.1.action.0.role_arn": "", 207 | "stage.1.action.0.run_order": "1", 208 | "stage.1.action.0.version": "1", 209 | "stage.1.name": "Build", 210 | "stage.2.action.#": "1", 211 | "stage.2.action.0.category": "Deploy", 212 | "stage.2.action.0.configuration.%": "3", 213 | "stage.2.action.0.configuration.ClusterName": "production-ecs-cluster", 214 | "stage.2.action.0.configuration.FileName": "imagedefinitions.json", 215 | "stage.2.action.0.configuration.ServiceName": "production-web", 216 | "stage.2.action.0.input_artifacts.#": "1", 217 | "stage.2.action.0.input_artifacts.0": "imagedefinitions", 218 | "stage.2.action.0.name": "Deploy", 219 | "stage.2.action.0.output_artifacts.#": "0", 220 | "stage.2.action.0.owner": "AWS", 221 | "stage.2.action.0.provider": "ECS", 222 | "stage.2.action.0.role_arn": "", 223 | "stage.2.action.0.run_order": "1", 224 | "stage.2.action.0.version": "1", 225 | "stage.2.name": "Production" 226 | }, 227 | "meta": {}, 228 | "tainted": false 229 | }, 230 | "deposed": [], 231 | "provider": "provider.aws" 232 | }, 233 | "aws_iam_role.codebuild_role": { 234 | "type": "aws_iam_role", 235 | "depends_on": [], 236 | "primary": { 237 | "id": "codebuild-role", 238 | "attributes": { 239 | "arn": "arn:aws:iam::757895497645:role/codebuild-role", 240 | "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codebuild.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}", 241 | "create_date": "2018-01-29T23:28:37Z", 242 | "force_detach_policies": "false", 243 | "id": "codebuild-role", 244 | "name": "codebuild-role", 245 | "path": "/", 246 | "unique_id": "AROAICHAQ5FCSUYX4VXQK" 247 | }, 248 | "meta": {}, 249 | "tainted": false 250 | }, 251 | "deposed": [], 252 | "provider": "provider.aws" 253 | }, 254 | "aws_iam_role.codepipeline_role": { 255 | "type": "aws_iam_role", 256 | "depends_on": [], 257 | "primary": { 258 | "id": "codepipeline-role", 259 | "attributes": { 260 | "arn": "arn:aws:iam::757895497645:role/codepipeline-role", 261 | "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codepipeline.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}", 262 | "create_date": "2018-01-29T23:28:37Z", 263 | "force_detach_policies": "false", 264 | "id": "codepipeline-role", 265 | "name": "codepipeline-role", 266 | "path": "/", 267 | "unique_id": "AROAJHWRJMZIPIHK55V3Y" 268 | }, 269 | "meta": {}, 270 | "tainted": false 271 | }, 272 | "deposed": [], 273 | "provider": "provider.aws" 274 | }, 275 | "aws_iam_role_policy.codebuild_policy": { 276 | "type": "aws_iam_role_policy", 277 | "depends_on": [ 278 | "aws_iam_role.codebuild_role", 279 | "data.template_file.codebuild_policy" 280 | ], 281 | "primary": { 282 | "id": "codebuild-role:codebuild-policy", 283 | "attributes": { 284 | "id": "codebuild-role:codebuild-policy", 285 | "name": "codebuild-policy", 286 | "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Action\": [\n \"logs:CreateLogGroup\",\n \"logs:CreateLogStream\",\n \"logs:PutLogEvents\",\n \"ecr:GetAuthorizationToken\",\n \"ecr:InitiateLayerUpload\",\n \"ecr:UploadLayerPart\",\n \"ecr:CompleteLayerUpload\",\n \"ecr:BatchCheckLayerAvailability\",\n \"ecr:PutImage\",\n \"ecs:RunTask\",\n \"iam:PassRole\"\n ]\n },\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::openjobs-experiment-source\",\n \"arn:aws:s3:::openjobs-experiment-source/*\"\n ]\n }\n ]\n}\n", 287 | "role": "codebuild-role" 288 | }, 289 | "meta": {}, 290 | "tainted": false 291 | }, 292 | "deposed": [], 293 | "provider": "provider.aws" 294 | }, 295 | "aws_iam_role_policy.codepipeline_policy": { 296 | "type": "aws_iam_role_policy", 297 | "depends_on": [ 298 | "aws_iam_role.codepipeline_role", 299 | "data.template_file.codepipeline_policy" 300 | ], 301 | "primary": { 302 | "id": "codepipeline-role:codepipeline_policy", 303 | "attributes": { 304 | "id": "codepipeline-role:codepipeline_policy", 305 | "name": "codepipeline_policy", 306 | "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::openjobs-experiment-source\",\n \"arn:aws:s3:::openjobs-experiment-source/*\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"codebuild:BatchGetBuilds\",\n \"codebuild:StartBuild\"\n ],\n \"Resource\": \"*\"\n },\n {\n \"Action\": [\n \"ecs:*\",\n \"events:DescribeRule\",\n \"events:DeleteRule\",\n \"events:ListRuleNamesByTarget\",\n \"events:ListTargetsByRule\",\n \"events:PutRule\",\n \"events:PutTargets\",\n \"events:RemoveTargets\",\n \"iam:ListAttachedRolePolicies\",\n \"iam:ListInstanceProfiles\",\n \"iam:ListRoles\",\n \"logs:CreateLogGroup\",\n \"logs:DescribeLogGroups\",\n \"logs:FilterLogEvents\"\n ],\n \"Resource\": \"*\",\n \"Effect\": \"Allow\"\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": \"ecs-tasks.amazonaws.com\"\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsInstanceRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"ec2.amazonaws.com\",\n \"ec2.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsAutoscaleRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"application-autoscaling.amazonaws.com\",\n \"application-autoscaling.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": \"iam:CreateServiceLinkedRole\",\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringLike\": {\n \"iam:AWSServiceName\": [\n \"ecs.amazonaws.com\",\n \"spot.amazonaws.com\",\n \"spotfleet.amazonaws.com\"\n ]\n }\n }\n }\n ]\n}\n", 307 | "role": "codepipeline-role" 308 | }, 309 | "meta": {}, 310 | "tainted": false 311 | }, 312 | "deposed": [], 313 | "provider": "provider.aws" 314 | }, 315 | "aws_s3_bucket.source": { 316 | "type": "aws_s3_bucket", 317 | "depends_on": [], 318 | "primary": { 319 | "id": "openjobs-experiment-source", 320 | "attributes": { 321 | "acceleration_status": "", 322 | "acl": "private", 323 | "arn": "arn:aws:s3:::openjobs-experiment-source", 324 | "bucket": "openjobs-experiment-source", 325 | "bucket_domain_name": "openjobs-experiment-source.s3.amazonaws.com", 326 | "force_destroy": "true", 327 | "hosted_zone_id": "Z3AQBSTGFYJSTF", 328 | "id": "openjobs-experiment-source", 329 | "logging.#": "0", 330 | "region": "us-east-1", 331 | "request_payer": "BucketOwner", 332 | "server_side_encryption_configuration.#": "0", 333 | "tags.%": "0", 334 | "versioning.#": "1", 335 | "versioning.0.enabled": "false", 336 | "versioning.0.mfa_delete": "false", 337 | "website.#": "0" 338 | }, 339 | "meta": {}, 340 | "tainted": false 341 | }, 342 | "deposed": [], 343 | "provider": "provider.aws" 344 | }, 345 | "data.template_file.buildspec": { 346 | "type": "template_file", 347 | "depends_on": [], 348 | "primary": { 349 | "id": "e7702248cb433806793abb9abe4a00cf364fad9c8148e6325d33919122c8932f", 350 | "attributes": { 351 | "id": "e7702248cb433806793abb9abe4a00cf364fad9c8148e6325d33919122c8932f", 352 | "rendered": "version: 0.2\n\nphases:\n pre_build:\n commands:\n - pip install awscli --upgrade --user\n - echo `aws --version`\n - echo Logging in to Amazon ECR...\n - $(aws ecr get-login --region us-east-1 --no-include-email)\n - REPOSITORY_URI=757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\n - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)\n - echo Entered the pre_build phase...\n build:\n commands:\n - echo Build started on `date`\n - echo Building the Docker image...\n - docker build --build-arg build_without=\"development test\" --build-arg rails_env=\"production\" -t $REPOSITORY_URI:latest .\n - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG\n post_build:\n commands:\n - echo Build completed on `date`\n - echo Pushing the Docker images...\n - docker push $REPOSITORY_URI:latest\n - docker push $REPOSITORY_URI:$IMAGE_TAG\n - echo Writing image definitions file...\n - printf '[{\"name\":\"web\",\"imageUri\":\"%s\"}]' $REPOSITORY_URI:$IMAGE_TAG \u003e imagedefinitions.json\n - echo upgrading db-migrate task definitions\n - aws ecs run-task --launch-type FARGATE --cluster production-ecs-cluster --task-definition production_db_migrate --network-configuration \"awsvpcConfiguration={subnets=[subnet-de3444f1],securityGroups=[sg-2b37fd5c,sg-34438943]}\"\nartifacts:\n files: imagedefinitions.json\n", 353 | "template": "version: 0.2\n\nphases:\n pre_build:\n commands:\n - pip install awscli --upgrade --user\n - echo `aws --version`\n - echo Logging in to Amazon ECR...\n - $(aws ecr get-login --region ${region} --no-include-email)\n - REPOSITORY_URI=${repository_url}\n - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)\n - echo Entered the pre_build phase...\n build:\n commands:\n - echo Build started on `date`\n - echo Building the Docker image...\n - docker build --build-arg build_without=\"development test\" --build-arg rails_env=\"production\" -t $REPOSITORY_URI:latest .\n - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG\n post_build:\n commands:\n - echo Build completed on `date`\n - echo Pushing the Docker images...\n - docker push $REPOSITORY_URI:latest\n - docker push $REPOSITORY_URI:$IMAGE_TAG\n - echo Writing image definitions file...\n - printf '[{\"name\":\"web\",\"imageUri\":\"%s\"}]' $REPOSITORY_URI:$IMAGE_TAG \u003e imagedefinitions.json\n - echo upgrading db-migrate task definitions\n - aws ecs run-task --launch-type FARGATE --cluster ${cluster_name} --task-definition production_db_migrate --network-configuration \"awsvpcConfiguration={subnets=[${subnet_id}],securityGroups=[${security_group_ids}]}\"\nartifacts:\n files: imagedefinitions.json\n", 354 | "vars.%": "5", 355 | "vars.cluster_name": "production-ecs-cluster", 356 | "vars.region": "us-east-1", 357 | "vars.repository_url": "757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production", 358 | "vars.security_group_ids": "sg-2b37fd5c,sg-34438943", 359 | "vars.subnet_id": "subnet-de3444f1" 360 | }, 361 | "meta": {}, 362 | "tainted": false 363 | }, 364 | "deposed": [], 365 | "provider": "provider.template" 366 | }, 367 | "data.template_file.codebuild_policy": { 368 | "type": "template_file", 369 | "depends_on": [ 370 | "aws_s3_bucket.source" 371 | ], 372 | "primary": { 373 | "id": "4c055009a1c510d22095df9aa79e4ae22ef6052f6fd5a4b27335c19c815dfc63", 374 | "attributes": { 375 | "id": "4c055009a1c510d22095df9aa79e4ae22ef6052f6fd5a4b27335c19c815dfc63", 376 | "rendered": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Action\": [\n \"logs:CreateLogGroup\",\n \"logs:CreateLogStream\",\n \"logs:PutLogEvents\",\n \"ecr:GetAuthorizationToken\",\n \"ecr:InitiateLayerUpload\",\n \"ecr:UploadLayerPart\",\n \"ecr:CompleteLayerUpload\",\n \"ecr:BatchCheckLayerAvailability\",\n \"ecr:PutImage\",\n \"ecs:RunTask\",\n \"iam:PassRole\"\n ]\n },\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::openjobs-experiment-source\",\n \"arn:aws:s3:::openjobs-experiment-source/*\"\n ]\n }\n ]\n}\n", 377 | "template": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Action\": [\n \"logs:CreateLogGroup\",\n \"logs:CreateLogStream\",\n \"logs:PutLogEvents\",\n \"ecr:GetAuthorizationToken\",\n \"ecr:InitiateLayerUpload\",\n \"ecr:UploadLayerPart\",\n \"ecr:CompleteLayerUpload\",\n \"ecr:BatchCheckLayerAvailability\",\n \"ecr:PutImage\",\n \"ecs:RunTask\",\n \"iam:PassRole\"\n ]\n },\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"${aws_s3_bucket_arn}\",\n \"${aws_s3_bucket_arn}/*\"\n ]\n }\n ]\n}\n", 378 | "vars.%": "1", 379 | "vars.aws_s3_bucket_arn": "arn:aws:s3:::openjobs-experiment-source" 380 | }, 381 | "meta": {}, 382 | "tainted": false 383 | }, 384 | "deposed": [], 385 | "provider": "provider.template" 386 | }, 387 | "data.template_file.codepipeline_policy": { 388 | "type": "template_file", 389 | "depends_on": [ 390 | "aws_s3_bucket.source" 391 | ], 392 | "primary": { 393 | "id": "ab9ecdafdd89d3679ee56bbe11c6c8dbd04026580dc57ff1987a66c5b4e69fa6", 394 | "attributes": { 395 | "id": "ab9ecdafdd89d3679ee56bbe11c6c8dbd04026580dc57ff1987a66c5b4e69fa6", 396 | "rendered": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"arn:aws:s3:::openjobs-experiment-source\",\n \"arn:aws:s3:::openjobs-experiment-source/*\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"codebuild:BatchGetBuilds\",\n \"codebuild:StartBuild\"\n ],\n \"Resource\": \"*\"\n },\n {\n \"Action\": [\n \"ecs:*\",\n \"events:DescribeRule\",\n \"events:DeleteRule\",\n \"events:ListRuleNamesByTarget\",\n \"events:ListTargetsByRule\",\n \"events:PutRule\",\n \"events:PutTargets\",\n \"events:RemoveTargets\",\n \"iam:ListAttachedRolePolicies\",\n \"iam:ListInstanceProfiles\",\n \"iam:ListRoles\",\n \"logs:CreateLogGroup\",\n \"logs:DescribeLogGroups\",\n \"logs:FilterLogEvents\"\n ],\n \"Resource\": \"*\",\n \"Effect\": \"Allow\"\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": \"ecs-tasks.amazonaws.com\"\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsInstanceRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"ec2.amazonaws.com\",\n \"ec2.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsAutoscaleRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"application-autoscaling.amazonaws.com\",\n \"application-autoscaling.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": \"iam:CreateServiceLinkedRole\",\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringLike\": {\n \"iam:AWSServiceName\": [\n \"ecs.amazonaws.com\",\n \"spot.amazonaws.com\",\n \"spotfleet.amazonaws.com\"\n ]\n }\n }\n }\n ]\n}\n", 397 | "template": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\":\"Allow\",\n \"Action\": [\n \"s3:GetObject\",\n \"s3:GetObjectVersion\",\n \"s3:GetBucketVersioning\",\n \"s3:List*\",\n \"s3:PutObject\"\n ],\n \"Resource\": [\n \"${aws_s3_bucket_arn}\",\n \"${aws_s3_bucket_arn}/*\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"codebuild:BatchGetBuilds\",\n \"codebuild:StartBuild\"\n ],\n \"Resource\": \"*\"\n },\n {\n \"Action\": [\n \"ecs:*\",\n \"events:DescribeRule\",\n \"events:DeleteRule\",\n \"events:ListRuleNamesByTarget\",\n \"events:ListTargetsByRule\",\n \"events:PutRule\",\n \"events:PutTargets\",\n \"events:RemoveTargets\",\n \"iam:ListAttachedRolePolicies\",\n \"iam:ListInstanceProfiles\",\n \"iam:ListRoles\",\n \"logs:CreateLogGroup\",\n \"logs:DescribeLogGroups\",\n \"logs:FilterLogEvents\"\n ],\n \"Resource\": \"*\",\n \"Effect\": \"Allow\"\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": \"ecs-tasks.amazonaws.com\"\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsInstanceRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"ec2.amazonaws.com\",\n \"ec2.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Action\": \"iam:PassRole\",\n \"Effect\": \"Allow\",\n \"Resource\": [\n \"arn:aws:iam::*:role/ecsAutoscaleRole*\"\n ],\n \"Condition\": {\n \"StringLike\": {\n \"iam:PassedToService\": [\n \"application-autoscaling.amazonaws.com\",\n \"application-autoscaling.amazonaws.com.cn\"\n ]\n }\n }\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": \"iam:CreateServiceLinkedRole\",\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringLike\": {\n \"iam:AWSServiceName\": [\n \"ecs.amazonaws.com\",\n \"spot.amazonaws.com\",\n \"spotfleet.amazonaws.com\"\n ]\n }\n }\n }\n ]\n}\n", 398 | "vars.%": "1", 399 | "vars.aws_s3_bucket_arn": "arn:aws:s3:::openjobs-experiment-source" 400 | }, 401 | "meta": {}, 402 | "tainted": false 403 | }, 404 | "deposed": [], 405 | "provider": "provider.template" 406 | } 407 | }, 408 | "depends_on": [] 409 | }, 410 | { 411 | "path": [ 412 | "root", 413 | "ecs" 414 | ], 415 | "outputs": { 416 | "alb_dns_name": { 417 | "sensitive": false, 418 | "type": "string", 419 | "value": "production-alb-openjobs-651485480.us-east-1.elb.amazonaws.com" 420 | }, 421 | "alb_zone_id": { 422 | "sensitive": false, 423 | "type": "string", 424 | "value": "Z35SXDOTRQ7X7K" 425 | }, 426 | "cluster_name": { 427 | "sensitive": false, 428 | "type": "string", 429 | "value": "production-ecs-cluster" 430 | }, 431 | "repository_url": { 432 | "sensitive": false, 433 | "type": "string", 434 | "value": "757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production" 435 | }, 436 | "service_name": { 437 | "sensitive": false, 438 | "type": "string", 439 | "value": "production-web" 440 | } 441 | }, 442 | "resources": { 443 | "aws_alb.alb_openjobs": { 444 | "type": "aws_alb", 445 | "depends_on": [ 446 | "aws_security_group.web_inbound_sg" 447 | ], 448 | "primary": { 449 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:loadbalancer/app/production-alb-openjobs/e05233787da23cb4", 450 | "attributes": { 451 | "access_logs.#": "0", 452 | "arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:loadbalancer/app/production-alb-openjobs/e05233787da23cb4", 453 | "arn_suffix": "app/production-alb-openjobs/e05233787da23cb4", 454 | "dns_name": "production-alb-openjobs-651485480.us-east-1.elb.amazonaws.com", 455 | "enable_deletion_protection": "false", 456 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:loadbalancer/app/production-alb-openjobs/e05233787da23cb4", 457 | "idle_timeout": "60", 458 | "internal": "false", 459 | "ip_address_type": "ipv4", 460 | "load_balancer_type": "application", 461 | "name": "production-alb-openjobs", 462 | "security_groups.#": "3", 463 | "security_groups.2014916961": "sg-34438943", 464 | "security_groups.569761485": "sg-2b37fd5c", 465 | "security_groups.796629976": "sg-9c36fceb", 466 | "subnets.#": "2", 467 | "subnets.1535720245": "subnet-6537474a", 468 | "subnets.2382224226": "subnet-08774e43", 469 | "tags.%": "2", 470 | "tags.Environment": "production", 471 | "tags.Name": "production-alb-openjobs", 472 | "vpc_id": "vpc-32041f4a", 473 | "zone_id": "Z35SXDOTRQ7X7K" 474 | }, 475 | "meta": { 476 | "e2bfb730-ecaa-11e6-8f88-34363bc7c4c0": { 477 | "create": 600000000000, 478 | "delete": 600000000000, 479 | "update": 600000000000 480 | } 481 | }, 482 | "tainted": false 483 | }, 484 | "deposed": [], 485 | "provider": "provider.aws" 486 | }, 487 | "aws_alb_listener.openjobs": { 488 | "type": "aws_alb_listener", 489 | "depends_on": [ 490 | "aws_alb.alb_openjobs", 491 | "aws_alb_target_group.alb_target_group" 492 | ], 493 | "primary": { 494 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:listener/app/production-alb-openjobs/e05233787da23cb4/f40e25cfcd5b6579", 495 | "attributes": { 496 | "arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:listener/app/production-alb-openjobs/e05233787da23cb4/f40e25cfcd5b6579", 497 | "default_action.#": "1", 498 | "default_action.0.target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 499 | "default_action.0.type": "forward", 500 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:listener/app/production-alb-openjobs/e05233787da23cb4/f40e25cfcd5b6579", 501 | "load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:loadbalancer/app/production-alb-openjobs/e05233787da23cb4", 502 | "port": "80", 503 | "protocol": "HTTP", 504 | "ssl_policy": "" 505 | }, 506 | "meta": {}, 507 | "tainted": false 508 | }, 509 | "deposed": [], 510 | "provider": "provider.aws" 511 | }, 512 | "aws_alb_target_group.alb_target_group": { 513 | "type": "aws_alb_target_group", 514 | "depends_on": [ 515 | "random_id.target_group_sufix" 516 | ], 517 | "primary": { 518 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 519 | "attributes": { 520 | "arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 521 | "arn_suffix": "targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 522 | "deregistration_delay": "300", 523 | "health_check.#": "1", 524 | "health_check.0.healthy_threshold": "5", 525 | "health_check.0.interval": "30", 526 | "health_check.0.matcher": "200", 527 | "health_check.0.path": "/", 528 | "health_check.0.port": "traffic-port", 529 | "health_check.0.protocol": "HTTP", 530 | "health_check.0.timeout": "5", 531 | "health_check.0.unhealthy_threshold": "2", 532 | "id": "arn:aws:elasticloadbalancing:us-east-1:757895497645:targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 533 | "name": "production-alb-target-group-f14c", 534 | "port": "80", 535 | "protocol": "HTTP", 536 | "stickiness.#": "1", 537 | "stickiness.0.cookie_duration": "86400", 538 | "stickiness.0.enabled": "false", 539 | "stickiness.0.type": "lb_cookie", 540 | "tags.%": "0", 541 | "target_type": "ip", 542 | "vpc_id": "vpc-32041f4a" 543 | }, 544 | "meta": {}, 545 | "tainted": false 546 | }, 547 | "deposed": [], 548 | "provider": "provider.aws" 549 | }, 550 | "aws_appautoscaling_policy.down": { 551 | "type": "aws_appautoscaling_policy", 552 | "depends_on": [ 553 | "aws_appautoscaling_target.target", 554 | "aws_ecs_cluster.cluster", 555 | "aws_ecs_service.web" 556 | ], 557 | "primary": { 558 | "id": "production_scale_down", 559 | "attributes": { 560 | "alarms.#": "0", 561 | "arn": "arn:aws:autoscaling:us-east-1:757895497645:scalingPolicy:4b2eb401-228f-42bb-a58c-97f439ab6844:resource/ecs/service/production-ecs-cluster/production-web:policyName/production_scale_down", 562 | "id": "production_scale_down", 563 | "name": "production_scale_down", 564 | "policy_type": "StepScaling", 565 | "resource_id": "service/production-ecs-cluster/production-web", 566 | "scalable_dimension": "ecs:service:DesiredCount", 567 | "service_namespace": "ecs", 568 | "step_scaling_policy_configuration.#": "1", 569 | "step_scaling_policy_configuration.0.adjustment_type": "ChangeInCapacity", 570 | "step_scaling_policy_configuration.0.cooldown": "60", 571 | "step_scaling_policy_configuration.0.metric_aggregation_type": "Maximum", 572 | "step_scaling_policy_configuration.0.min_adjustment_magnitude": "0", 573 | "step_scaling_policy_configuration.0.step_adjustment.#": "1", 574 | "step_scaling_policy_configuration.0.step_adjustment.1330763481.metric_interval_lower_bound": "0", 575 | "step_scaling_policy_configuration.0.step_adjustment.1330763481.metric_interval_upper_bound": "-1", 576 | "step_scaling_policy_configuration.0.step_adjustment.1330763481.scaling_adjustment": "-1", 577 | "target_tracking_scaling_policy_configuration.#": "0" 578 | }, 579 | "meta": {}, 580 | "tainted": false 581 | }, 582 | "deposed": [], 583 | "provider": "provider.aws" 584 | }, 585 | "aws_appautoscaling_policy.up": { 586 | "type": "aws_appautoscaling_policy", 587 | "depends_on": [ 588 | "aws_appautoscaling_target.target", 589 | "aws_ecs_cluster.cluster", 590 | "aws_ecs_service.web" 591 | ], 592 | "primary": { 593 | "id": "production_scale_up", 594 | "attributes": { 595 | "alarms.#": "0", 596 | "arn": "arn:aws:autoscaling:us-east-1:757895497645:scalingPolicy:4b2eb401-228f-42bb-a58c-97f439ab6844:resource/ecs/service/production-ecs-cluster/production-web:policyName/production_scale_up", 597 | "id": "production_scale_up", 598 | "name": "production_scale_up", 599 | "policy_type": "StepScaling", 600 | "resource_id": "service/production-ecs-cluster/production-web", 601 | "scalable_dimension": "ecs:service:DesiredCount", 602 | "service_namespace": "ecs", 603 | "step_scaling_policy_configuration.#": "1", 604 | "step_scaling_policy_configuration.0.adjustment_type": "ChangeInCapacity", 605 | "step_scaling_policy_configuration.0.cooldown": "60", 606 | "step_scaling_policy_configuration.0.metric_aggregation_type": "Maximum", 607 | "step_scaling_policy_configuration.0.min_adjustment_magnitude": "0", 608 | "step_scaling_policy_configuration.0.step_adjustment.#": "1", 609 | "step_scaling_policy_configuration.0.step_adjustment.2280411133.metric_interval_lower_bound": "0", 610 | "step_scaling_policy_configuration.0.step_adjustment.2280411133.metric_interval_upper_bound": "-1", 611 | "step_scaling_policy_configuration.0.step_adjustment.2280411133.scaling_adjustment": "1", 612 | "target_tracking_scaling_policy_configuration.#": "0" 613 | }, 614 | "meta": {}, 615 | "tainted": false 616 | }, 617 | "deposed": [], 618 | "provider": "provider.aws" 619 | }, 620 | "aws_appautoscaling_target.target": { 621 | "type": "aws_appautoscaling_target", 622 | "depends_on": [ 623 | "aws_ecs_cluster.cluster", 624 | "aws_ecs_service.web", 625 | "aws_iam_role.ecs_autoscale_role" 626 | ], 627 | "primary": { 628 | "id": "service/production-ecs-cluster/production-web", 629 | "attributes": { 630 | "id": "service/production-ecs-cluster/production-web", 631 | "max_capacity": "4", 632 | "min_capacity": "2", 633 | "resource_id": "service/production-ecs-cluster/production-web", 634 | "role_arn": "arn:aws:iam::757895497645:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService", 635 | "scalable_dimension": "ecs:service:DesiredCount", 636 | "service_namespace": "ecs" 637 | }, 638 | "meta": {}, 639 | "tainted": false 640 | }, 641 | "deposed": [], 642 | "provider": "provider.aws" 643 | }, 644 | "aws_cloudwatch_log_group.openjobs": { 645 | "type": "aws_cloudwatch_log_group", 646 | "depends_on": [], 647 | "primary": { 648 | "id": "openjobs", 649 | "attributes": { 650 | "arn": "arn:aws:logs:us-east-1:757895497645:log-group:openjobs:*", 651 | "id": "openjobs", 652 | "kms_key_id": "", 653 | "name": "openjobs", 654 | "retention_in_days": "0", 655 | "tags.%": "2", 656 | "tags.Application": "OpenJobs", 657 | "tags.Environment": "production" 658 | }, 659 | "meta": {}, 660 | "tainted": false 661 | }, 662 | "deposed": [], 663 | "provider": "provider.aws" 664 | }, 665 | "aws_cloudwatch_metric_alarm.service_cpu_high": { 666 | "type": "aws_cloudwatch_metric_alarm", 667 | "depends_on": [ 668 | "aws_appautoscaling_policy.down", 669 | "aws_appautoscaling_policy.up", 670 | "aws_ecs_cluster.cluster", 671 | "aws_ecs_service.web" 672 | ], 673 | "primary": { 674 | "id": "production_openjobs_web_cpu_utilization_high", 675 | "attributes": { 676 | "actions_enabled": "true", 677 | "alarm_actions.#": "1", 678 | "alarm_actions.2876257399": "arn:aws:autoscaling:us-east-1:757895497645:scalingPolicy:4b2eb401-228f-42bb-a58c-97f439ab6844:resource/ecs/service/production-ecs-cluster/production-web:policyName/production_scale_up", 679 | "alarm_description": "", 680 | "alarm_name": "production_openjobs_web_cpu_utilization_high", 681 | "comparison_operator": "GreaterThanOrEqualToThreshold", 682 | "datapoints_to_alarm": "0", 683 | "dimensions.%": "2", 684 | "dimensions.ClusterName": "production-ecs-cluster", 685 | "dimensions.ServiceName": "production-web", 686 | "evaluate_low_sample_count_percentiles": "", 687 | "evaluation_periods": "2", 688 | "extended_statistic": "", 689 | "id": "production_openjobs_web_cpu_utilization_high", 690 | "insufficient_data_actions.#": "0", 691 | "metric_name": "CPUUtilization", 692 | "namespace": "AWS/ECS", 693 | "ok_actions.#": "1", 694 | "ok_actions.901305810": "arn:aws:autoscaling:us-east-1:757895497645:scalingPolicy:4b2eb401-228f-42bb-a58c-97f439ab6844:resource/ecs/service/production-ecs-cluster/production-web:policyName/production_scale_down", 695 | "period": "60", 696 | "statistic": "Maximum", 697 | "threshold": "85", 698 | "treat_missing_data": "missing", 699 | "unit": "" 700 | }, 701 | "meta": { 702 | "schema_version": "1" 703 | }, 704 | "tainted": false 705 | }, 706 | "deposed": [], 707 | "provider": "provider.aws" 708 | }, 709 | "aws_ecr_repository.openjobs_app": { 710 | "type": "aws_ecr_repository", 711 | "depends_on": [], 712 | "primary": { 713 | "id": "openjobs/production", 714 | "attributes": { 715 | "arn": "arn:aws:ecr:us-east-1:757895497645:repository/openjobs/production", 716 | "id": "openjobs/production", 717 | "name": "openjobs/production", 718 | "registry_id": "757895497645", 719 | "repository_url": "757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production" 720 | }, 721 | "meta": {}, 722 | "tainted": false 723 | }, 724 | "deposed": [], 725 | "provider": "provider.aws" 726 | }, 727 | "aws_ecs_cluster.cluster": { 728 | "type": "aws_ecs_cluster", 729 | "depends_on": [], 730 | "primary": { 731 | "id": "arn:aws:ecs:us-east-1:757895497645:cluster/production-ecs-cluster", 732 | "attributes": { 733 | "arn": "arn:aws:ecs:us-east-1:757895497645:cluster/production-ecs-cluster", 734 | "id": "arn:aws:ecs:us-east-1:757895497645:cluster/production-ecs-cluster", 735 | "name": "production-ecs-cluster" 736 | }, 737 | "meta": {}, 738 | "tainted": false 739 | }, 740 | "deposed": [], 741 | "provider": "provider.aws" 742 | }, 743 | "aws_ecs_service.web": { 744 | "type": "aws_ecs_service", 745 | "depends_on": [ 746 | "aws_alb_target_group.alb_target_group", 747 | "aws_ecs_cluster.cluster", 748 | "aws_ecs_task_definition.web", 749 | "aws_iam_role_policy.ecs_service_role_policy", 750 | "aws_security_group.ecs_service", 751 | "data.aws_ecs_task_definition.web" 752 | ], 753 | "primary": { 754 | "id": "arn:aws:ecs:us-east-1:757895497645:service/production-web", 755 | "attributes": { 756 | "cluster": "arn:aws:ecs:us-east-1:757895497645:cluster/production-ecs-cluster", 757 | "deployment_maximum_percent": "200", 758 | "deployment_minimum_healthy_percent": "100", 759 | "desired_count": "2", 760 | "health_check_grace_period_seconds": "0", 761 | "iam_role": "aws-service-role", 762 | "id": "arn:aws:ecs:us-east-1:757895497645:service/production-web", 763 | "launch_type": "FARGATE", 764 | "load_balancer.#": "1", 765 | "load_balancer.3261201814.container_name": "web", 766 | "load_balancer.3261201814.container_port": "80", 767 | "load_balancer.3261201814.elb_name": "", 768 | "load_balancer.3261201814.target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:757895497645:targetgroup/production-alb-target-group-f14c/64f397ce227b864f", 769 | "name": "production-web", 770 | "network_configuration.#": "1", 771 | "network_configuration.0.security_groups.#": "3", 772 | "network_configuration.0.security_groups.2014916961": "sg-34438943", 773 | "network_configuration.0.security_groups.3119024256": "sg-ab4983dc", 774 | "network_configuration.0.security_groups.569761485": "sg-2b37fd5c", 775 | "network_configuration.0.subnets.#": "2", 776 | "network_configuration.0.subnets.3113454962": "subnet-30625b7b", 777 | "network_configuration.0.subnets.3378482322": "subnet-de3444f1", 778 | "placement_constraints.#": "0", 779 | "placement_strategy.#": "0", 780 | "task_definition": "production_web:17" 781 | }, 782 | "meta": {}, 783 | "tainted": false 784 | }, 785 | "deposed": [], 786 | "provider": "provider.aws" 787 | }, 788 | "aws_ecs_task_definition.db_migrate": { 789 | "type": "aws_ecs_task_definition", 790 | "depends_on": [ 791 | "aws_iam_role.ecs_execution_role", 792 | "data.template_file.db_migrate_task" 793 | ], 794 | "primary": { 795 | "id": "production_db_migrate", 796 | "attributes": { 797 | "arn": "arn:aws:ecs:us-east-1:757895497645:task-definition/production_db_migrate:3", 798 | "container_definitions": "[{\"command\":[\"bundle\",\"exec\",\"rake\",\"db:migrate\"],\"cpu\":0,\"environment\":[{\"name\":\"RAILS_LOG_TO_STDOUT\",\"value\":\"true\"},{\"name\":\"RAILS_ENV\",\"value\":\"production\"},{\"name\":\"DATABASE_URL\",\"value\":\"postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40\"},{\"name\":\"SECRET_KEY_BASE\",\"value\":\"8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e\"}],\"essential\":true,\"image\":\"757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"openjobs\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"db_migrate\"}},\"memory\":300,\"mountPoints\":[],\"name\":\"db-migrate\",\"portMappings\":[],\"volumesFrom\":[]}]", 799 | "cpu": "256", 800 | "execution_role_arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role", 801 | "family": "production_db_migrate", 802 | "id": "production_db_migrate", 803 | "memory": "512", 804 | "network_mode": "awsvpc", 805 | "placement_constraints.#": "0", 806 | "requires_compatibilities.#": "1", 807 | "requires_compatibilities.3072437307": "FARGATE", 808 | "revision": "3", 809 | "task_role_arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role" 810 | }, 811 | "meta": { 812 | "schema_version": "1" 813 | }, 814 | "tainted": false 815 | }, 816 | "deposed": [], 817 | "provider": "provider.aws" 818 | }, 819 | "aws_ecs_task_definition.web": { 820 | "type": "aws_ecs_task_definition", 821 | "depends_on": [ 822 | "aws_ecs_task_definition.web" 823 | ], 824 | "primary": { 825 | "id": "production_web", 826 | "attributes": { 827 | "arn": "arn:aws:ecs:us-east-1:757895497645:task-definition/production_web:15", 828 | "container_definitions": "[{\"cpu\":0,\"environment\":[{\"name\":\"RAILS_LOG_TO_STDOUT\",\"value\":\"true\"},{\"name\":\"RAILS_ENV\",\"value\":\"production\"},{\"name\":\"RAILS_SERVE_STATIC_FILES\",\"value\":\"true\"},{\"name\":\"DATABASE_URL\",\"value\":\"postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40\"},{\"name\":\"PORT\",\"value\":\"80\"},{\"name\":\"SECRET_KEY_BASE\",\"value\":\"8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e\"}],\"essential\":true,\"image\":\"757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\",\"logConfiguration\":{\"logDriver\":\"awslogs\",\"options\":{\"awslogs-group\":\"openjobs\",\"awslogs-region\":\"us-east-1\",\"awslogs-stream-prefix\":\"web\"}},\"memory\":300,\"mountPoints\":[],\"name\":\"web\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80,\"protocol\":\"tcp\"}],\"volumesFrom\":[]}]", 829 | "cpu": "256", 830 | "execution_role_arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role", 831 | "family": "production_web", 832 | "id": "production_web", 833 | "memory": "512", 834 | "network_mode": "awsvpc", 835 | "placement_constraints.#": "0", 836 | "requires_compatibilities.#": "1", 837 | "requires_compatibilities.3072437307": "FARGATE", 838 | "revision": "15", 839 | "task_role_arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role" 840 | }, 841 | "meta": { 842 | "schema_version": "1" 843 | }, 844 | "tainted": false 845 | }, 846 | "deposed": [], 847 | "provider": "provider.aws" 848 | }, 849 | "aws_iam_role.ecs_autoscale_role": { 850 | "type": "aws_iam_role", 851 | "depends_on": [], 852 | "primary": { 853 | "id": "production_ecs_autoscale_role", 854 | "attributes": { 855 | "arn": "arn:aws:iam::757895497645:role/production_ecs_autoscale_role", 856 | "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"application-autoscaling.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}", 857 | "create_date": "2018-01-29T23:28:37Z", 858 | "force_detach_policies": "false", 859 | "id": "production_ecs_autoscale_role", 860 | "name": "production_ecs_autoscale_role", 861 | "path": "/", 862 | "unique_id": "AROAJVPUE3QI2CNQV4IDS" 863 | }, 864 | "meta": {}, 865 | "tainted": false 866 | }, 867 | "deposed": [], 868 | "provider": "provider.aws" 869 | }, 870 | "aws_iam_role.ecs_execution_role": { 871 | "type": "aws_iam_role", 872 | "depends_on": [], 873 | "primary": { 874 | "id": "ecs_task_execution_role", 875 | "attributes": { 876 | "arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role", 877 | "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ecs-tasks.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}", 878 | "create_date": "2018-01-29T23:28:37Z", 879 | "force_detach_policies": "false", 880 | "id": "ecs_task_execution_role", 881 | "name": "ecs_task_execution_role", 882 | "path": "/", 883 | "unique_id": "AROAICQO62AXRIGA7AA4K" 884 | }, 885 | "meta": {}, 886 | "tainted": false 887 | }, 888 | "deposed": [], 889 | "provider": "provider.aws" 890 | }, 891 | "aws_iam_role.ecs_role": { 892 | "type": "aws_iam_role", 893 | "depends_on": [ 894 | "data.aws_iam_policy_document.ecs_service_role" 895 | ], 896 | "primary": { 897 | "id": "ecs_role", 898 | "attributes": { 899 | "arn": "arn:aws:iam::757895497645:role/ecs_role", 900 | "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ecs.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}", 901 | "create_date": "2018-01-29T23:28:37Z", 902 | "force_detach_policies": "false", 903 | "id": "ecs_role", 904 | "name": "ecs_role", 905 | "path": "/", 906 | "unique_id": "AROAIVPNQJFMXVLEUPUAE" 907 | }, 908 | "meta": {}, 909 | "tainted": false 910 | }, 911 | "deposed": [], 912 | "provider": "provider.aws" 913 | }, 914 | "aws_iam_role_policy.ecs_autoscale_role_policy": { 915 | "type": "aws_iam_role_policy", 916 | "depends_on": [ 917 | "aws_iam_role.ecs_autoscale_role" 918 | ], 919 | "primary": { 920 | "id": "production_ecs_autoscale_role:ecs_autoscale_role_policy", 921 | "attributes": { 922 | "id": "production_ecs_autoscale_role:ecs_autoscale_role_policy", 923 | "name": "ecs_autoscale_role_policy", 924 | "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"ecs:DescribeServices\",\n \"ecs:UpdateService\"\n ],\n \"Resource\": [\n \"*\"\n ]\n },\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"cloudwatch:DescribeAlarms\"\n ],\n \"Resource\": [\n \"*\"\n ]\n }\n ]\n}\n", 925 | "role": "production_ecs_autoscale_role" 926 | }, 927 | "meta": {}, 928 | "tainted": false 929 | }, 930 | "deposed": [], 931 | "provider": "provider.aws" 932 | }, 933 | "aws_iam_role_policy.ecs_execution_role_policy": { 934 | "type": "aws_iam_role_policy", 935 | "depends_on": [ 936 | "aws_iam_role.ecs_execution_role" 937 | ], 938 | "primary": { 939 | "id": "ecs_task_execution_role:ecs_execution_role_policy", 940 | "attributes": { 941 | "id": "ecs_task_execution_role:ecs_execution_role_policy", 942 | "name": "ecs_execution_role_policy", 943 | "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"ecr:GetAuthorizationToken\",\n \"ecr:BatchCheckLayerAvailability\",\n \"ecr:GetDownloadUrlForLayer\",\n \"ecr:BatchGetImage\",\n \"logs:CreateLogStream\",\n \"logs:PutLogEvents\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}\n", 944 | "role": "ecs_task_execution_role" 945 | }, 946 | "meta": {}, 947 | "tainted": false 948 | }, 949 | "deposed": [], 950 | "provider": "provider.aws" 951 | }, 952 | "aws_iam_role_policy.ecs_service_role_policy": { 953 | "type": "aws_iam_role_policy", 954 | "depends_on": [ 955 | "aws_iam_role.ecs_role", 956 | "data.aws_iam_policy_document.ecs_service_policy" 957 | ], 958 | "primary": { 959 | "id": "ecs_role:ecs_service_role_policy", 960 | "attributes": { 961 | "id": "ecs_role:ecs_service_role_policy", 962 | "name": "ecs_service_role_policy", 963 | "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"elasticloadbalancing:RegisterInstancesWithLoadBalancer\",\n \"elasticloadbalancing:Describe*\",\n \"elasticloadbalancing:DeregisterInstancesFromLoadBalancer\",\n \"ec2:Describe*\",\n \"ec2:AuthorizeSecurityGroupIngress\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", 964 | "role": "ecs_role" 965 | }, 966 | "meta": {}, 967 | "tainted": false 968 | }, 969 | "deposed": [], 970 | "provider": "provider.aws" 971 | }, 972 | "aws_security_group.ecs_service": { 973 | "type": "aws_security_group", 974 | "depends_on": [], 975 | "primary": { 976 | "id": "sg-ab4983dc", 977 | "attributes": { 978 | "description": "Allow egress from container", 979 | "egress.#": "1", 980 | "egress.482069346.cidr_blocks.#": "1", 981 | "egress.482069346.cidr_blocks.0": "0.0.0.0/0", 982 | "egress.482069346.description": "", 983 | "egress.482069346.from_port": "0", 984 | "egress.482069346.ipv6_cidr_blocks.#": "0", 985 | "egress.482069346.prefix_list_ids.#": "0", 986 | "egress.482069346.protocol": "-1", 987 | "egress.482069346.security_groups.#": "0", 988 | "egress.482069346.self": "false", 989 | "egress.482069346.to_port": "0", 990 | "id": "sg-ab4983dc", 991 | "ingress.#": "1", 992 | "ingress.3068409405.cidr_blocks.#": "1", 993 | "ingress.3068409405.cidr_blocks.0": "0.0.0.0/0", 994 | "ingress.3068409405.description": "", 995 | "ingress.3068409405.from_port": "8", 996 | "ingress.3068409405.ipv6_cidr_blocks.#": "0", 997 | "ingress.3068409405.protocol": "icmp", 998 | "ingress.3068409405.security_groups.#": "0", 999 | "ingress.3068409405.self": "false", 1000 | "ingress.3068409405.to_port": "0", 1001 | "name": "production-ecs-service-sg", 1002 | "owner_id": "757895497645", 1003 | "revoke_rules_on_delete": "false", 1004 | "tags.%": "2", 1005 | "tags.Environment": "production", 1006 | "tags.Name": "production-ecs-service-sg", 1007 | "vpc_id": "vpc-32041f4a" 1008 | }, 1009 | "meta": { 1010 | "schema_version": "1" 1011 | }, 1012 | "tainted": false 1013 | }, 1014 | "deposed": [], 1015 | "provider": "provider.aws" 1016 | }, 1017 | "aws_security_group.web_inbound_sg": { 1018 | "type": "aws_security_group", 1019 | "depends_on": [], 1020 | "primary": { 1021 | "id": "sg-9c36fceb", 1022 | "attributes": { 1023 | "description": "Allow HTTP from Anywhere into ALB", 1024 | "egress.#": "1", 1025 | "egress.482069346.cidr_blocks.#": "1", 1026 | "egress.482069346.cidr_blocks.0": "0.0.0.0/0", 1027 | "egress.482069346.description": "", 1028 | "egress.482069346.from_port": "0", 1029 | "egress.482069346.ipv6_cidr_blocks.#": "0", 1030 | "egress.482069346.prefix_list_ids.#": "0", 1031 | "egress.482069346.protocol": "-1", 1032 | "egress.482069346.security_groups.#": "0", 1033 | "egress.482069346.self": "false", 1034 | "egress.482069346.to_port": "0", 1035 | "id": "sg-9c36fceb", 1036 | "ingress.#": "2", 1037 | "ingress.2214680975.cidr_blocks.#": "1", 1038 | "ingress.2214680975.cidr_blocks.0": "0.0.0.0/0", 1039 | "ingress.2214680975.description": "", 1040 | "ingress.2214680975.from_port": "80", 1041 | "ingress.2214680975.ipv6_cidr_blocks.#": "0", 1042 | "ingress.2214680975.protocol": "tcp", 1043 | "ingress.2214680975.security_groups.#": "0", 1044 | "ingress.2214680975.self": "false", 1045 | "ingress.2214680975.to_port": "80", 1046 | "ingress.3068409405.cidr_blocks.#": "1", 1047 | "ingress.3068409405.cidr_blocks.0": "0.0.0.0/0", 1048 | "ingress.3068409405.description": "", 1049 | "ingress.3068409405.from_port": "8", 1050 | "ingress.3068409405.ipv6_cidr_blocks.#": "0", 1051 | "ingress.3068409405.protocol": "icmp", 1052 | "ingress.3068409405.security_groups.#": "0", 1053 | "ingress.3068409405.self": "false", 1054 | "ingress.3068409405.to_port": "0", 1055 | "name": "production-web-inbound-sg", 1056 | "owner_id": "757895497645", 1057 | "revoke_rules_on_delete": "false", 1058 | "tags.%": "1", 1059 | "tags.Name": "production-web-inbound-sg", 1060 | "vpc_id": "vpc-32041f4a" 1061 | }, 1062 | "meta": { 1063 | "schema_version": "1" 1064 | }, 1065 | "tainted": false 1066 | }, 1067 | "deposed": [], 1068 | "provider": "provider.aws" 1069 | }, 1070 | "data.aws_ecs_task_definition.web": { 1071 | "type": "aws_ecs_task_definition", 1072 | "depends_on": [ 1073 | "aws_ecs_task_definition.web" 1074 | ], 1075 | "primary": { 1076 | "id": "arn:aws:ecs:us-east-1:757895497645:task-definition/production_web:17", 1077 | "attributes": { 1078 | "family": "production_web", 1079 | "id": "arn:aws:ecs:us-east-1:757895497645:task-definition/production_web:17", 1080 | "network_mode": "awsvpc", 1081 | "revision": "17", 1082 | "status": "ACTIVE", 1083 | "task_definition": "production_web", 1084 | "task_role_arn": "arn:aws:iam::757895497645:role/ecs_task_execution_role" 1085 | }, 1086 | "meta": {}, 1087 | "tainted": false 1088 | }, 1089 | "deposed": [], 1090 | "provider": "provider.aws" 1091 | }, 1092 | "data.aws_iam_policy_document.ecs_service_policy": { 1093 | "type": "aws_iam_policy_document", 1094 | "depends_on": [], 1095 | "primary": { 1096 | "id": "3615693260", 1097 | "attributes": { 1098 | "id": "3615693260", 1099 | "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"elasticloadbalancing:RegisterInstancesWithLoadBalancer\",\n \"elasticloadbalancing:Describe*\",\n \"elasticloadbalancing:DeregisterInstancesFromLoadBalancer\",\n \"ec2:Describe*\",\n \"ec2:AuthorizeSecurityGroupIngress\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}", 1100 | "statement.#": "1", 1101 | "statement.0.actions.#": "5", 1102 | "statement.0.actions.2459212947": "ec2:Describe*", 1103 | "statement.0.actions.2464853358": "ec2:AuthorizeSecurityGroupIngress", 1104 | "statement.0.actions.2706807274": "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", 1105 | "statement.0.actions.2747799858": "elasticloadbalancing:Describe*", 1106 | "statement.0.actions.982461153": "elasticloadbalancing:RegisterInstancesWithLoadBalancer", 1107 | "statement.0.condition.#": "0", 1108 | "statement.0.effect": "Allow", 1109 | "statement.0.not_actions.#": "0", 1110 | "statement.0.not_principals.#": "0", 1111 | "statement.0.not_resources.#": "0", 1112 | "statement.0.principals.#": "0", 1113 | "statement.0.resources.#": "1", 1114 | "statement.0.resources.2679715827": "*", 1115 | "statement.0.sid": "" 1116 | }, 1117 | "meta": {}, 1118 | "tainted": false 1119 | }, 1120 | "deposed": [], 1121 | "provider": "provider.aws" 1122 | }, 1123 | "data.aws_iam_policy_document.ecs_service_role": { 1124 | "type": "aws_iam_policy_document", 1125 | "depends_on": [], 1126 | "primary": { 1127 | "id": "3622649364", 1128 | "attributes": { 1129 | "id": "3622649364", 1130 | "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"ecs.amazonaws.com\"\n }\n }\n ]\n}", 1131 | "statement.#": "1", 1132 | "statement.0.actions.#": "1", 1133 | "statement.0.actions.2528466339": "sts:AssumeRole", 1134 | "statement.0.condition.#": "0", 1135 | "statement.0.effect": "Allow", 1136 | "statement.0.not_actions.#": "0", 1137 | "statement.0.not_principals.#": "0", 1138 | "statement.0.not_resources.#": "0", 1139 | "statement.0.principals.#": "1", 1140 | "statement.0.principals.1113412664.identifiers.#": "1", 1141 | "statement.0.principals.1113412664.identifiers.1509832800": "ecs.amazonaws.com", 1142 | "statement.0.principals.1113412664.type": "Service", 1143 | "statement.0.resources.#": "0", 1144 | "statement.0.sid": "" 1145 | }, 1146 | "meta": {}, 1147 | "tainted": false 1148 | }, 1149 | "deposed": [], 1150 | "provider": "provider.aws" 1151 | }, 1152 | "data.template_file.db_migrate_task": { 1153 | "type": "template_file", 1154 | "depends_on": [ 1155 | "aws_ecr_repository.openjobs_app" 1156 | ], 1157 | "primary": { 1158 | "id": "9f8dc05fb135a66b81d1a71719cc13472331e59cb17a7ffc53e4369a00a5d974", 1159 | "attributes": { 1160 | "id": "9f8dc05fb135a66b81d1a71719cc13472331e59cb17a7ffc53e4369a00a5d974", 1161 | "rendered": "[\n {\n \"name\": \"db-migrate\",\n \"image\": \"757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\",\n \"command\": [\"bundle\", \"exec\", \"rake\", \"db:migrate\"],\n \"memory\": 300,\n \"logConfiguration\": {\n \"logDriver\": \"awslogs\",\n \"options\": {\n \"awslogs-group\": \"openjobs\",\n \"awslogs-region\": \"us-east-1\",\n \"awslogs-stream-prefix\": \"db_migrate\"\n }\n },\n \"environment\": [\n {\n \"name\": \"RAILS_ENV\",\n \"value\": \"production\"\n },\n {\n \"name\": \"DATABASE_URL\",\n \"value\": \"postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40\"\n },\n {\n \"name\": \"SECRET_KEY_BASE\",\n \"value\": \"8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e\"\n },\n {\n \"name\": \"RAILS_LOG_TO_STDOUT\",\n \"value\": \"true\"\n }\n ]\n }\n]\n", 1162 | "template": "[\n {\n \"name\": \"db-migrate\",\n \"image\": \"${image}\",\n \"command\": [\"bundle\", \"exec\", \"rake\", \"db:migrate\"],\n \"memory\": 300,\n \"logConfiguration\": {\n \"logDriver\": \"awslogs\",\n \"options\": {\n \"awslogs-group\": \"${log_group}\",\n \"awslogs-region\": \"us-east-1\",\n \"awslogs-stream-prefix\": \"db_migrate\"\n }\n },\n \"environment\": [\n {\n \"name\": \"RAILS_ENV\",\n \"value\": \"production\"\n },\n {\n \"name\": \"DATABASE_URL\",\n \"value\": \"${database_url}\"\n },\n {\n \"name\": \"SECRET_KEY_BASE\",\n \"value\": \"${secret_key_base}\"\n },\n {\n \"name\": \"RAILS_LOG_TO_STDOUT\",\n \"value\": \"true\"\n }\n ]\n }\n]\n", 1163 | "vars.%": "4", 1164 | "vars.database_url": "postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40", 1165 | "vars.image": "757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production", 1166 | "vars.log_group": "openjobs", 1167 | "vars.secret_key_base": "8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e" 1168 | }, 1169 | "meta": {}, 1170 | "tainted": false 1171 | }, 1172 | "deposed": [], 1173 | "provider": "provider.template" 1174 | }, 1175 | "data.template_file.web_task": { 1176 | "type": "template_file", 1177 | "depends_on": [ 1178 | "aws_cloudwatch_log_group.openjobs", 1179 | "aws_ecr_repository.openjobs_app" 1180 | ], 1181 | "primary": { 1182 | "id": "73682dd0b9de61124ffb2871c60782725d5be54498ef1b502df4c39d4463ab49", 1183 | "attributes": { 1184 | "id": "73682dd0b9de61124ffb2871c60782725d5be54498ef1b502df4c39d4463ab49", 1185 | "rendered": "[\n {\n \"name\": \"web\",\n \"image\": \"757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production\",\n \"portMappings\": [\n {\n \"containerPort\": 80,\n \"hostPort\": 80\n }\n ],\n \"memory\": 300,\n \"networkMode\": \"awsvpc\",\n \"logConfiguration\": {\n \"logDriver\": \"awslogs\",\n \"options\": {\n \"awslogs-group\": \"openjobs\",\n \"awslogs-region\": \"us-east-1\",\n \"awslogs-stream-prefix\": \"web\"\n }\n },\n \"environment\": [\n {\n \"name\": \"RAILS_ENV\",\n \"value\": \"production\"\n },\n {\n \"name\": \"DATABASE_URL\",\n \"value\": \"postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40\"\n },\n {\n \"name\": \"SECRET_KEY_BASE\",\n \"value\": \"8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e\"\n },\n {\n \"name\": \"PORT\",\n \"value\": \"80\"\n },\n {\n \"name\": \"RAILS_LOG_TO_STDOUT\",\n \"value\": \"true\"\n },\n {\n \"name\": \"RAILS_SERVE_STATIC_FILES\",\n \"value\": \"true\"\n }\n ]\n }\n]\n\n", 1186 | "template": "[\n {\n \"name\": \"web\",\n \"image\": \"${image}\",\n \"portMappings\": [\n {\n \"containerPort\": 80,\n \"hostPort\": 80\n }\n ],\n \"memory\": 300,\n \"networkMode\": \"awsvpc\",\n \"logConfiguration\": {\n \"logDriver\": \"awslogs\",\n \"options\": {\n \"awslogs-group\": \"${log_group}\",\n \"awslogs-region\": \"us-east-1\",\n \"awslogs-stream-prefix\": \"web\"\n }\n },\n \"environment\": [\n {\n \"name\": \"RAILS_ENV\",\n \"value\": \"production\"\n },\n {\n \"name\": \"DATABASE_URL\",\n \"value\": \"${database_url}\"\n },\n {\n \"name\": \"SECRET_KEY_BASE\",\n \"value\": \"${secret_key_base}\"\n },\n {\n \"name\": \"PORT\",\n \"value\": \"80\"\n },\n {\n \"name\": \"RAILS_LOG_TO_STDOUT\",\n \"value\": \"true\"\n },\n {\n \"name\": \"RAILS_SERVE_STATIC_FILES\",\n \"value\": \"true\"\n }\n ]\n }\n]\n\n", 1187 | "vars.%": "4", 1188 | "vars.database_url": "postgresql://openjobs:myawesomepasswordproduction@production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432/openjobs_production?encoding=utf8\u0026pool=40", 1189 | "vars.image": "757895497645.dkr.ecr.us-east-1.amazonaws.com/openjobs/production", 1190 | "vars.log_group": "openjobs", 1191 | "vars.secret_key_base": "8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e" 1192 | }, 1193 | "meta": {}, 1194 | "tainted": false 1195 | }, 1196 | "deposed": [], 1197 | "provider": "provider.template" 1198 | }, 1199 | "random_id.target_group_sufix": { 1200 | "type": "random_id", 1201 | "depends_on": [], 1202 | "primary": { 1203 | "id": "8Uw", 1204 | "attributes": { 1205 | "b64": "8Uw", 1206 | "b64_std": "8Uw=", 1207 | "b64_url": "8Uw", 1208 | "byte_length": "2", 1209 | "dec": "61772", 1210 | "hex": "f14c", 1211 | "id": "8Uw" 1212 | }, 1213 | "meta": {}, 1214 | "tainted": false 1215 | }, 1216 | "deposed": [], 1217 | "provider": "provider.random" 1218 | } 1219 | }, 1220 | "depends_on": [] 1221 | }, 1222 | { 1223 | "path": [ 1224 | "root", 1225 | "networking" 1226 | ], 1227 | "outputs": { 1228 | "default_sg_id": { 1229 | "sensitive": false, 1230 | "type": "string", 1231 | "value": "sg-34438943" 1232 | }, 1233 | "private_subnets_id": { 1234 | "sensitive": false, 1235 | "type": "list", 1236 | "value": [ 1237 | "subnet-de3444f1", 1238 | "subnet-30625b7b" 1239 | ] 1240 | }, 1241 | "public_subnets_id": { 1242 | "sensitive": false, 1243 | "type": "list", 1244 | "value": [ 1245 | "subnet-6537474a", 1246 | "subnet-08774e43" 1247 | ] 1248 | }, 1249 | "security_groups_ids": { 1250 | "sensitive": false, 1251 | "type": "list", 1252 | "value": [ 1253 | "sg-34438943" 1254 | ] 1255 | }, 1256 | "vpc_id": { 1257 | "sensitive": false, 1258 | "type": "string", 1259 | "value": "vpc-32041f4a" 1260 | } 1261 | }, 1262 | "resources": { 1263 | "aws_eip.nat_eip": { 1264 | "type": "aws_eip", 1265 | "depends_on": [ 1266 | "aws_internet_gateway.ig" 1267 | ], 1268 | "primary": { 1269 | "id": "eipalloc-098c613f", 1270 | "attributes": { 1271 | "association_id": "eipassoc-eed306e5", 1272 | "domain": "vpc", 1273 | "id": "eipalloc-098c613f", 1274 | "instance": "", 1275 | "network_interface": "eni-8bf61c46", 1276 | "private_ip": "10.0.1.128", 1277 | "public_ip": "34.193.75.40", 1278 | "tags.%": "0", 1279 | "vpc": "true" 1280 | }, 1281 | "meta": {}, 1282 | "tainted": false 1283 | }, 1284 | "deposed": [], 1285 | "provider": "provider.aws" 1286 | }, 1287 | "aws_internet_gateway.ig": { 1288 | "type": "aws_internet_gateway", 1289 | "depends_on": [ 1290 | "aws_vpc.vpc" 1291 | ], 1292 | "primary": { 1293 | "id": "igw-1a373e63", 1294 | "attributes": { 1295 | "id": "igw-1a373e63", 1296 | "tags.%": "2", 1297 | "tags.Environment": "production", 1298 | "tags.Name": "production-igw", 1299 | "vpc_id": "vpc-32041f4a" 1300 | }, 1301 | "meta": {}, 1302 | "tainted": false 1303 | }, 1304 | "deposed": [], 1305 | "provider": "provider.aws" 1306 | }, 1307 | "aws_nat_gateway.nat": { 1308 | "type": "aws_nat_gateway", 1309 | "depends_on": [ 1310 | "aws_eip.nat_eip", 1311 | "aws_internet_gateway.ig", 1312 | "aws_subnet.public_subnet.*" 1313 | ], 1314 | "primary": { 1315 | "id": "nat-0000beab268c3255b", 1316 | "attributes": { 1317 | "allocation_id": "eipalloc-098c613f", 1318 | "id": "nat-0000beab268c3255b", 1319 | "network_interface_id": "eni-8bf61c46", 1320 | "private_ip": "10.0.1.128", 1321 | "public_ip": "34.193.75.40", 1322 | "subnet_id": "subnet-6537474a", 1323 | "tags.%": "2", 1324 | "tags.Environment": "production", 1325 | "tags.Name": "production-us-east-1a-nat" 1326 | }, 1327 | "meta": {}, 1328 | "tainted": false 1329 | }, 1330 | "deposed": [], 1331 | "provider": "provider.aws" 1332 | }, 1333 | "aws_route.private_nat_gateway": { 1334 | "type": "aws_route", 1335 | "depends_on": [ 1336 | "aws_nat_gateway.nat", 1337 | "aws_route_table.private" 1338 | ], 1339 | "primary": { 1340 | "id": "r-rtb-6fc4f8121080289494", 1341 | "attributes": { 1342 | "destination_cidr_block": "0.0.0.0/0", 1343 | "destination_prefix_list_id": "", 1344 | "egress_only_gateway_id": "", 1345 | "gateway_id": "", 1346 | "id": "r-rtb-6fc4f8121080289494", 1347 | "instance_id": "", 1348 | "instance_owner_id": "", 1349 | "nat_gateway_id": "nat-0000beab268c3255b", 1350 | "network_interface_id": "", 1351 | "origin": "CreateRoute", 1352 | "route_table_id": "rtb-6fc4f812", 1353 | "state": "active", 1354 | "vpc_peering_connection_id": "" 1355 | }, 1356 | "meta": {}, 1357 | "tainted": false 1358 | }, 1359 | "deposed": [], 1360 | "provider": "provider.aws" 1361 | }, 1362 | "aws_route.public_internet_gateway": { 1363 | "type": "aws_route", 1364 | "depends_on": [ 1365 | "aws_internet_gateway.ig", 1366 | "aws_route_table.public" 1367 | ], 1368 | "primary": { 1369 | "id": "r-rtb-8cccf0f11080289494", 1370 | "attributes": { 1371 | "destination_cidr_block": "0.0.0.0/0", 1372 | "destination_prefix_list_id": "", 1373 | "egress_only_gateway_id": "", 1374 | "gateway_id": "igw-1a373e63", 1375 | "id": "r-rtb-8cccf0f11080289494", 1376 | "instance_id": "", 1377 | "instance_owner_id": "", 1378 | "nat_gateway_id": "", 1379 | "network_interface_id": "", 1380 | "origin": "CreateRoute", 1381 | "route_table_id": "rtb-8cccf0f1", 1382 | "state": "active", 1383 | "vpc_peering_connection_id": "" 1384 | }, 1385 | "meta": {}, 1386 | "tainted": false 1387 | }, 1388 | "deposed": [], 1389 | "provider": "provider.aws" 1390 | }, 1391 | "aws_route_table.private": { 1392 | "type": "aws_route_table", 1393 | "depends_on": [ 1394 | "aws_vpc.vpc" 1395 | ], 1396 | "primary": { 1397 | "id": "rtb-6fc4f812", 1398 | "attributes": { 1399 | "id": "rtb-6fc4f812", 1400 | "propagating_vgws.#": "0", 1401 | "route.#": "1", 1402 | "route.4236193873.cidr_block": "0.0.0.0/0", 1403 | "route.4236193873.egress_only_gateway_id": "", 1404 | "route.4236193873.gateway_id": "", 1405 | "route.4236193873.instance_id": "", 1406 | "route.4236193873.ipv6_cidr_block": "", 1407 | "route.4236193873.nat_gateway_id": "nat-0000beab268c3255b", 1408 | "route.4236193873.network_interface_id": "", 1409 | "route.4236193873.vpc_peering_connection_id": "", 1410 | "tags.%": "2", 1411 | "tags.Environment": "production", 1412 | "tags.Name": "production-private-route-table", 1413 | "vpc_id": "vpc-32041f4a" 1414 | }, 1415 | "meta": {}, 1416 | "tainted": false 1417 | }, 1418 | "deposed": [], 1419 | "provider": "provider.aws" 1420 | }, 1421 | "aws_route_table.public": { 1422 | "type": "aws_route_table", 1423 | "depends_on": [ 1424 | "aws_vpc.vpc" 1425 | ], 1426 | "primary": { 1427 | "id": "rtb-8cccf0f1", 1428 | "attributes": { 1429 | "id": "rtb-8cccf0f1", 1430 | "propagating_vgws.#": "0", 1431 | "route.#": "1", 1432 | "route.1381113949.cidr_block": "0.0.0.0/0", 1433 | "route.1381113949.egress_only_gateway_id": "", 1434 | "route.1381113949.gateway_id": "igw-1a373e63", 1435 | "route.1381113949.instance_id": "", 1436 | "route.1381113949.ipv6_cidr_block": "", 1437 | "route.1381113949.nat_gateway_id": "", 1438 | "route.1381113949.network_interface_id": "", 1439 | "route.1381113949.vpc_peering_connection_id": "", 1440 | "tags.%": "2", 1441 | "tags.Environment": "production", 1442 | "tags.Name": "production-public-route-table", 1443 | "vpc_id": "vpc-32041f4a" 1444 | }, 1445 | "meta": {}, 1446 | "tainted": false 1447 | }, 1448 | "deposed": [], 1449 | "provider": "provider.aws" 1450 | }, 1451 | "aws_route_table_association.private.0": { 1452 | "type": "aws_route_table_association", 1453 | "depends_on": [ 1454 | "aws_route_table.private", 1455 | "aws_subnet.private_subnet.*" 1456 | ], 1457 | "primary": { 1458 | "id": "rtbassoc-f2ef6e8e", 1459 | "attributes": { 1460 | "id": "rtbassoc-f2ef6e8e", 1461 | "route_table_id": "rtb-6fc4f812", 1462 | "subnet_id": "subnet-de3444f1" 1463 | }, 1464 | "meta": {}, 1465 | "tainted": false 1466 | }, 1467 | "deposed": [], 1468 | "provider": "provider.aws" 1469 | }, 1470 | "aws_route_table_association.private.1": { 1471 | "type": "aws_route_table_association", 1472 | "depends_on": [ 1473 | "aws_route_table.private", 1474 | "aws_subnet.private_subnet.*" 1475 | ], 1476 | "primary": { 1477 | "id": "rtbassoc-78ec6d04", 1478 | "attributes": { 1479 | "id": "rtbassoc-78ec6d04", 1480 | "route_table_id": "rtb-6fc4f812", 1481 | "subnet_id": "subnet-30625b7b" 1482 | }, 1483 | "meta": {}, 1484 | "tainted": false 1485 | }, 1486 | "deposed": [], 1487 | "provider": "provider.aws" 1488 | }, 1489 | "aws_route_table_association.public.0": { 1490 | "type": "aws_route_table_association", 1491 | "depends_on": [ 1492 | "aws_route_table.public", 1493 | "aws_subnet.public_subnet.*" 1494 | ], 1495 | "primary": { 1496 | "id": "rtbassoc-ebed6c97", 1497 | "attributes": { 1498 | "id": "rtbassoc-ebed6c97", 1499 | "route_table_id": "rtb-8cccf0f1", 1500 | "subnet_id": "subnet-6537474a" 1501 | }, 1502 | "meta": {}, 1503 | "tainted": false 1504 | }, 1505 | "deposed": [], 1506 | "provider": "provider.aws" 1507 | }, 1508 | "aws_route_table_association.public.1": { 1509 | "type": "aws_route_table_association", 1510 | "depends_on": [ 1511 | "aws_route_table.public", 1512 | "aws_subnet.public_subnet.*" 1513 | ], 1514 | "primary": { 1515 | "id": "rtbassoc-f0f4758c", 1516 | "attributes": { 1517 | "id": "rtbassoc-f0f4758c", 1518 | "route_table_id": "rtb-8cccf0f1", 1519 | "subnet_id": "subnet-08774e43" 1520 | }, 1521 | "meta": {}, 1522 | "tainted": false 1523 | }, 1524 | "deposed": [], 1525 | "provider": "provider.aws" 1526 | }, 1527 | "aws_security_group.default": { 1528 | "type": "aws_security_group", 1529 | "depends_on": [ 1530 | "aws_vpc.vpc" 1531 | ], 1532 | "primary": { 1533 | "id": "sg-34438943", 1534 | "attributes": { 1535 | "description": "Default security group to allow inbound/outbound from the VPC", 1536 | "egress.#": "1", 1537 | "egress.753360330.cidr_blocks.#": "0", 1538 | "egress.753360330.description": "", 1539 | "egress.753360330.from_port": "0", 1540 | "egress.753360330.ipv6_cidr_blocks.#": "0", 1541 | "egress.753360330.prefix_list_ids.#": "0", 1542 | "egress.753360330.protocol": "-1", 1543 | "egress.753360330.security_groups.#": "0", 1544 | "egress.753360330.self": "true", 1545 | "egress.753360330.to_port": "0", 1546 | "id": "sg-34438943", 1547 | "ingress.#": "1", 1548 | "ingress.753360330.cidr_blocks.#": "0", 1549 | "ingress.753360330.description": "", 1550 | "ingress.753360330.from_port": "0", 1551 | "ingress.753360330.ipv6_cidr_blocks.#": "0", 1552 | "ingress.753360330.protocol": "-1", 1553 | "ingress.753360330.security_groups.#": "0", 1554 | "ingress.753360330.self": "true", 1555 | "ingress.753360330.to_port": "0", 1556 | "name": "production-default-sg", 1557 | "owner_id": "757895497645", 1558 | "revoke_rules_on_delete": "false", 1559 | "tags.%": "1", 1560 | "tags.Environment": "production", 1561 | "vpc_id": "vpc-32041f4a" 1562 | }, 1563 | "meta": { 1564 | "schema_version": "1" 1565 | }, 1566 | "tainted": false 1567 | }, 1568 | "deposed": [], 1569 | "provider": "provider.aws" 1570 | }, 1571 | "aws_subnet.private_subnet.0": { 1572 | "type": "aws_subnet", 1573 | "depends_on": [ 1574 | "aws_vpc.vpc" 1575 | ], 1576 | "primary": { 1577 | "id": "subnet-de3444f1", 1578 | "attributes": { 1579 | "assign_ipv6_address_on_creation": "false", 1580 | "availability_zone": "us-east-1a", 1581 | "cidr_block": "10.0.10.0/24", 1582 | "id": "subnet-de3444f1", 1583 | "map_public_ip_on_launch": "false", 1584 | "tags.%": "2", 1585 | "tags.Environment": "production", 1586 | "tags.Name": "production-us-east-1a-private-subnet", 1587 | "vpc_id": "vpc-32041f4a" 1588 | }, 1589 | "meta": { 1590 | "schema_version": "1" 1591 | }, 1592 | "tainted": false 1593 | }, 1594 | "deposed": [], 1595 | "provider": "provider.aws" 1596 | }, 1597 | "aws_subnet.private_subnet.1": { 1598 | "type": "aws_subnet", 1599 | "depends_on": [ 1600 | "aws_vpc.vpc" 1601 | ], 1602 | "primary": { 1603 | "id": "subnet-30625b7b", 1604 | "attributes": { 1605 | "assign_ipv6_address_on_creation": "false", 1606 | "availability_zone": "us-east-1b", 1607 | "cidr_block": "10.0.20.0/24", 1608 | "id": "subnet-30625b7b", 1609 | "map_public_ip_on_launch": "false", 1610 | "tags.%": "2", 1611 | "tags.Environment": "production", 1612 | "tags.Name": "production-us-east-1b-private-subnet", 1613 | "vpc_id": "vpc-32041f4a" 1614 | }, 1615 | "meta": { 1616 | "schema_version": "1" 1617 | }, 1618 | "tainted": false 1619 | }, 1620 | "deposed": [], 1621 | "provider": "provider.aws" 1622 | }, 1623 | "aws_subnet.public_subnet.0": { 1624 | "type": "aws_subnet", 1625 | "depends_on": [ 1626 | "aws_vpc.vpc" 1627 | ], 1628 | "primary": { 1629 | "id": "subnet-6537474a", 1630 | "attributes": { 1631 | "assign_ipv6_address_on_creation": "false", 1632 | "availability_zone": "us-east-1a", 1633 | "cidr_block": "10.0.1.0/24", 1634 | "id": "subnet-6537474a", 1635 | "map_public_ip_on_launch": "true", 1636 | "tags.%": "2", 1637 | "tags.Environment": "production", 1638 | "tags.Name": "production-us-east-1a-public-subnet", 1639 | "vpc_id": "vpc-32041f4a" 1640 | }, 1641 | "meta": { 1642 | "schema_version": "1" 1643 | }, 1644 | "tainted": false 1645 | }, 1646 | "deposed": [], 1647 | "provider": "provider.aws" 1648 | }, 1649 | "aws_subnet.public_subnet.1": { 1650 | "type": "aws_subnet", 1651 | "depends_on": [ 1652 | "aws_vpc.vpc" 1653 | ], 1654 | "primary": { 1655 | "id": "subnet-08774e43", 1656 | "attributes": { 1657 | "assign_ipv6_address_on_creation": "false", 1658 | "availability_zone": "us-east-1b", 1659 | "cidr_block": "10.0.2.0/24", 1660 | "id": "subnet-08774e43", 1661 | "map_public_ip_on_launch": "true", 1662 | "tags.%": "2", 1663 | "tags.Environment": "production", 1664 | "tags.Name": "production-us-east-1b-public-subnet", 1665 | "vpc_id": "vpc-32041f4a" 1666 | }, 1667 | "meta": { 1668 | "schema_version": "1" 1669 | }, 1670 | "tainted": false 1671 | }, 1672 | "deposed": [], 1673 | "provider": "provider.aws" 1674 | }, 1675 | "aws_vpc.vpc": { 1676 | "type": "aws_vpc", 1677 | "depends_on": [], 1678 | "primary": { 1679 | "id": "vpc-32041f4a", 1680 | "attributes": { 1681 | "assign_generated_ipv6_cidr_block": "false", 1682 | "cidr_block": "10.0.0.0/16", 1683 | "default_network_acl_id": "acl-8280eef9", 1684 | "default_route_table_id": "rtb-d6bd81ab", 1685 | "default_security_group_id": "sg-d335ffa4", 1686 | "dhcp_options_id": "dopt-15849877", 1687 | "enable_classiclink": "false", 1688 | "enable_classiclink_dns_support": "false", 1689 | "enable_dns_hostnames": "true", 1690 | "enable_dns_support": "true", 1691 | "id": "vpc-32041f4a", 1692 | "instance_tenancy": "default", 1693 | "main_route_table_id": "rtb-d6bd81ab", 1694 | "tags.%": "2", 1695 | "tags.Environment": "production", 1696 | "tags.Name": "production-vpc" 1697 | }, 1698 | "meta": { 1699 | "schema_version": "1" 1700 | }, 1701 | "tainted": false 1702 | }, 1703 | "deposed": [], 1704 | "provider": "provider.aws" 1705 | } 1706 | }, 1707 | "depends_on": [] 1708 | }, 1709 | { 1710 | "path": [ 1711 | "root", 1712 | "rds" 1713 | ], 1714 | "outputs": { 1715 | "db_access_sg_id": { 1716 | "sensitive": false, 1717 | "type": "string", 1718 | "value": "sg-2b37fd5c" 1719 | }, 1720 | "rds_address": { 1721 | "sensitive": false, 1722 | "type": "string", 1723 | "value": "production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com" 1724 | } 1725 | }, 1726 | "resources": { 1727 | "aws_db_instance.rds": { 1728 | "type": "aws_db_instance", 1729 | "depends_on": [ 1730 | "aws_db_subnet_group.rds_subnet_group", 1731 | "aws_security_group.rds_sg" 1732 | ], 1733 | "primary": { 1734 | "id": "production-database", 1735 | "attributes": { 1736 | "address": "production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com", 1737 | "allocated_storage": "20", 1738 | "arn": "arn:aws:rds:us-east-1:757895497645:db:production-database", 1739 | "auto_minor_version_upgrade": "true", 1740 | "availability_zone": "us-east-1a", 1741 | "backup_retention_period": "0", 1742 | "backup_window": "08:37-09:07", 1743 | "ca_cert_identifier": "rds-ca-2015", 1744 | "copy_tags_to_snapshot": "false", 1745 | "db_subnet_group_name": "production-rds-subnet-group", 1746 | "endpoint": "production-database.ccgs7gcr5zuj.us-east-1.rds.amazonaws.com:5432", 1747 | "engine": "postgres", 1748 | "engine_version": "9.6.6", 1749 | "hosted_zone_id": "Z2R2ITUGPM61AM", 1750 | "iam_database_authentication_enabled": "false", 1751 | "id": "production-database", 1752 | "identifier": "production-database", 1753 | "instance_class": "db.t2.micro", 1754 | "iops": "0", 1755 | "kms_key_id": "", 1756 | "license_model": "postgresql-license", 1757 | "maintenance_window": "sat:04:07-sat:04:37", 1758 | "monitoring_interval": "0", 1759 | "multi_az": "false", 1760 | "name": "openjobs_production", 1761 | "option_group_name": "default:postgres-9-6", 1762 | "parameter_group_name": "default.postgres9.6", 1763 | "password": "myawesomepasswordproduction", 1764 | "port": "5432", 1765 | "publicly_accessible": "false", 1766 | "replicas.#": "0", 1767 | "replicate_source_db": "", 1768 | "resource_id": "db-Z2YKHEFX3HMYUCQTU4Q3FC2BGY", 1769 | "security_group_names.#": "0", 1770 | "skip_final_snapshot": "true", 1771 | "snapshot_identifier": "rds-production-snapshot", 1772 | "status": "available", 1773 | "storage_encrypted": "false", 1774 | "storage_type": "standard", 1775 | "tags.%": "1", 1776 | "tags.Environment": "production", 1777 | "timezone": "", 1778 | "username": "openjobs", 1779 | "vpc_security_group_ids.#": "1", 1780 | "vpc_security_group_ids.251623276": "sg-c931fbbe" 1781 | }, 1782 | "meta": { 1783 | "e2bfb730-ecaa-11e6-8f88-34363bc7c4c0": { 1784 | "create": 2400000000000, 1785 | "delete": 2400000000000, 1786 | "update": 4800000000000 1787 | } 1788 | }, 1789 | "tainted": false 1790 | }, 1791 | "deposed": [], 1792 | "provider": "provider.aws" 1793 | }, 1794 | "aws_db_subnet_group.rds_subnet_group": { 1795 | "type": "aws_db_subnet_group", 1796 | "depends_on": [], 1797 | "primary": { 1798 | "id": "production-rds-subnet-group", 1799 | "attributes": { 1800 | "arn": "arn:aws:rds:us-east-1:757895497645:subgrp:production-rds-subnet-group", 1801 | "description": "RDS subnet group", 1802 | "id": "production-rds-subnet-group", 1803 | "name": "production-rds-subnet-group", 1804 | "subnet_ids.#": "2", 1805 | "subnet_ids.3113454962": "subnet-30625b7b", 1806 | "subnet_ids.3378482322": "subnet-de3444f1", 1807 | "tags.%": "1", 1808 | "tags.Environment": "production" 1809 | }, 1810 | "meta": {}, 1811 | "tainted": false 1812 | }, 1813 | "deposed": [], 1814 | "provider": "provider.aws" 1815 | }, 1816 | "aws_security_group.db_access_sg": { 1817 | "type": "aws_security_group", 1818 | "depends_on": [], 1819 | "primary": { 1820 | "id": "sg-2b37fd5c", 1821 | "attributes": { 1822 | "description": "Allow access to RDS", 1823 | "egress.#": "0", 1824 | "id": "sg-2b37fd5c", 1825 | "ingress.#": "0", 1826 | "name": "production-db-access-sg", 1827 | "owner_id": "757895497645", 1828 | "revoke_rules_on_delete": "false", 1829 | "tags.%": "2", 1830 | "tags.Environment": "production", 1831 | "tags.Name": "production-db-access-sg", 1832 | "vpc_id": "vpc-32041f4a" 1833 | }, 1834 | "meta": { 1835 | "schema_version": "1" 1836 | }, 1837 | "tainted": false 1838 | }, 1839 | "deposed": [], 1840 | "provider": "provider.aws" 1841 | }, 1842 | "aws_security_group.rds_sg": { 1843 | "type": "aws_security_group", 1844 | "depends_on": [ 1845 | "aws_security_group.db_access_sg" 1846 | ], 1847 | "primary": { 1848 | "id": "sg-c931fbbe", 1849 | "attributes": { 1850 | "description": "production Security Group", 1851 | "egress.#": "1", 1852 | "egress.482069346.cidr_blocks.#": "1", 1853 | "egress.482069346.cidr_blocks.0": "0.0.0.0/0", 1854 | "egress.482069346.description": "", 1855 | "egress.482069346.from_port": "0", 1856 | "egress.482069346.ipv6_cidr_blocks.#": "0", 1857 | "egress.482069346.prefix_list_ids.#": "0", 1858 | "egress.482069346.protocol": "-1", 1859 | "egress.482069346.security_groups.#": "0", 1860 | "egress.482069346.self": "false", 1861 | "egress.482069346.to_port": "0", 1862 | "id": "sg-c931fbbe", 1863 | "ingress.#": "2", 1864 | "ingress.4257570995.cidr_blocks.#": "0", 1865 | "ingress.4257570995.description": "", 1866 | "ingress.4257570995.from_port": "5432", 1867 | "ingress.4257570995.ipv6_cidr_blocks.#": "0", 1868 | "ingress.4257570995.protocol": "tcp", 1869 | "ingress.4257570995.security_groups.#": "1", 1870 | "ingress.4257570995.security_groups.569761485": "sg-2b37fd5c", 1871 | "ingress.4257570995.self": "false", 1872 | "ingress.4257570995.to_port": "5432", 1873 | "ingress.753360330.cidr_blocks.#": "0", 1874 | "ingress.753360330.description": "", 1875 | "ingress.753360330.from_port": "0", 1876 | "ingress.753360330.ipv6_cidr_blocks.#": "0", 1877 | "ingress.753360330.protocol": "-1", 1878 | "ingress.753360330.security_groups.#": "0", 1879 | "ingress.753360330.self": "true", 1880 | "ingress.753360330.to_port": "0", 1881 | "name": "production-rds-sg", 1882 | "owner_id": "757895497645", 1883 | "revoke_rules_on_delete": "false", 1884 | "tags.%": "2", 1885 | "tags.Environment": "production", 1886 | "tags.Name": "production-rds-sg", 1887 | "vpc_id": "vpc-32041f4a" 1888 | }, 1889 | "meta": { 1890 | "schema_version": "1" 1891 | }, 1892 | "tainted": false 1893 | }, 1894 | "deposed": [], 1895 | "provider": "provider.aws" 1896 | } 1897 | }, 1898 | "depends_on": [] 1899 | } 1900 | ] 1901 | } 1902 | -------------------------------------------------------------------------------- /terraform.tfvars: -------------------------------------------------------------------------------- 1 | region = "us-east-1" 2 | domain = "ecsfargateexample.tk" 3 | 4 | /* rds */ 5 | production_database_name = "openjobs_production" 6 | production_database_username = "openjobs" 7 | production_database_password = "myawesomepasswordproduction" 8 | 9 | /* secret key */ 10 | production_secret_key_base = "8d412aee3ceaa494fe1c276f5f7e524b9e33f649c03690e689e5b36a0cf4ce2a6f50024bc31f276c22b668e619d61a42b79f5e595759f377a8fa373e2907f41e" 11 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "Region that the instances will be created" 3 | } 4 | 5 | /*==== 6 | environment specific variables 7 | ======*/ 8 | 9 | variable "production_database_name" { 10 | description = "The database name for Production" 11 | } 12 | 13 | variable "production_database_username" { 14 | description = "The username for the Production database" 15 | } 16 | 17 | variable "production_database_password" { 18 | description = "The user password for the Production database" 19 | } 20 | 21 | variable "production_secret_key_base" { 22 | description = "The Rails secret key for production" 23 | } 24 | 25 | variable "domain" { 26 | default = "The domain of your application" 27 | } 28 | --------------------------------------------------------------------------------