Skip to content

Instantly share code, notes, and snippets.

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 sagoyanfisic/d7e285c0ab963acc6df698227c70134b to your computer and use it in GitHub Desktop.
Save sagoyanfisic/d7e285c0ab963acc6df698227c70134b to your computer and use it in GitHub Desktop.
Yaml template to stop AWS Services like RDS, Aurora, EKS in scheduled interval
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Yaml template to stop AWS Services like RDS, Aurora, EKS in scheduled interval
Parameters:
#general params
ScheduleExpression:
Type: String
Description: Schedule expressions using cron
Default: cron(30 4 * * ? *)
ExcludeAuroraClusterArnListInCommaSeprated:
Description: Aurora Cluster arn list in comma separated which you don't want to stop. Please ignore if you want to stop all cluster
Type: String
Default: arn:aws:rds:us-east-1:111111111111:cluster:aurorcluster-1, arn:aws:rds:us-east-2:111111111111:cluster:auroracluster-2
ExcludeRDSDBInstancesArnListInCommaSeprated:
Description: RDS DB Instances list in comma separated which you don't want to stop. Please ignore if you want to stop all instances
Type: String
Default: arn:aws:rds:us-east-1:111111111111:db:rds-instance-1, arn:aws:rds:us-east-2:111111111111:db:rds-instance-2
ExcludeEKSClusterNodeGroupsArnListInCommaSeprated:
Description: Aurora Cluster arn list in comma separated which you don't want to stop. Please ignore if you want to stop all cluster
Type: String
Default: arn:aws:eks:us-east-2:111111111111:cluster/testcluster
ExcludeAutoScalingGroupIncludingBeanstalkListInCommaSeprated:
Description: AutoScaling (includng Beanstalk) Group arn list in comma separated which you don't want to stop. Please ignore if you want to stop all autoscalinggroup
Type: String
Default: arn:aws:autoscaling:us-east-1:111111111111:autoScalingGroup:6d5af669-eb3b-4530-894b-e314a667f2e7:autoScalingGroupName/test-0-ASG
ExcludeEC2InstancesIdListInCommaSeprated:
Description: Instance ID list in comma separated which you don't want to stop. Please ignore if you want to stop all Instances
Type: String
Default: i-02185df0872f0f852
# Static variable Mapping
Mappings:
StaticValue:
keyval:
CreatedBy: "Nirmal Singh Tomar"
Feature: "This cloud formation template will stop mentioned AWS services like ECS EKS RDS Aurora EC2 and ASG in scheduled interval."
Resources:
#lambda execution role config
StopServicesLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "stop-services-lambdarole"
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: 'LambdaSSMAssume'
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
StopServicesLambdaRolePolicy:
Type: AWS::IAM::Policy
DependsOn: [StopServicesLambdaRole]
Properties:
PolicyName: StopServicesLambdaRolePolicy
PolicyDocument:
Statement:
- Action: ["logs:DescribeLogStreams", "logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup"]
Resource: "*"
Effect: Allow
- Action: ["ec2:DescribeRegions", "ec2:DescribeInstances", "ec2:StopInstances", "autoscaling:Describe*", "autoscaling:UpdateAutoScalingGroup", "autoscaling:DescribeAutoScalingGroups"]
Resource: "*"
Effect: Allow
- Action: ["rds:DescribeDBInstances","rds:DescribeDBClusters", "rds:StopDBCluster", "rds:StopDBInstance"]
Resource: "*"
Effect: Allow
- Action: ["eks:ListClusters","eks:DescribeCluster", "eks:ListNodegroups", "eks:UpdateNodegroupConfig",]
Resource: "*"
Effect: Allow
Roles: [!Ref StopServicesLambdaRole]
# Function: StopAuroraCluster
#This Lambda Function will stop RDS services from all available AWS region except China.
StopAuroraCluster:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'StopAuroraCluster'
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import boto3
import os
ec2 = boto3.client('ec2')
# Retrieves all regions/endpoints that work with EC2
availableRegions = ec2.describe_regions()
#print('AWS Regions:', availableRegions['Regions'])
def lambda_handler(event, context):
#Print Exclude List
comma_seprated_exclude_List = os.environ.get('comma_seprated_exclude_List')
excludedList = list(comma_seprated_exclude_List.split(","))
print('excludedList:',excludedList)
for region in availableRegions['Regions']:
#print('region',region['RegionName'])
#List Aurora Cluster
client = boto3.client('rds',region_name=region['RegionName'])
response = client.describe_db_clusters(
IncludeShared=False
)
#To Stop Aurora Database
for dbCluster in response['DBClusters']:
if search(excludedList, dbCluster['DBClusterArn']):
print('---------------------------\nNot Stopping Aurora Cluster:', dbCluster['DBClusterArn'], 'as its in ignorance list')
elif dbCluster['Status'] == 'available' :
print('---------------------------\nStopping dbCluster Identifier ::',dbCluster['DBClusterArn'])
response = client.stop_db_cluster(DBClusterIdentifier=dbCluster['DBClusterIdentifier'])
print('Aurora cluster stop command successfully executed')
else :
print('--------------------------\n Ignoring Aurora Cluster:',dbCluster['DBClusterArn'] , 'as its not in started state, its existing state is ::',dbCluster['Status'] )
# Function for search in exclude list
def search(excludeList, instanceName):
for i in range(len(excludeList)):
if excludeList[i].strip() == instanceName :
return True
return False
Description: ''
MemorySize: 128
Timeout: 90
Role: !GetAtt StopServicesLambdaRole.Arn
Environment:
Variables:
comma_seprated_exclude_List: !Ref ExcludeAuroraClusterArnListInCommaSeprated
Tags:
- Key: "CreatedBy"
Value: !FindInMap [StaticValue, keyval, CreatedBy]
- Key: "Feature"
Value: !FindInMap [StaticValue, keyval, Feature]
#Cloud Watch config
StopAuroraClusterLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
RetentionInDays: 90
LogGroupName: !Join ["", ["/aws/lambda/", !Ref StopAuroraCluster]]
# Function: StopRDSInstances
#This Lambda Function will stop all RDS Instances except Aurora from all available AWS region except China.
StopRDSInstances:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'StopRDSInstances'
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import boto3
import os
ec2 = boto3.client('ec2')
# Retrieves all regions/endpoints that work with EC2
availableRegions = ec2.describe_regions()
def lambda_handler(event, context):
#Print Exclude List
comma_seprated_exclude_List = os.environ.get('comma_seprated_exclude_List')
excludedList = list(comma_seprated_exclude_List.split(","))
print('excludedList:',excludedList)
for region in availableRegions['Regions']:
rds = boto3.client('rds', region_name=region['RegionName'])
#List RDS Instances
listRDS = rds.describe_db_instances()
#To Stop RDS Database
for rdsInstances in listRDS['DBInstances']:
#print('-\n AWS region:',region['RegionName'])
#print('-\n listRDS::',listRDS)
if search(excludedList, rdsInstances['DBInstanceArn']) and (not(rdsInstances['Engine'].startswith('aurora'))):
print('---------------------------\nNot Stopping RDS Instance:' ,rdsInstances['DBInstanceArn'], ' as its in ignorance list')
elif rdsInstances['DBInstanceStatus'] =='available' and (not(rdsInstances['Engine'].startswith('aurora'))):
print('---------------------------\nStopping rds instance ::',rdsInstances['DBInstanceArn'])
response = rds.stop_db_instance(DBInstanceIdentifier=rdsInstances['DBInstanceIdentifier'])
print('RDS Instances stop command successfully executed')
elif not(rdsInstances['Engine'].startswith('aurora')):
print('--------------------------\n Ignoring RDS Instance:',rdsInstances['DBInstanceArn'] , 'as its not in started state, its existing state is ::',rdsInstances['DBInstanceStatus'] )
# Function for search in exclude list
def search(excludeList, instanceName):
for i in range(len(excludeList)):
if excludeList[i].strip() == instanceName:
return True
return False
Description: ''
MemorySize: 128
Timeout: 90
Role: !GetAtt StopServicesLambdaRole.Arn
Environment:
Variables:
comma_seprated_exclude_List: !Ref ExcludeRDSDBInstancesArnListInCommaSeprated
Tags:
- Key: "CreatedBy"
Value: !FindInMap [StaticValue, keyval, CreatedBy]
- Key: "Feature"
Value: !FindInMap [StaticValue, keyval, Feature]
#Cloud Watch config
StopRDSInstancesLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
RetentionInDays: 90
LogGroupName: !Join ["", ["/aws/lambda/", !Ref StopRDSInstances]]
# Function: ScaleDownEKSNodeGroups
#This Lambda Function will scale down all EKS NodeGroup across regions.
ScaleDownEKSNodeGroups:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'ScaleDownEKSNodeGroups'
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import json
import json
import boto3
import os
ec2 = boto3.client('ec2')
# Retrieves all regions/endpoints that work with EC2
availableRegions = ec2.describe_regions()
#print('AWS Regions:', availableRegions['Regions'])
def lambda_handler(event, context):
#Print Exclude List
comma_seprated_exclude_List = os.environ.get('comma_seprated_exclude_List')
excludedList = list(comma_seprated_exclude_List.split(","))
print('excludedList:',excludedList)
for region in availableRegions['Regions']:
#print('region',region['RegionName'])
eksClient = boto3.client('eks',region_name=region['RegionName'])
cluster_name_list = eksClient.list_clusters()
#print('cluster names',cluster_name_list['clusters'])
for clusterName in cluster_name_list['clusters']:
print('---------------------------\n region',region['RegionName'], 'clusterName::', clusterName)
eksCluster = eksClient.describe_cluster(name=clusterName)
#print('---------------------------\n dsccluster', dsccluster['cluster']['arn'])
if search(excludedList, eksCluster['cluster']['arn']):
print('Not Making any changes as EKS Cluster ARN ::', eksCluster['cluster']['arn'], ': is in ignorance list')
else :
#Code to get the node group list
node_group_list = eksClient.list_nodegroups(clusterName=clusterName)
#print('node_group_list::',node_group_list['nodegroups'])
for nodelist in node_group_list['nodegroups']:
#code to update node config
print('Scaling Down EKS Cluster Cluster ::', eksCluster['cluster']['arn'], 'Node Group:', nodelist)
response = eksClient.update_nodegroup_config(
clusterName=clusterName,
nodegroupName=nodelist,
scalingConfig={
'minSize': 0,
'maxSize': 1,
'desiredSize': 0
})
print('Scaling Down EKS Cluster Cluster ::', eksCluster['cluster']['arn'], 'Node Group:', nodelist, 'Completed')
# Function for search in exclude list
def search(excludeList, instanceName):
for i in range(len(excludeList)):
if excludeList[i].strip() == instanceName:
return True
return False
Description: ''
MemorySize: 128
Timeout: 90
Role: !GetAtt StopServicesLambdaRole.Arn
Environment:
Variables:
comma_seprated_exclude_List: !Ref ExcludeEKSClusterNodeGroupsArnListInCommaSeprated
Tags:
- Key: "CreatedBy"
Value: !FindInMap [StaticValue, keyval, CreatedBy]
- Key: "Feature"
Value: !FindInMap [StaticValue, keyval, Feature]
#Cloud Watch config
ScaleDownEKSNodeGroupsLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
RetentionInDays: 90
LogGroupName: !Join ["", ["/aws/lambda/", !Ref ScaleDownEKSNodeGroups]]
# Function: ScaleDownASG
#This Lambda Function will scale down all AutoScaling Group across regions.
ScaleDownASG:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'ScaleDownASG'
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import os
import boto3
ec2 = boto3.client('ec2')
# Retrieves all regions/endpoints that work with EC2
availableRegions = ec2.describe_regions()
#print('AWS Regions:', availableRegions['Regions'])
def lambda_handler(event, context):
#Print Exclude List
comma_seprated_exclude_List = os.environ.get('comma_seprated_exclude_List')
excludedList = list(comma_seprated_exclude_List.split(","))
print('excludedList:',excludedList)
for region in availableRegions['Regions']:
client = boto3.client('autoscaling',region_name=region['RegionName'])
autoscaling_grp_name = client.describe_auto_scaling_groups()
for autoscaling_grps in autoscaling_grp_name['AutoScalingGroups']:
print('----------------------------\n AWS region:',region['RegionName'])
#print(' AWSautoscaling_grps:',autoscaling_grps)
#print('Tages:',autoscaling_grps['Tags'])
#get_item_lambda = lambda collection, key, target : next((item for item in collection if item.get(key, None) == target), None)
if search(excludedList, autoscaling_grps['AutoScalingGroupARN']):
print('Not Changing Autoscaling group:', autoscaling_grps['AutoScalingGroupName'], ' as its in ignorance list')
elif (get_item(autoscaling_grps['Tags']) is not None):
print('Not Changing Autoscaling group:', autoscaling_grps['AutoScalingGroupName'], ' as its EKS AutoScaling Group')
else:
print('Scaling Down Autoscaling group:', autoscaling_grps['AutoScalingGroupName'])
response = client.update_auto_scaling_group(
AutoScalingGroupName=autoscaling_grps['AutoScalingGroupName'],
MinSize=0,
DesiredCapacity=0,
MaxSize=0
)
print('Scaling Down Autoscaling group:', autoscaling_grps['AutoScalingGroupName'], ':Completed')
# Function for search in exclude list
def search(excludeList, instanceName):
for i in range(len(excludeList)):
if excludeList[i].strip() == instanceName:
return True
return False
def get_item(collection):
key = "Key"
target = "eks:cluster-name"
return next((item for item in collection if item[key] == target), None)
Description: ''
MemorySize: 128
Timeout: 90
Role: !GetAtt StopServicesLambdaRole.Arn
Environment:
Variables:
comma_seprated_exclude_List: !Ref ExcludeAutoScalingGroupIncludingBeanstalkListInCommaSeprated
Tags:
- Key: "CreatedBy"
Value: !FindInMap [StaticValue, keyval, CreatedBy]
- Key: "Feature"
Value: !FindInMap [StaticValue, keyval, Feature]
#Cloud Watch config
ScaleDownASGLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
RetentionInDays: 90
LogGroupName: !Join ["", ["/aws/lambda/", !Ref ScaleDownASG]]
# Function: StopEc2
#This Lambda Function will stop EC2 machine from all available AWS region except China.
StopEC2:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'StopEC2'
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import os
import boto3
ec2 = boto3.client('ec2')
# Retrieves all regions/endpoints that work with EC2
availableRegions = ec2.describe_regions()
#print('AWS Regions:', availableRegions['Regions'])
def lambda_handler(event, context):
#Print Exclude List
comma_seprated_exclude_List = os.environ.get('comma_seprated_exclude_List')
excludedList = list(comma_seprated_exclude_List.split(","))
print('excludedList:',excludedList)
for region in availableRegions['Regions']:
#print(region['RegionName'])
ec2 = boto3.resource('ec2', region_name=region['RegionName'])
running_instances = ec2.instances.filter(Filters=[{'Name': 'instance-state-name','Values': ['running']}])
for instance in running_instances:
print('----------------------------\n region:',region['RegionName'], ' instance.id:', instance.id)
if search(excludedList, instance.id):
print('Not Stoping Instance :', instance.id, ' as its in ignorance list')
else:
print('Stoping instance::', instance.id)
ec2 = boto3.client('ec2', region_name=region['RegionName'])
ec2.stop_instances(InstanceIds=[instance.id])
print('Stoping instance::', instance.id, ' Completed')
# Function for search in exclude list
def search(excludeList, instanceName):
for i in range(len(excludeList)):
if excludeList[i].strip() == instanceName:
return True
return False
Description: ''
MemorySize: 128
Timeout: 60
Role: !GetAtt StopServicesLambdaRole.Arn
Environment:
Variables:
comma_seprated_exclude_List: !Ref ExcludeEC2InstancesIdListInCommaSeprated
Tags:
- Key: "CreatedBy"
Value: !FindInMap [StaticValue, keyval, CreatedBy]
- Key: "Feature"
Value: !FindInMap [StaticValue, keyval, Feature]
#Cloud Watch config
StopEC2LogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
RetentionInDays: 90
LogGroupName: !Join ["", ["/aws/lambda/", !Ref StopEC2]]
#AWS StepFunction workflow to stop services in preconfigured time
StateMachineSchedulerExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
- states.amazonaws.com
Action: "sts:AssumeRole"
Policies:
- PolicyName: InvokeCloudWatchEvent
PolicyDocument:
Statement:
- Action: ["states:startexecution"]
Resource: "*"
Effect: Allow
- Effect: Allow
Action:
- "events:DescribeRule"
Resource:
- "*"
StepFunctionLambdaExecutinRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: "sts:AssumeRole"
Policies:
- PolicyName: InvokeCallbackLambda
PolicyDocument:
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource:
- "*"
WorkflowToStopServicesInScheduledInterval:
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: State_Machine_Workflow_To_Stop_Services_In_Scheduled_Interval
DefinitionString:
!Sub
- |-
{
"Comment": "State machine Workflow to Stop AWS Services at scheduled interval",
"StartAt": "Parallel",
"States": {
"Parallel": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "StopAuroraCluster",
"States": {
"StopAuroraCluster": {
"Type": "Task",
"Resource": "${StopAuroraCluster.Arn}",
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 20,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"End": true
}
}
},
{
"StartAt": "StopRDSInstances",
"States": {
"StopRDSInstances": {
"Type": "Task",
"Resource": "${StopRDSInstances.Arn}",
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"End": true,
"TimeoutSeconds": 60
}
}
},
{
"StartAt": "ScaleDownASG",
"States": {
"ScaleDownASG": {
"Type": "Task",
"Resource": "${ScaleDownASG.Arn}",
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"Next": "Wait"
},
"Wait": {
"Type": "Wait",
"Seconds": 60,
"Next": "StopEC2Instances"
},
"StopEC2Instances": {
"Type": "Task",
"Resource": "${StopEC2.Arn}",
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"End": true
}
}
},
{
"StartAt": "ScaleDownEKSNodeGroups",
"States": {
"ScaleDownEKSNodeGroups": {
"Type": "Task",
"Resource": "${ScaleDownEKSNodeGroups.Arn}",
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"End": true,
"TimeoutSeconds": 60
}
}
}
],
"End": true
}
}
}
- {ScaleDownEKSNodeGroupsArn: !GetAtt [ ScaleDownEKSNodeGroups, Arn ]}
RoleArn: !GetAtt StepFunctionLambdaExecutinRole.Arn
StopAWSServicesWorkFlowScheduler:
Type: AWS::Events::Rule
DependsOn: [WorkflowToStopServicesInScheduledInterval]
Properties:
Description: To Trigger the Step Function for Stop AWS services
Name: StopAWSServicesScheduler
RoleArn: !GetAtt StateMachineSchedulerExecutionRole.Arn
ScheduleExpression: !Ref ScheduleExpression
State: ENABLED
Targets:
-
Arn: !Ref WorkflowToStopServicesInScheduledInterval
Id: "TargetFunctionV1"
RoleArn: !GetAtt StateMachineSchedulerExecutionRole.Arn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment