Skip to content

Instantly share code, notes, and snippets.

@mattkaar
Last active October 27, 2020 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattkaar/8345e39c8184897d1feac05bc7b8f512 to your computer and use it in GitHub Desktop.
Save mattkaar/8345e39c8184897d1feac05bc7b8f512 to your computer and use it in GitHub Desktop.
AIA Cloud Security Lab
---
AWSTemplateFormatVersion: '2010-09-09'
Description: AIA CloudFormation Lab
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
InstanceType:
Description: Type for each EC2 instance
Type: String
Default: t2.micro
AllowedValues:
- t2.nano
- t2.micro
- t2.small
- t2.medium
- t2.large
ConstraintDescription: must be a valid EC2 instance type.
OperatorEmail:
Description: Email address for SNS notifications
Type: String
AllowedPattern: ^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$
ConstraintDescription: must be a valid email address.
SSHLocation:
Description: The IP address range that can be used to SSH to the EC2 instances
Type: String
MinLength: 9
MaxLength: 18
Default: 0.0.0.0/0
AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
Resources:
LogRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
- vpc-flow-logs.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
LogRoleInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- Ref: LogRole
EC2Server:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
yum:
amazon-cloudwatch-agent: []
files:
'/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json':
content: !Sub |
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [{
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log",
"log_stream_name": "{instance_id}/var/log/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log",
"timestamp_format": "%Y-%m-%dT%H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/amazon/amazon-cloudwatch-agent/configuration-validation.log",
"log_stream_name": "{instance_id}/var/log/amazon/amazon-cloudwatch-agent/configuration-validation.log",
"timestamp_format": "%Y/%m/%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/amazon/ssm/amazon-ssm-agent.log",
"log_stream_name": "{instance_id}/var/log/amazon/ssm/amazon-ssm-agent.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/amazon/ssm/errors.log",
"log_stream_name": "{instance_id}/var/log/amazon/ssm/errors.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/audit/audit.log",
"log_stream_name": "{instance_id}/var/log/audit/audit.log"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/boot.log",
"log_stream_name": "{instance_id}/var/log/boot.log"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cfn-hup.log",
"log_stream_name": "{instance_id}/var/log/cfn-hup.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cfn-init-cmd.log",
"log_stream_name": "{instance_id}/var/log/cfn-init-cmd.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cfn-init.log",
"log_stream_name": "{instance_id}/var/log/cfn-init.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cfn-wire.log",
"log_stream_name": "{instance_id}/var/log/cfn-wire.log",
"timestamp_format": "%Y-%m-%d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cloud-init-output.log",
"log_stream_name": "{instance_id}/var/log/cloud-init-output.log"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cloud-init.log",
"log_stream_name": "{instance_id}/var/log/cloud-init.log",
"timestamp_format": "%b %d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/cron",
"log_stream_name": "{instance_id}/var/log/cron",
"timestamp_format": "%b %-d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/dmesg",
"log_stream_name": "{instance_id}/var/log/dmesg"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/grubby_prune_debug",
"log_stream_name": "{instance_id}/var/log/grubby_prune_debug"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/maillog",
"log_stream_name": "{instance_id}/var/log/maillog",
"timestamp_format": "%b %-d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/messages",
"log_stream_name": "{instance_id}/var/log/messages",
"timestamp_format": "%b %-d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/secure",
"log_stream_name": "{instance_id}/var/log/secure",
"timestamp_format": "%b %-d %H:%M:%S"
}, {
"log_group_name": "${ServerLogGroup}",
"file_path": "/var/log/yum.log",
"log_stream_name": "{instance_id}/var/log/yum.log",
"timestamp_format": "%b %d %H:%M:%S"
}]
}
}
},
"metrics": {
"append_dimensions": {
"InstanceId": "${!aws:InstanceId}"
},
"metrics_collected": {
"mem": {
"measurement": [
"mem_used_percent"
]
},
"swap": {
"measurement": [
"swap_used_percent"
]
},
"disk": {
"resources": [
"/"
],
"measurement": [
"used_percent"
],
"drop_device": true
}
}
}
}
services:
sysvinit:
amazon-cloudwatch-agent:
enabled: "true"
ensureRunning: "true"
files:
- "/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json"
Properties:
InstanceType:
Ref: InstanceType
SecurityGroups:
- Ref: InstanceSecurityGroup
KeyName:
Ref: KeyName
ImageId: ami-0947d2ba12ee1ff75
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
VolumeSize: 8
DeleteOnTermination: true
Encrypted: true
Monitoring: true
HibernationOptions:
Configured: true
IamInstanceProfile:
Ref: LogRoleInstanceProfile
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-server'
UserData: !Base64
'Fn::Join':
- ''
- - |
#!/bin/bash -xe
- |
# Install the files and packages from the metadata
- '/opt/aws/bin/cfn-init -v '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource EC2Server '
- ' --region '
- !Ref 'AWS::Region'
- |+
- |
# Signal the status from cfn-init
- '/opt/aws/bin/cfn-signal -e $? '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource EC2Server '
- ' --region '
- !Ref 'AWS::Region'
- |+
CreationPolicy:
ResourceSignal:
Timeout: PT5M
EC2Analysis:
Type: AWS::EC2::Instance
Properties:
InstanceType:
Ref: InstanceType
SecurityGroups:
- Ref: InstanceSecurityGroup
KeyName:
Ref: KeyName
ImageId: ami-0dba2cb6798deb6d8
Monitoring: true
IamInstanceProfile:
Ref: LogRoleInstanceProfile
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-analysis'
UserData: !Base64 |
#!/bin/bash
apt update
apt full-upgrade -y
apt install -y hydra nmap sleuthkit
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable SSH access via port 22
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp:
Ref: SSHLocation
ServerLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 7
# InvalidUser and InvalidUserAlarm:
# When a user tries to SSH with invalid username the next line is logged in the SSH log file:
# Apr 20 02:39:35 ip-172-31-63-56 sshd[17136]: Received disconnect from xxx.xxx.xxx.xxx: 11: [preauth]
InvalidUser:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName:
Ref: ServerLogGroup
FilterPattern: "[Mon, day, timestamp, ip, id, status = Invalid, ...]"
MetricTransformations:
- MetricValue: '1'
MetricNamespace: SSH
MetricName: sshInvalidUser
InvalidUserAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: The number of invalid users is greater than 2 over 1 minutes
MetricName: sshInvalidUser
Namespace: SSH
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 2
AlarmActions:
- Ref: AlarmNotificationTopic
ComparisonOperator: GreaterThanThreshold
SSHReceiveddisconnect:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName:
Ref: ServerLogGroup
FilterPattern: "[Mon, day, timestamp, ip, id, msg1, msg2 = disconnect, ...]"
MetricTransformations:
- MetricValue: '1'
MetricNamespace: SSH
MetricName: sshDisconnect
SSHReceiveddisconnectAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: The number disconnect requests is greater then 10 in 5 minutes
MetricName: sshDisconnect
Namespace: SSH
Statistic: Sum
Period: 60
EvaluationPeriods: 5
Threshold: 10
AlarmActions:
- Ref: AlarmNotificationTopic
ComparisonOperator: GreaterThanThreshold
AlarmNotificationTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint:
Ref: OperatorEmail
Protocol: email
Outputs:
InstanceId:
Description: InstanceId of the newly created EC2 instance
Value:
Ref: EC2Server
AZ:
Description: Availability Zone of the newly created EC2 instance
Value:
Fn::GetAtt:
- EC2Server
- AvailabilityZone
PublicDNS:
Description: Public DNSName of the newly created EC2 instance
Value:
Fn::GetAtt:
- EC2Server
- PublicDnsName
PublicIP:
Description: Public IP address of the newly created EC2 instance
Value:
Fn::GetAtt:
- EC2Server
- PublicIp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment