mmb/meme_captain_web

View on GitHub
aws/meme_captain.json

Summary

Maintainability
Test Coverage
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Outputs": {
    "dbHost": {
      "Value": {
        "Fn::GetAtt": [
          "database",
          "Endpoint.Address"
        ]
      }
    }
  },
  "Parameters": {
    "canaryAmi": {
      "Type": "String"
    },
    "dbPassword": {
      "NoEcho": "TRUE",
      "Type": "String"
    },
    "dbUser": {
      "Type": "String"
    },
    "onDemandAmi": {
      "Type": "String"
    },
    "spotAmi": {
      "Type": "String"
    }
  },
  "Resources": {
    "autoScalingTopic": {
      "Properties": {
        "DisplayName": "autoscaling",
        "Subscription": [
          {
            "Endpoint": "matthewm@boedicker.org",
            "Protocol": "email"
          }
        ],
        "TopicName": "autoscaling"
      },
      "Type": "AWS::SNS::Topic"
    },
    "canaryAutoScalingGroup": {
      "Properties": {
        "DesiredCapacity": 1,
        "HealthCheckGracePeriod": 300,
        "HealthCheckType": "ELB",
        "LaunchConfigurationName": {
          "Ref": "canaryLaunchConfig"
        },
        "MaxSize": 1,
        "MinSize": 1,
        "NotificationConfigurations": [
          {
            "NotificationTypes": [
              "autoscaling:EC2_INSTANCE_LAUNCH",
              "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
              "autoscaling:EC2_INSTANCE_TERMINATE",
              "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
            ],
            "TopicARN": {
              "Ref": "autoScalingTopic"
            }
          }
        ],
        "Tags": [
          {
            "Key": "pool",
            "PropagateAtLaunch": true,
            "Value": "canary"
          }
        ],
        "TargetGroupARNs": [
          {
            "Ref": "elbTargetGroup"
          }
        ],
        "VPCZoneIdentifier": [
          {
            "Ref": "publicSubnet1"
          }
        ]
      },
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "UpdatePolicy": {
        "AutoScalingRollingUpdate": {}
      }
    },
    "canaryLaunchConfig": {
      "Properties": {
        "AssociatePublicIpAddress": true,
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/xvda",
            "Ebs": {
              "VolumeSize": "16"
            }
          }
        ],
        "IamInstanceProfile": {
          "Ref": "instanceProfile"
        },
        "ImageId": {
          "Ref": "canaryAmi"
        },
        "InstanceType": "t2.small",
        "KeyName": "memecaptain",
        "SecurityGroups": [
          {
            "Ref": "webSecurityGroup"
          }
        ],
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [
              "\n",
              [
                "#!/bin/bash",
                "set -e",
                "aws s3 cp s3://memecaptain-secrets/database.yml /database.yml",
                "aws s3 cp s3://memecaptain-secrets/env/small.env /env",
                "echo canary > /pool",
                ". /startup"
              ]
            ]
          }
        }
      },
      "Type": "AWS::AutoScaling::LaunchConfiguration"
    },
    "cloudFrontLogsBucket": {
      "Properties": {
        "AccessControl": "Private",
        "BucketName": "memecaptain-cloudfront-logs"
      },
      "Type": "AWS::S3::Bucket"
    },
    "database": {
      "Properties": {
        "AllocatedStorage": "10",
        "AvailabilityZone": "us-east-1d",
        "BackupRetentionPeriod": "1",
        "DBInstanceClass": "db.t2.small",
        "DBName": "memecaptain",
        "DBSubnetGroupName": {
          "Ref": "dbSubnetGroup"
        },
        "Engine": "postgres",
        "MasterUserPassword": {
          "Ref": "dbPassword"
        },
        "MasterUsername": {
          "Ref": "dbUser"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "memecaptain"
          }
        ],
        "VPCSecurityGroups": [
          {
            "Ref": "dbSecurityGroup"
          }
        ]
      },
      "Type": "AWS::RDS::DBInstance"
    },
    "dbFreeStorageLowAlarm": {
      "Properties": {
        "AlarmActions": [
          {
            "Ref": "dbTopic"
          }
        ],
        "AlarmDescription": "notify if database free storage is < 5G",
        "AlarmName": "dbFreeStorageLow",
        "ComparisonOperator": "LessThanThreshold",
        "Dimensions": [
          {
            "Name": "DBInstanceIdentifier",
            "Value": {
              "Ref": "database"
            }
          }
        ],
        "EvaluationPeriods": "1",
        "MetricName": "FreeStorageSpace",
        "Namespace": "AWS/RDS",
        "Period": "60",
        "Statistic": "Minimum",
        "Threshold": "5000000000"
      },
      "Type": "AWS::CloudWatch::Alarm"
    },
    "dbSecurityGroup": {
      "Properties": {
        "GroupDescription": "db security group",
        "SecurityGroupEgress": [
          {
            "CidrIp": "0.0.0.0/0",
            "FromPort": "1",
            "IpProtocol": "tcp",
            "ToPort": "65535"
          }
        ],
        "SecurityGroupIngress": [
          {
            "FromPort": "5432",
            "IpProtocol": "tcp",
            "SourceSecurityGroupId": {
              "Ref": "webSecurityGroup"
            },
            "ToPort": "5432"
          }
        ],
        "Tags": [
          {
            "Key": "Name",
            "Value": "db"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::SecurityGroup"
    },
    "dbSubnetGroup": {
      "Properties": {
        "DBSubnetGroupDescription": "db subnet group",
        "SubnetIds": [
          {
            "Ref": "privateSubnet1"
          },
          {
            "Ref": "privateSubnet2"
          }
        ]
      },
      "Type": "AWS::RDS::DBSubnetGroup"
    },
    "dbTopic": {
      "Properties": {
        "DisplayName": "db",
        "Subscription": [
          {
            "Endpoint": "matthewm@boedicker.org",
            "Protocol": "email"
          }
        ],
        "TopicName": "db"
      },
      "Type": "AWS::SNS::Topic"
    },
    "elb2": {
      "DependsOn": "internetGatewayAttachment",
      "Properties": {
        "LoadBalancerAttributes": [
          {
            "Key": "access_logs.s3.enabled",
            "Value": true
          },
          {
            "Key": "access_logs.s3.bucket",
            "Value": {
              "Ref": "elbLogsBucket"
            }
          }
        ],
        "Name": "memecaptain2",
        "SecurityGroups": [
          {
            "Ref": "elbSecurityGroup"
          }
        ],
        "Subnets": [
          {
            "Ref": "publicSubnet1"
          },
          {
            "Ref": "publicSubnet2"
          }
        ]
      },
      "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer"
    },
    "elbCert": {
      "Properties": {
        "DomainName": "*.memecaptain.com",
        "SubjectAlternativeNames": [
          "memecaptain.com"
        ]
      },
      "Type": "AWS::CertificateManager::Certificate"
    },
    "elbHttpListener": {
      "Properties": {
        "DefaultActions": [
          {
            "TargetGroupArn": {
              "Ref": "elbTargetGroup"
            },
            "Type": "forward"
          }
        ],
        "LoadBalancerArn": {
          "Ref": "elb2"
        },
        "Port": 80,
        "Protocol": "HTTP"
      },
      "Type": "AWS::ElasticLoadBalancingV2::Listener"
    },
    "elbHttpsListener": {
      "Properties": {
        "Certificates": [
          {
            "CertificateArn": {
              "Ref": "elbCert"
            }
          }
        ],
        "DefaultActions": [
          {
            "TargetGroupArn": {
              "Ref": "elbTargetGroup"
            },
            "Type": "forward"
          }
        ],
        "LoadBalancerArn": {
          "Ref": "elb2"
        },
        "Port": 443,
        "Protocol": "HTTPS"
      },
      "Type": "AWS::ElasticLoadBalancingV2::Listener"
    },
    "elbLogsBucket": {
      "Properties": {
        "AccessControl": "Private",
        "BucketName": "memecaptain-elb-logs"
      },
      "Type": "AWS::S3::Bucket"
    },
    "elbLogsBucketPolicy": {
      "Properties": {
        "Bucket": {
          "Ref": "elbLogsBucket"
        },
        "PolicyDocument": {
          "Statement": [
            {
              "Action": [
                "s3:PutObject"
              ],
              "Effect": "Allow",
              "Principal": {
                "AWS": [
                  "127311923021"
                ]
              },
              "Resource": {
                "Fn::Join": [
                  "",
                  [
                    "arn:aws:s3:::",
                    {
                      "Ref": "elbLogsBucket"
                    },
                    "/AWSLogs/165945320610/*"
                  ]
                ]
              }
            }
          ]
        }
      },
      "Type": "AWS::S3::BucketPolicy"
    },
    "elbSecurityGroup": {
      "Properties": {
        "GroupDescription": "elb security group",
        "SecurityGroupEgress": [
          {
            "CidrIp": "0.0.0.0/0",
            "FromPort": "1",
            "IpProtocol": "tcp",
            "ToPort": "65535"
          }
        ],
        "SecurityGroupIngress": [
          {
            "CidrIp": "0.0.0.0/0",
            "FromPort": "80",
            "IpProtocol": "tcp",
            "ToPort": "80"
          },
          {
            "CidrIp": "0.0.0.0/0",
            "FromPort": "443",
            "IpProtocol": "tcp",
            "ToPort": "443"
          }
        ],
        "Tags": [
          {
            "Key": "Name",
            "Value": "elb"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::SecurityGroup"
    },
    "elbTargetGroup": {
      "Properties": {
        "HealthCheckIntervalSeconds": 30,
        "HealthCheckPath": "/instance_health",
        "HealthCheckPort": "80",
        "HealthCheckProtocol": "HTTP",
        "HealthCheckTimeoutSeconds": 5,
        "HealthyThresholdCount": 4,
        "Name": "memecaptain",
        "Port": 80,
        "Protocol": "HTTP",
        "UnhealthyThresholdCount": 2,
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::ElasticLoadBalancingV2::TargetGroup"
    },
    "imageStoreBucket": {
      "Properties": {
        "AccessControl": "Private",
        "BucketName": "memecaptain-images",
        "VersioningConfiguration": {
          "Status": "Enabled"
        }
      },
      "Type": "AWS::S3::Bucket"
    },
    "instanceProfile": {
      "Properties": {
        "Roles": [
          {
            "Ref": "instanceRole"
          }
        ]
      },
      "Type": "AWS::IAM::InstanceProfile"
    },
    "instanceRole": {
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              }
            }
          ],
          "Version": "2012-10-17"
        },
        "Path": "/",
        "Policies": [
          {
            "PolicyDocument": {
              "Statement": [
                {
                  "Action": [
                    "s3:ListBucket"
                  ],
                  "Effect": "Allow",
                  "Resource": "arn:aws:s3:::memecaptain-secrets"
                },
                {
                  "Action": [
                    "s3:GetObject"
                  ],
                  "Effect": "Allow",
                  "Resource": "arn:aws:s3:::memecaptain-secrets/*"
                }
              ],
              "Version": "2012-10-17"
            },
            "PolicyName": "secretsPolicy"
          },
          {
            "PolicyDocument": {
              "Statement": [
                {
                  "Action": [
                    "s3:CreateMultipartUpload",
                    "s3:PutObject",
                    "s3:GetObject"
                  ],
                  "Effect": "Allow",
                  "Resource": "arn:aws:s3:::memecaptain-images/*"
                }
              ],
              "Version": "2012-10-17"
            },
            "PolicyName": "imageStorePolicy"
          }
        ]
      },
      "Type": "AWS::IAM::Role"
    },
    "internetGateway": {
      "Type": "AWS::EC2::InternetGateway"
    },
    "internetGatewayAttachment": {
      "Properties": {
        "InternetGatewayId": {
          "Ref": "internetGateway"
        },
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::VPCGatewayAttachment"
    },
    "internetGatewayRoute": {
      "DependsOn": "internetGatewayAttachment",
      "Properties": {
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {
          "Ref": "internetGateway"
        },
        "RouteTableId": {
          "Ref": "internetGatewayRouteTable"
        }
      },
      "Type": "AWS::EC2::Route"
    },
    "internetGatewayRouteTable": {
      "Properties": {
        "Tags": [
          {
            "Key": "Name",
            "Value": "igw"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::RouteTable"
    },
    "natRouteTable": {
      "Properties": {
        "Tags": [
          {
            "Key": "Name",
            "Value": "nat"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::RouteTable"
    },
    "onDemandAutoScalingGroup": {
      "Properties": {
        "DesiredCapacity": 0,
        "HealthCheckGracePeriod": 300,
        "HealthCheckType": "ELB",
        "LaunchConfigurationName": {
          "Ref": "onDemandLaunchConfig"
        },
        "MaxSize": 0,
        "MinSize": 0,
        "NotificationConfigurations": [
          {
            "NotificationTypes": [
              "autoscaling:EC2_INSTANCE_LAUNCH",
              "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
              "autoscaling:EC2_INSTANCE_TERMINATE",
              "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
            ],
            "TopicARN": {
              "Ref": "autoScalingTopic"
            }
          }
        ],
        "Tags": [
          {
            "Key": "pool",
            "PropagateAtLaunch": true,
            "Value": "ondemand"
          }
        ],
        "TargetGroupARNs": [
          {
            "Ref": "elbTargetGroup"
          }
        ],
        "VPCZoneIdentifier": [
          {
            "Ref": "publicSubnet1"
          }
        ]
      },
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "UpdatePolicy": {
        "AutoScalingRollingUpdate": {}
      }
    },
    "onDemandLaunchConfig": {
      "Properties": {
        "AssociatePublicIpAddress": true,
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/xvda",
            "Ebs": {
              "VolumeSize": "16"
            }
          }
        ],
        "IamInstanceProfile": {
          "Ref": "instanceProfile"
        },
        "ImageId": {
          "Ref": "onDemandAmi"
        },
        "InstanceType": "t2.small",
        "KeyName": "memecaptain",
        "SecurityGroups": [
          {
            "Ref": "webSecurityGroup"
          }
        ],
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [
              "\n",
              [
                "#!/bin/bash",
                "set -e",
                "aws s3 cp s3://memecaptain-secrets/database.yml /database.yml",
                "aws s3 cp s3://memecaptain-secrets/env/small.env /env",
                "echo ondemand > /pool",
                ". /startup"
              ]
            ]
          }
        }
      },
      "Type": "AWS::AutoScaling::LaunchConfiguration"
    },
    "privateSubnet1": {
      "Properties": {
        "AvailabilityZone": "us-east-1d",
        "CidrBlock": "10.0.2.0/24",
        "Tags": [
          {
            "Key": "Name",
            "Value": "private1"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::Subnet"
    },
    "privateSubnet1RouteTableAssociation": {
      "Properties": {
        "RouteTableId": {
          "Ref": "natRouteTable"
        },
        "SubnetId": {
          "Ref": "privateSubnet1"
        }
      },
      "Type": "AWS::EC2::SubnetRouteTableAssociation"
    },
    "privateSubnet2": {
      "Properties": {
        "AvailabilityZone": "us-east-1e",
        "CidrBlock": "10.0.3.0/24",
        "Tags": [
          {
            "Key": "Name",
            "Value": "private2"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::Subnet"
    },
    "privateSubnet2RouteTableAssociation": {
      "Properties": {
        "RouteTableId": {
          "Ref": "natRouteTable"
        },
        "SubnetId": {
          "Ref": "privateSubnet2"
        }
      },
      "Type": "AWS::EC2::SubnetRouteTableAssociation"
    },
    "publicSubnet1": {
      "Properties": {
        "AvailabilityZone": "us-east-1d",
        "CidrBlock": "10.0.0.0/24",
        "Tags": [
          {
            "Key": "Name",
            "Value": "public1"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::Subnet"
    },
    "publicSubnet1RouteTableAssociation": {
      "Properties": {
        "RouteTableId": {
          "Ref": "internetGatewayRouteTable"
        },
        "SubnetId": {
          "Ref": "publicSubnet1"
        }
      },
      "Type": "AWS::EC2::SubnetRouteTableAssociation"
    },
    "publicSubnet2": {
      "Properties": {
        "AvailabilityZone": "us-east-1e",
        "CidrBlock": "10.0.1.0/24",
        "Tags": [
          {
            "Key": "Name",
            "Value": "public2"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::Subnet"
    },
    "publicSubnet2RouteTableAssociation": {
      "Properties": {
        "RouteTableId": {
          "Ref": "internetGatewayRouteTable"
        },
        "SubnetId": {
          "Ref": "publicSubnet2"
        }
      },
      "Type": "AWS::EC2::SubnetRouteTableAssociation"
    },
    "s3VPCEndpoint": {
      "Properties": {
        "RouteTableIds": [
          {
            "Ref": "internetGatewayRouteTable"
          }
        ],
        "ServiceName": "com.amazonaws.us-east-1.s3",
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::VPCEndpoint"
    },
    "secretsBucket": {
      "Properties": {
        "AccessControl": "Private",
        "BucketName": "memecaptain-secrets"
      },
      "Type": "AWS::S3::Bucket"
    },
    "v1RedirectBucket": {
      "Properties": {
        "AccessControl": "PublicRead",
        "BucketName": "v1.memecaptain.com",
        "WebsiteConfiguration": {
          "RedirectAllRequestsTo": {
            "HostName": "memecaptain.com"
          }
        }
      },
      "Type": "AWS::S3::Bucket"
    },
    "vpc": {
      "Properties": {
        "CidrBlock": "10.0.0.0/16",
        "Tags": [
          {
            "Key": "Name",
            "Value": "memecaptain"
          }
        ]
      },
      "Type": "AWS::EC2::VPC"
    },
    "webSecurityGroup": {
      "Properties": {
        "GroupDescription": "web security group",
        "SecurityGroupEgress": [
          {
            "CidrIp": "0.0.0.0/0",
            "FromPort": "1",
            "IpProtocol": "tcp",
            "ToPort": "65535"
          },
          {
            "CidrIp": "10.0.0.0/24",
            "FromPort": "8125",
            "IpProtocol": "udp",
            "ToPort": "8125"
          }
        ],
        "SecurityGroupIngress": [
          {
            "FromPort": "80",
            "IpProtocol": "tcp",
            "SourceSecurityGroupId": {
              "Ref": "elbSecurityGroup"
            },
            "ToPort": "80"
          }
        ],
        "Tags": [
          {
            "Key": "Name",
            "Value": "web"
          }
        ],
        "VpcId": {
          "Ref": "vpc"
        }
      },
      "Type": "AWS::EC2::SecurityGroup"
    }
  }
}