Skip to content

appvia/terraform-aws-instance-scheduler

Appvia Banner

Terraform Registry Latest Release Slack Community Contributors

Github Actions

Terraform AWS Instance Scheduler

This repository packages AWS Instance Scheduler into composable Terraform modules for hub-and-spoke platforms. It solves the problem of inconsistent runtime controls across accounts by standardizing schedule deployment, schedule data management, and tag enforcement as code.

In a typical landing zone setup, modules/scheduler runs in a central account, modules/config manages periods/schedules in DynamoDB, and modules/tagging backfills missing schedule tags. For spoke onboarding there are now two explicit options: modules/spoke for standalone deployment into a single target account, and modules/spokes for organizational deployment via CloudFormation StackSets across multiple accounts/OUs. modules/macro can inject default tags into CloudFormation resources through a transform.

Capabilities

  • Security by default: S3 template buckets enforce TLS, block insecure uploads, require encryption, and enable versioning.
  • Cross-account operations: Supports centralized scheduling patterns with AWS Organizations and StackSets for multi-account rollout.
  • Operational excellence: Separates scheduler deployment from schedule data so teams can iterate schedules without replacing the scheduler stack.
  • Flexible tagging controls: Provides scheduled Lambda-based tag enforcement for EC2, Auto Scaling, RDS, Aurora, DocumentDB, and Neptune.
  • Cloud platform alignment: Designed for AWS landing zone patterns with hub account orchestration and spoke account execution.
  • Compliance support: Helps implement cost-control and governance objectives that commonly map to SOC 2, ISO 27001, and PCI-DSS operating controls.

Usage Gallery

Golden Path (Simple)

Deploy the scheduler in a central account and define one business-hours schedule.

locals {
  tags = {
    Environment = "development"
    Owner       = "platform"
    Product     = "landing-zone"
  }
}

module "scheduler" {
  source = "github.com/appvia/terraform-aws-instance-scheduler//modules/scheduler?ref=main"

  scheduler_tag_name         = "Schedule"
  scheduler_regions          = ["eu-west-2"]
  scheduler_organizations_ids = ["o-abc123xyz0"]
  scheduler_frequency        = 15
  tags                       = local.tags
}

module "config" {
  source = "github.com/appvia/terraform-aws-instance-scheduler//modules/config?ref=main"

  dyanmodb_table_name = module.scheduler.scheduler_dynamodb_table

  periods = {
    office_hours = {
      description = "Weekday operating window"
      start_time  = "08:00"
      end_time    = "18:00"
      weekdays    = ["mon-fri"]
    }
  }

  schedules = {
    office_hours = {
      description = "Run only in office hours"
      periods     = ["office_hours"]
      timezone    = "Europe/London"
    }
  }
}

Power User (Advanced)

Enable broader resource coverage, explicit security inputs, and centralized tag enforcement across resource classes.

locals {
  tags = {
    Environment = "production"
    Owner       = "platform"
    Compliance  = "pci"
  }
}

module "scheduler" {
  source = "github.com/appvia/terraform-aws-instance-scheduler//modules/scheduler?ref=main"

  cloudformation_bucket_name       = "org-prod-instance-scheduler-templates"
  enable_cloudformation_macro      = true
  enable_cloudwatch_dashboard      = true
  enable_ssm_maintenance_windows   = true
  enable_rds_snapshot              = true
  scheduler_tag_name               = "Schedule"
  scheduler_regions                = ["eu-west-2", "eu-central-1"]
  scheduler_organizations_ids      = ["o-abc123xyz0"]
  scheduler_log_group_retention    = "30"
  scheduler_timezone               = "UTC"
  kms_key_arns                     = ["arn:aws:kms:eu-west-2:111122223333:key/abcd-1234"]
  tags                             = local.tags
}

module "spokes" {
  source = "github.com/appvia/terraform-aws-instance-scheduler//modules/spokes?ref=main"

  scheduler_account_id = "111122223333"
  organizational_units = {
    engineering = "ou-abcd-11111111"
    data        = "ou-abcd-22222222"
  }
  tags = local.tags
}

module "tagging" {
  source = "github.com/appvia/terraform-aws-instance-scheduler//modules/tagging?ref=main"

  scheduler_tag_name  = "Schedule"
  scheduler_tag_value = "office_hours"
  schedule            = "rate(15 minutes)"
  enable_autoscaling  = true
  enable_ec2          = true
  enable_rds          = true
  autoscaling = {
    excluded_tags = ["DoNotSchedule=true"]
  }
  tags = local.tags
}

Known Limitations

  • CloudFormation stack and StackSet updates are asynchronous and can take several minutes before full rollout completes.
  • S3 bucket names are globally unique; naming conventions must avoid collisions across AWS accounts.
  • Scheduler frequency is constrained to supported values (1, 2, 5, 10, 15, 30, 60 minutes).
  • modules/config writes directly to the scheduler DynamoDB table; name collisions in periods/schedules overwrite existing items.
  • Choose modules/spoke for single-account onboarding and modules/spokes for OU-based multi-account onboarding via StackSets.

Update Documentation

The terraform-docs utility is used to generate this README. Follow the below steps to update:

  1. Make changes to the .terraform-docs.yml file
  2. Fetch the terraform-docs binary (https://terraform-docs.io/user-guide/installation/)
  3. Run terraform-docs markdown table --output-file ${PWD}/README.md --output-mode inject .

Providers

No providers.

Inputs

No inputs.

Outputs

No outputs.

About

Terraform module used to deploy the Instance Scheduler

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors