πŸš€ Problem & Solution

πŸ“Œ Context / Backstory

We had a requirement to start a test EC2 instance automatically at 08:00 each morning. This server, called Tests01, was only needed during working hours, and we wanted to avoid manual intervention or running it 24/7.

⚠️ The Problem

  • Manual starts were unreliable and easy to forget.
  • CloudFormation alone doesn't handle timed triggers.
  • Lambda + CloudWatch Events provide scheduling, but managing them manually is messy.
  • We needed this fully automated and reproducible, ideally within infrastructure-as-code.

πŸ’‘ The Solution

We used Sceptre to deploy a CloudFormation template that provisions: - A CloudWatch rule triggered at 08:00 - A Lambda function that starts the Tests01 instance - All IAM roles and permissions necessary

πŸ‘₯ Who This Helps

  • DevOps engineers using AWS automation
  • Teams migrating from cron jobs to infrastructure-as-code
  • Anyone needing scheduled resource management in the cloud

βš™οΈ Technical Implementation

Let's visualize the automation flow:

flowchart LR CW[CloudWatch Event] L[Lambda Function] EC2[EC2 Instance] CW -->|"Trigger (08:00)"| L L -->|"StartInstances API"| EC2 subgraph "AWS Infrastructure" CW L EC2 end

1️⃣ Sceptre Project Setup

Project layout:

config/
  config.yaml
  dev/
    start-tests.yaml
templates/
  start-tests.yaml

Global config/config.yaml:

project_code: startup-project
region: eu-west-1

Stack config config/dev/start-tests.yaml:

template_path: start-tests.yaml
stack_name: start-tests-scheduler
parameters:
  InstanceId: i-0123456789abcdef0

2️⃣ CloudFormation Template

File: templates/start-tests.yaml

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  InstanceId:
    Type: String
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: StartInstance
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ec2:StartInstances
                Resource: "*"

  StartInstanceLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.9
      Timeout: 30
      Code:
        ZipFile: |
          import boto3
          import os
          def handler(event, context):
              ec2 = boto3.client('ec2')
              ec2.start_instances(InstanceIds=[os.environ['INSTANCE_ID']])
      Environment:
        Variables:
          INSTANCE_ID: !Ref InstanceId

  StartEventRule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: cron(0 8 * * ? *)
      Targets:
        - Arn: !GetAtt StartInstanceLambda.Arn
          Id: TargetFunctionV1

  PermissionForEventsToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref StartInstanceLambda
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt StartEventRule.Arn

πŸ› οΈ Troubleshooting & Debugging

  • Ensure the Lambda role has permissions to ec2:StartInstances.
  • Use aws lambda invoke to manually test the function.
  • Logs appear in CloudWatch Logs; confirm the instance ID is correct.
  • Validate your cron expression with AWS docs: cron(0 8 * * ? *) runs at 08:00 UTC.

πŸ” Optimizations & Alternatives

  • You can also add a second Lambda + CloudWatch rule to stop the instance at 18:00.
  • Consider replacing this with AWS Systems Manager Automation documents if you're not using CloudFormation.
  • If you're managing multiple instances, parameterize the instance list or use tags.

βœ… Conclusion & Takeaways

This setup gives you a reproducible, versioned, and automated method for managing instance scheduling using CloudFormation and Sceptre. It's a clean way to handle what would otherwise be a manual or error-prone taskβ€”and it fits directly into a GitOps-style workflow.

πŸ’¬ Comments & Next Steps

Have you implemented similar automation patterns with CloudFormation? Share your experience or ask questions below!