{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "AWS CloudFormation Sample Template: Launches OpsWorks stack, layer, instances and associated resources to run a PHP application. The application runs inside an Amazon VPC and uses ELB to load balance ** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
  "Mappings": {
    "AWSNATAMI": {
      "us-east-1": {
        "AMI": "ami-c6699baf"
      },
      "us-west-2": {
        "AMI": "ami-52ff7262"
      },
      "us-west-1": {
        "AMI": "ami-3bcc9e7e"
      },
      "eu-west-1": {
        "AMI": "ami-0b5b6c7f"
      },
      "ap-southeast-1": {
        "AMI": "ami-02eb9350"
      },
      "ap-northeast-1": {
        "AMI": "ami-14d86d15"
      },
      "sa-east-1": {
        "AMI": "ami-0439e619"
      }
    },
    "SubnetConfig": {
      "VPC": {
        "CIDR": "10.0.0.0/16"
      },
      "Public": {
        "CIDR": "10.0.0.0/24"
      },
      "Private": {
        "CIDR": "10.0.1.0/24"
      }
    }
  },
  "Resources": {
    "OpsWorksStack": {
      "Type": "AWS::OpsWorks::Stack",
      "Properties": {
        "Name": {
          "Ref": "AWS::StackName"
        },
        "ServiceRoleArn": {
          "Fn::GetAtt": [
            "OpsWorksServiceRole",
            "Arn"
          ]
        },
        "DefaultInstanceProfileArn": {
          "Fn::GetAtt": [
            "OpsWorksInstanceProfile",
            "Arn"
          ]
        },
        "VpcId": {
          "Ref": "VPC"
        },
        "DefaultSubnetId": {
          "Ref": "PrivateSubnet"
        }
      }
    },
    "OpsWorksLayer": {
      "Type": "AWS::OpsWorks::Layer",
      "Metadata" : {
        "Comment" : "OpsWorks instances require outbound Internet access. Using DependsOn to make sure outbound Internet Access is estlablished before creating instances in this layer."
      },
      "DependsOn": [ "NATIPAddress", "PublicRoute", "PublicSubnetRouteTableAssociation", "PrivateRoute", "PrivateSubnetRouteTableAssociation", "OpsWorksApp"],
      "Properties": {
        "StackId": {
          "Ref": "OpsWorksStack"
        },
        "Name": "MyPHPApp",
        "Type": "php-app",
        "Shortname": "php-app",
        "EnableAutoHealing": "true",
        "AutoAssignElasticIps": "false",
        "AutoAssignPublicIps": "true",
        "CustomSecurityGroupIds": [
          {
            "Ref": "OpsWorksSecurityGroup"
          }
        ]
      }
    },
    "OpsWorksInstance1": {
      "Type": "AWS::OpsWorks::Instance",
      "Properties": {
        "StackId": {
          "Ref": "OpsWorksStack"
        },
        "LayerIds": [
          {
            "Ref": "OpsWorksLayer"
          }
        ],
        "InstanceType": "m1.small"
      }
    },
    "OpsWorksInstance2": {
      "Type": "AWS::OpsWorks::Instance",
      "Properties": {
        "StackId": {
          "Ref": "OpsWorksStack"
        },
        "LayerIds": [
          {
            "Ref": "OpsWorksLayer"
          }
        ],
        "InstanceType": "m1.small"
      }
    },
    "OpsWorksApp": {
      "Type": "AWS::OpsWorks::App",
      "Properties": {
        "StackId": {
          "Ref": "OpsWorksStack"
        },
        "Name": "MyPHPApp",
        "Type": "php",
        "AppSource": {
          "Type": "git",
          "Url": "git://github.com/amazonwebservices/opsworks-demo-php-simple-app.git",
          "Revision": "version1"
        },
        "Attributes": {
          "DocumentRoot": " "
        }
      }
    },
    "OpsWorksServiceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "opsworks.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "Policies": [
          {
            "PolicyName": "opsworks-service",
            "PolicyDocument": {
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "ec2:*",
                    "iam:PassRole",
                    "cloudwatch:GetMetricStatistics",
                    "elasticloadbalancing:*"
                  ],
                  "Resource": "*"
                }
              ]
            }
          }
        ]
      }
    },
    "OpsWorksInstanceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/"
      }
    },
    "OpsWorksInstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [
          {
            "Ref": "OpsWorksInstanceRole"
          }
        ]
      }
    },
    "OpsWorksSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription" : "Allow inbound requests from the ELB to the OpsWorks instances",
        "VpcId": {
          "Ref": "VPC"
        },
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": "80",
            "ToPort": "80",
            "SourceSecurityGroupId": {
              "Ref": "ELBSecurityGroup"
            }
          }
        ]
      }
    },
    "ELB": {
      "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties": {
        "SecurityGroups": [
          {
            "Ref": "ELBSecurityGroup"
          }
        ],
        "Subnets": [
          {
            "Ref": "PublicSubnet"
          }
        ],
        "Listeners": [
          {
            "LoadBalancerPort": "80",
            "InstancePort": "80",
            "Protocol": "HTTP"
          }
        ],
        "HealthCheck": {
          "Target": "HTTP:80/",
          "HealthyThreshold": "3",
          "UnhealthyThreshold": "5",
          "Interval": "90",
          "Timeout": "60"
        }
      }
    },
    "ELBAttachment": {
      "Type": "AWS::OpsWorks::ElasticLoadBalancerAttachment",
      "Properties": {
        "ElasticLoadBalancerName": {
          "Ref": "ELB"
        },
        "LayerId": {
          "Ref": "OpsWorksLayer"
        }
      }
    },
    "ELBSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription" : "Allow inbound access to the ELB",
        "VpcId": {
          "Ref": "VPC"
        },
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": "80",
            "ToPort": "80",
            "CidrIp": "0.0.0.0/0"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "tcp",
            "FromPort": "80",
            "ToPort": "80",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "DependsOn": "OpsWorksServiceRole",
      "Properties": {
        "CidrBlock": {
          "Fn::FindInMap": [
            "SubnetConfig",
            "VPC",
            "CIDR"
          ]
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          }
        ]
      }
    },
    "PublicSubnet": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": [
            "SubnetConfig",
            "Public",
            "CIDR"
          ]
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          }
        ]
      }
    },
    "InternetGateway": {
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          }
        ]
      }
    },
    "VPCGatewayAttachment": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "InternetGatewayId": {
          "Ref": "InternetGateway"
        }
      }
    },
    "PublicRouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          }
        ]
      }
    },
    "PublicRoute": {
      "Type": "AWS::EC2::Route",
      "DependsOn": "VPCGatewayAttachment",
      "Properties": {
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        },
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {
          "Ref": "InternetGateway"
        }
      }
    },
    "PublicSubnetRouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet"
        },
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        }
      }
    },
    "PublicNetworkAcl": {
      "Type": "AWS::EC2::NetworkAcl",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          }
        ]
      }
    },
    "InboundHTTPPublicNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        },
        "RuleNumber": "100",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "false",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "80",
          "To": "80"
        }
      }
    },
    "InboundHTTPSPublicNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        },
        "RuleNumber": "101",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "false",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "443",
          "To": "443"
        }
      }
    },
    "InboundSSHPublicNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        },
        "RuleNumber": "102",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "false",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "22",
          "To": "22"
        }
      }
    },
    "InboundEmphemeralPublicNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        },
        "RuleNumber": "103",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "false",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "1024",
          "To": "65535"
        }
      }
    },
    "OutboundPublicNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        },
        "RuleNumber": "100",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "true",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "0",
          "To": "65535"
        }
      }
    },
    "PublicSubnetNetworkAclAssociation": {
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet"
        },
        "NetworkAclId": {
          "Ref": "PublicNetworkAcl"
        }
      }
    },
    "PrivateSubnet": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": [
            "SubnetConfig",
            "Private",
            "CIDR"
          ]
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Name",
            "Value": "Private"
          }
        ]
      }
    },
    "PrivateRouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          }
        ]
      }
    },
    "PrivateSubnetRouteTableAssociation": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet"
        },
        "RouteTableId": {
          "Ref": "PrivateRouteTable"
        }
      }
    },
    "PrivateRoute": {
      "Type": "AWS::EC2::Route",
      "Properties": {
        "RouteTableId": {
          "Ref": "PrivateRouteTable"
        },
        "DestinationCidrBlock": "0.0.0.0/0",
        "InstanceId": {
          "Ref": "NATDevice"
        }
      }
    },
    "PrivateNetworkAcl": {
      "Type": "AWS::EC2::NetworkAcl",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [
          {
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          }
        ]
      }
    },
    "InboundPrivateNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PrivateNetworkAcl"
        },
        "RuleNumber": "100",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "false",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "0",
          "To": "65535"
        }
      }
    },
    "OutBoundPrivateNetworkAclEntry": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "NetworkAclId": {
          "Ref": "PrivateNetworkAcl"
        },
        "RuleNumber": "100",
        "Protocol": "6",
        "RuleAction": "allow",
        "Egress": "true",
        "CidrBlock": "0.0.0.0/0",
        "PortRange": {
          "From": "0",
          "To": "65535"
        }
      }
    },
    "PrivateSubnetNetworkAclAssociation": {
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet"
        },
        "NetworkAclId": {
          "Ref": "PrivateNetworkAcl"
        }
      }
    },
    "NATIPAddress": {
      "Type": "AWS::EC2::EIP",
      "Properties": {
        "Domain": "vpc",
        "InstanceId": {
          "Ref": "NATDevice"
        }
      }
    },
    "NATDevice": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "InstanceType": "m1.small",
        "SubnetId": {
          "Ref": "PublicSubnet"
        },
        "SourceDestCheck": "false",
        "ImageId": {
          "Fn::FindInMap": [
            "AWSNATAMI",
            {
              "Ref": "AWS::Region"
            },
            "AMI"
          ]
        },
        "SecurityGroupIds": [
          {
            "Ref": "NATSecurityGroup"
          }
        ]
      }
    },
    "NATSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription" : "Allow OpsWorks instances to access the NAT Device",
        "VpcId": {
          "Ref": "VPC"
        },
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": "80",
            "ToPort": "80",
            "SourceSecurityGroupId": {
              "Ref": "OpsWorksSecurityGroup"
            }
          },
          {
            "IpProtocol": "tcp",
            "FromPort": "9418",
            "ToPort": "9418",
            "SourceSecurityGroupId": {
              "Ref": "OpsWorksSecurityGroup"
            }
          },
          {
            "IpProtocol": "tcp",
            "FromPort": "443",
            "ToPort": "443",
            "SourceSecurityGroupId": {
              "Ref": "OpsWorksSecurityGroup"
            }
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "tcp",
            "FromPort": "80",
            "ToPort": "80",
            "CidrIp": "0.0.0.0/0"
          },
          {
            "IpProtocol": "tcp",
            "FromPort": "9418",
            "ToPort": "9418",
            "CidrIp": "0.0.0.0/0"
          },
          {
            "IpProtocol": "tcp",
            "FromPort": "443",
            "ToPort": "443",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    }
  },
  "Outputs": {
    "StackId": {
      "Value": {
        "Ref": "OpsWorksStack"
      }
    },
    "AppId": {
      "Value": {
        "Ref": "OpsWorksApp"
      }
    },
    "VPC": {
      "Description": "VPC",
      "Value": {
        "Ref": "VPC"
      }
    },
    "PublicSubnet": {
      "Value": {
        "Ref": "PublicSubnet"
      }
    },
    "PrivateSubnet": {
      "Value": {
        "Ref": "PrivateSubnet"
      }
    },
    "ELB": {
      "Value": {
        "Ref": "ELB"
      }
    }
  }
}