Skip to content
malak.cloud
  • Contact
  • Przemek Malak
  • Search Icon

malak.cloud

Cloud-native in everyday life

Automatically Start EC2 and RDS on a Schedule Using AWS Step Functions

Automatically Start EC2 and RDS on a Schedule Using AWS Step Functions

22 września 2025

Introduction

If you’re running non-production AWS environments — development, staging, QA — there’s a good chance your EC2 instances and RDS databases are sitting idle for 16 hours a day, quietly burning through your cloud budget. Nights, weekends, holidays: the meter keeps running even when nobody’s working.

The obvious fix is to stop resources when they’re not needed and start them back up when they are. The problem is doing that reliably without babysitting it manually every morning, and without accidentally forgetting to bring something up before the team arrives.

This post walks through a small open-source project I built to solve exactly that. It uses three native AWS services — EventBridge, Step Functions, and the AWS SDK integration built into Step Functions — to automatically start EC2 instances and RDS databases on a schedule. No Lambda functions, no custom runtime code to maintain. Just a config file and a CDK stack you deploy once and forget about.

What This Project Does

This project is a serverless automation tool built with AWS CDK (Python) that automatically starts EC2 instances and RDS databases on a schedule — so you don’t pay for compute time when nobody’s using it.

The Problem It Solves

In dev/staging environments, you typically don’t need servers running overnight or on weekends. Manually starting them each morning is tedious and error-prone. This project fully automates that workflow.

Architecture

EventBridge Rule(s)  →  AWS Step Function  →  EC2 / RDS Resources
   (cron schedule)        (orchestrator)        (started/rebooted)

Three AWS services are wired together:

  1. Amazon EventBridge — fires on a cron schedule (e.g. „8:00 AM Mon–Fri”)
  2. AWS Step Functions — receives the event and processes a list of resources one by one, with optional delays between each
  3. EC2 / RDS SDK calls — the Step Function calls AWS APIs directly (no Lambda needed) to start instances and clusters

What It Can Do

  • Start EC2 instances on a schedule
  • Reboot EC2 instances on a schedule
  • Start RDS DB clusters (Aurora)
  • Start RDS DB instances
  • Multiple independent schedules — e.g. a dev group starts at 8 AM and a QA group starts at 9 AM
  • Sequential startup with configurable delays — useful when the App Server must wait for the database to come up first
  • Least-privilege IAM — the Step Function role only has permission to touch the exact resource IDs listed in your config file, not all resources in the account

Configuration

Everything is driven by a single event_rules.json file. No code changes needed to add/remove resources or change schedules:

{
  "event_rules": [
    {
      "ruleId": "dev-environment",
      "cron": { "minute": "0", "hour": "8", "week_day": "MON-FRI", "month": "*", "year": "*" },
      "instances": [
        { "action": "StartDBCluster", "DBClusterIdentifier": "dev-aurora-cluster", "delay": 30 },
        { "action": "StartInstances",  "instanceId": "i-0abc123",                  "delay": 10 },
        { "action": "StartInstances",  "instanceId": "i-0def456",                  "delay": 0  }
      ]
    }
  ]
}

The delay field tells the Step Function to wait N seconds after starting a resource before moving on to the next one — so you can, for example, wait 30 seconds for the database to boot before starting the app server.

How to Deploy

Prerequisites

  • AWS CLI configured (aws configure)
  • Node.js installed (required by AWS CDK CLI)
  • Python 3.8+
  • AWS CDK CLI: npm install -g aws-cdk

Step 1 — Configure your resources

Edit event_rules.json and add your EC2 instance IDs and RDS identifiers with the desired cron schedules. All times are UTC.

Step 2 — Bootstrap CDK (first time only)

This creates the S3 bucket and IAM roles CDK needs to deploy assets in your account:

cdk bootstrap aws://<YOUR_ACCOUNT_ID>/<YOUR_REGION> # e.g. cdk bootstrap aws://123456789012/us-east-1

Step 3 — Preview what will be deployed

cdk synth
This prints the CloudFormation template. Inspect the IAM policy to confirm it lists only your specific resource ARNs (not wildcards).

Step 3 — Deploy

cdk deploy

CDK will show you a summary of IAM changes and ask for confirmation before deploying. The stack creates:

  • One EventBridge rule per entry in event_rules.json
  • One Step Function (shared by all rules)
  • One IAM role scoped to the exact resources in your config

Step 5 — Verify

In the AWS Console:

  • EventBridge → Rules — confirm the rule(s) exist with the correct cron
  • Step Functions — confirm the state machine was created
  • Wait for the scheduled time (or manually trigger the rule) and check Executions in the Step Function console

Updating the schedule or resource list

Edit event_rules.json, then run: cdk deploy

 

CDK detects the diff and updates only what changed. The IAM policy is automatically regenerated to match the new resource list.

You can add more event rules to start, stop, or restart more instances.

Teardown

cdk destroy
This removes all resources created by the stack from your AWS account.

Summary

This project is intentionally minimal. There’s no application server, no database, no dependencies at runtime — just a Step Function that fires on a schedule and makes a handful of AWS API calls. That simplicity is the point: fewer moving parts means less to break, less to monitor, and less to pay for.

The key design decisions worth highlighting:

  • No Lambda — Step Functions can call EC2 and RDS APIs directly via the AWS SDK integration, which removes an entire layer of code and infrastructure
  • Config-driven — adding a new resource or changing a schedule is a one-line edit to event_rules.json followed by cdk deploy, no code changes needed
  • Least-privilege IAM — the IAM role is automatically scoped to the exact resource ARNs in your config file, so a misconfigured or compromised execution can’t touch anything outside your defined list

In practice, for a team of 5–10 engineers with a handful of dev/staging instances, this kind of setup typically saves 40–60% of EC2/RDS costs in non-production environments — just by not running things when no one’s around.

The full source is on GitHub. Clone it, drop in your instance IDs, and run cdk deploy. That’s genuinely all there is to it.


AWS, CloudNative, Cookbook, DEV, EN

Post navigation

PREVIOUS
Implementing Canary Deployments using AWS NLB and ECS

Comments are closed.
Hi. My name is Przemek Malak. Thanks for visiting. I hope you found what I write about interesting.
If you'd like to chat with me, the easiest way is through LinkedIn.

Losowe wpisy

  • Łączymy Amazon GuardDuty z MS Teams i Slackiem

    1 maja 2021
  • AWS Step Functions

    13 lutego 2018
  • Jak za pomocą funkcji Lambda włączyć i wyłączyć serwer EC2 w AWS

    25 października 2017
  • re:Invent 2023 Nowości

    2 grudnia 2023
  • Serverless API – Jak postawić API bez serwera

    13 sierpnia 2017
  • Apps
  • AWS
  • CloudNative
  • Cookbook
  • Data
  • DEV
  • EN
  • GCP
  • IoT
  • Istio
  • k8s
  • Security
  • Social
  • GitHub
  • LinkedIn
© 2026   All Rights Reserved.
Ta strona korzysta z ciasteczek aby świadczyć usługi na najwyższym poziomie. Dalsze korzystanie ze strony oznacza, że zgadzasz się na ich użycie.