Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
669 lines (630 sloc) 20.4 KB
#
# Tutorial CloudFormation Template
#
# This template will provision a new Virtual Private Cloud and split it into a
# public and private subnet. A web server will be provisioned in the public
# subnet and a database server will be provisioned in the private subnet.
#
Description: Provisions a simple cluster with a web and database server
Parameters:
KeyPairName:
Type: String
Description: The name of the keypair used when provisioning instances
InstanceType:
Type: String
Description: Instance type to provision
Default: t2.micro
ImageId:
Type: String
Description: Image to use when provisioning instances
Default: ami-035be7bafff33b6b6 # Amazon Linux 2
VolumeSize:
Type: Number
Description: Size of the volume in GB
Default: 250
RootDevice:
Type: String
Description: Name of the root device on provisioned instances
Default: xvda # varies based on Linux type (Ubunut /dev/sda1)
RootFsType:
Type: String
Description: File system type for root device
Default: xfs
Resources:
#
# Virtual Private Network to hold our resources
#
TutorialVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: "10.6.0.0/24"
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: "Name"
Value: "Tutorial VPC"
#
# Internet Gateway
#
TutorialInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: "Name"
Value: "Internet Gateway"
TutorialVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref TutorialVPC
InternetGatewayId: !Ref TutorialInternetGateway
#
# Subnets
#
TutorialPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref TutorialVPC
CidrBlock: "10.6.0.0/25"
MapPublicIpOnLaunch: true
Tags:
- Key: "Name"
Value: "Public Subnet"
TutorialPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref TutorialVPC
CidrBlock: "10.6.0.128/25"
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Private Subnet"
#
# Routing
#
TutorialPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref TutorialVPC
Tags:
- Key: "Name"
Value: "Public Internet Route Table"
TutorialPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref TutorialVPC
Tags:
- Key: "Name"
Value: "Private Route Table"
TutorialInternetRoute:
Type: AWS::EC2::Route
DependsOn: TutorialVPCGatewayAttachment
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref TutorialInternetGateway
RouteTableId: !Ref TutorialPublicRouteTable
TutorialNatGatewaySubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref TutorialVPC
Tags:
- Key: "Name"
Value: "NAT Gateway Subnet Route Table"
TutorialNatGatewayInternetRoute:
Type: AWS::EC2::Route
DependsOn: TutorialVPCGatewayAttachment
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref TutorialInternetGateway
RouteTableId: !Ref TutorialNatGatewaySubnetRouteTable
TutorialNatGatewayElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
TutorialNatGateway:
Type: AWS::EC2::NatGateway
DependsOn: TutorialVPCGatewayAttachment
Properties:
AllocationId: !Sub ${TutorialNatGatewayElasticIP.AllocationId}
SubnetId: !Ref TutorialPublicSubnet
Tags:
- Key: "Name"
Value: "NAT Gateway"
TutorialPrivateSubnetNatRoute:
Type: AWS::EC2::Route
DependsOn: TutorialNatGateway
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref TutorialNatGateway
RouteTableId: !Ref TutorialPrivateRouteTable
TutorialPublicSubnetRouteAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref TutorialPublicRouteTable
SubnetId: !Ref TutorialPublicSubnet
TutorialPrivateSubnetRouteAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref TutorialPrivateRouteTable
SubnetId: !Ref TutorialPrivateSubnet
#
# Security Groups
#
TutorialPublicSecurityGroup:
Type: AWS::EC2::SecurityGroup
Description: "Public Security Group"
Properties:
VpcId: !Ref TutorialVPC
GroupDescription: Web Server Security Group
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: 80 # HTTP
ToPort: 80
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: 443 # HTTPS
ToPort: 443
- CidrIp: 0.0.0.0/0 # Replace with your IP Range
IpProtocol: tcp
FromPort: 3389 # MS Remote Desktop
ToPort: 3389
- CidrIp: 0.0.0.0/0 # Replace with your IP Range
IpProtocol: tcp
FromPort: 22 # SSH
ToPort: 22
- CidrIp: 10.6.0.0/24 # Inside the VPC
IpProtocol: -1 # All traffic
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: 80 # HTTP
ToPort: 80
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: 443 # HTTPS
ToPort: 443
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: 587 # SSL SMTP
ToPort: 587
- CidrIp: 10.6.0.0/24 # Inside the VPC
IpProtocol: -1 # All traffic
Tags:
- Key: "Name"
Value: "Public Subnet"
TutorialPrivateSecurityGroup:
Type: AWS::EC2::SecurityGroup
Description: "Private Security Group"
Properties:
VpcId: !Ref TutorialVPC
GroupDescription: Private Subnet Security Group
SecurityGroupIngress:
- CidrIp: 10.6.0.0/24 # Inside the VPC
IpProtocol: -1 # All traffic
SecurityGroupEgress:
- CidrIp: 10.6.0.0/24 # Inside the VPC
IpProtocol: -1 # All traffic
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: '80' # HTTP
ToPort: '80'
- CidrIp: 0.0.0.0/0 # Public Internet
IpProtocol: tcp
FromPort: '443' # HTTPS
ToPort: '443'
Tags:
- Key: "Name"
Value: "Private Subnet"
#
# S3 Bucket for Backups
#
TutorialBackupS3Bucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
AccessControl: Private
Tags:
- Key: "Name"
Value: "Backup Bucket"
#
# Administrator IAM Group
#
TutorialAdminGroup:
Type: AWS::IAM::Group
Properties:
Policies:
- PolicyName: TutorialAdminPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketByTags
- s3:ListBucketMultipartUploads
- s3:ListBucketVersions
Resource: !Sub ${TutorialBackupS3Bucket.Arn}
- Effect: Allow
Action:
- s3:PutObject
- s3:DeleteObject
- s3:GetObject
Resource: !Sub ${TutorialBackupS3Bucket.Arn}/*
#
# Role and Policies for Instances
#
TutorialInstanceRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
- arn:aws-us-gov:iam::aws:policy/CloudWatchAgentServerPolicy # Allow CloudWatch Agent to run on servers
- arn:aws-us-gov:iam::aws:policy/service-role/AmazonEC2RoleforSSM # Allow SSM Agent Access to CloudWatch
- arn:aws-us-gov:iam::aws:policy/AmazonSSMReadOnlyAccess # Allow instance to read SSM parameters
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
TutorialInstanceRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: TutorialInstanceRolePolicy
Roles:
- Ref: TutorialInstanceRole
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketByTags
- s3:ListBucketMultipartUploads
- s3:ListBucketVersions
Resource: !Sub ${TutorialBackupS3Bucket.Arn}
- Effect: Allow
Action:
- s3:PutObject
- s3:DeleteObject
- s3:GetObject
Resource: !Sub ${TutorialBackupS3Bucket.Arn}/*
TutorialInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref TutorialInstanceRole
#
# Log Groups
#
TutorialBootLog:
Type: AWS::Logs::LogGroup
TutorialKernelLog:
Type: AWS::Logs::LogGroup
#
# Instances
#
TutorialDatabaseServer:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
files:
/etc/profile.d/cloudformation-init.sh:
content: !Sub |
export BACKUP_S3_BUCKET="${TutorialBackupS3Bucket}"
/etc/amazon/amazon-cloudwatch-agent.json:
content: !Sub |
{
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${!aws:AutoScalingGroupName}",
"ImageId": "${!aws:ImageId}",
"InstanceId": "${!aws:InstanceId}",
"InstanceType": "${!aws:InstanceType}"
},
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 30,
"totalcpu": false
},
"disk": {
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 30,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time"
],
"metrics_collection_interval": 30,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 30
},
"statsd": {
"metrics_aggregation_interval": 30,
"metrics_collection_interval": 10,
"service_address": ":8125"
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 30
}
}
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"log_group_name": "${TutorialBootLog}",
"file_path": "/var/log/boot.log"
},
{
"log_group_name": "${TutorialKernelLog}",
"file_path": "/var/log/messages"
}
]
}
}
}
}
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
KeyName: !Ref KeyPairName
NetworkInterfaces:
- SubnetId: !Ref TutorialPrivateSubnet
DeviceIndex: 0
GroupSet:
- !Ref TutorialPrivateSecurityGroup
BlockDeviceMappings:
- DeviceName: !Sub "/dev/${RootDevice}"
Ebs:
VolumeSize: !Ref VolumeSize
VolumeType: gp2
IamInstanceProfile: !Ref TutorialInstanceProfile
Tags:
- Key: "Name"
Value: "Tutorial Database Server"
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
# cloudformation initialize
/opt/aws/bin/cfn-init -v -s ${AWS::StackName} --region ${AWS::Region} -r TutorialDatabaseServer
# download and install cloudwatch agent
wget https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
yum -y install amazon-cloudwatch-agent.rpm
mv /etc/amazon/amazon-cloudwatch-agent.json /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json
sudo systemctl enable amazon-cloudwatch-agent
sudo systemctl start amazon-cloudwatch-agent
TutorialWebServer:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
files:
/etc/profile.d/cloudformation-init.sh:
content: !Sub |
export BACKUP_S3_BUCKET="${TutorialBackupS3Bucket}"
export DATABASE_SERVER="${TutorialDatabaseServer.PrivateIp}"
/etc/amazon/amazon-cloudwatch-agent.json:
content: !Sub |
{
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${!aws:AutoScalingGroupName}",
"ImageId": "${!aws:ImageId}",
"InstanceId": "${!aws:InstanceId}",
"InstanceType": "${!aws:InstanceType}"
},
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 30,
"totalcpu": false
},
"disk": {
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 30,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time"
],
"metrics_collection_interval": 30,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 30
},
"statsd": {
"metrics_aggregation_interval": 30,
"metrics_collection_interval": 10,
"service_address": ":8125"
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 30
}
}
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"log_group_name": "${TutorialBootLog}",
"file_path": "/var/log/boot.log"
},
{
"log_group_name": "${TutorialKernelLog}",
"file_path": "/var/log/messages"
}
]
}
}
}
}
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
KeyName: !Ref KeyPairName
NetworkInterfaces:
- SubnetId: !Ref TutorialPublicSubnet
DeviceIndex: 0
GroupSet:
- !Ref TutorialPublicSecurityGroup
BlockDeviceMappings:
- DeviceName: !Sub "/dev/${RootDevice}"
Ebs:
VolumeSize: !Ref VolumeSize
VolumeType: gp2
IamInstanceProfile: !Ref TutorialInstanceProfile
Tags:
- Key: "Name"
Value: "Tutorial Web Server"
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
# cloudformation initialize
/opt/aws/bin/cfn-init -v -s ${AWS::StackName} --region ${AWS::Region} -r TutorialWebServer
# download and install cloudwatch agent
wget https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
yum -y install amazon-cloudwatch-agent.rpm
mv /etc/amazon/amazon-cloudwatch-agent.json /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.json
sudo systemctl enable amazon-cloudwatch-agent
sudo systemctl start amazon-cloudwatch-agent
#
# Topic for monitoring alarms
#
# Subscriptions may be created through the SNS console (i.e. email, SMS, etc.)
#
TutorialAlarmTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: TutorialAlarms
#
# Alarms
#
TutorialDatabaseCPUAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Database Server CPU Usage High
AlarmActions:
- !Ref TutorialAlarmTopic
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 60
EvaluationPeriods: 3
Threshold: 89
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: InstanceId
Value: !Ref TutorialDatabaseServer
TutorialDatabaseDiskAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Database Server Disk Usage High
AlarmActions:
- !Ref TutorialAlarmTopic
MetricName: disk_used_percent
Namespace: CWAgent
Statistic: Average
Period: 60
EvaluationPeriods: 3
Threshold: 89
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: InstanceId
Value: !Ref TutorialDatabaseServer
- Name: ImageId
Value: !Ref ImageId
- Name: InstanceType
Value: !Ref InstanceType
- Name: path
Value: /
- Name: device
Value: !Sub ${RootDevice}1
- Name: fstype
Value: !Ref RootFsType
TutorialWebCPUAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Database Server CPU Usage High
AlarmActions:
- !Ref TutorialAlarmTopic
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 60
EvaluationPeriods: 3
Threshold: 89
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: InstanceId
Value: !Ref TutorialWebServer
TutorialWebDiskAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Web Server Disk Usage High
AlarmActions:
- !Ref TutorialAlarmTopic
MetricName: disk_used_percent
Namespace: CWAgent
Statistic: Average
Period: 60
EvaluationPeriods: 3
Threshold: 89
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: InstanceId
Value: !Ref TutorialWebServer
- Name: ImageId
Value: !Ref ImageId
- Name: InstanceType
Value: !Ref InstanceType
- Name: path
Value: /
- Name: device
Value: !Sub ${RootDevice}1
- Name: fstype
Value: !Ref RootFsType