Skip to content

Repository files navigation

terraform-aws-lightsail

Terraform module that creates and manages AWS Lightsail resources: instances with their key pairs, block storage, static IPs and firewall rules, plus load balancers, managed relational databases, object storage buckets, certificates, CDN distributions, container services, DNS zones and native alarms.

Compatibility

This module requires Terraform 1.6.0 or later, AWS provider versions from 5.40.0 up to but not including 7.0.0, and AWS Cloud Control (awscc) provider versions from 1.0.0 up to but not including 2.0.0.

Usage

Each resource family is enabled by supplying its input and skipped when that input is left at its default. A single instance with storage, a static IP, an explicit firewall and alarms looks like this:

module "lightsail" {
  source  = "ganexcloud/lightsail/aws"
  version = "~> 1.0"

  name = "app-production"

  instance = {
    availability_zone = "us-east-1a"
    blueprint_id      = "amazon_linux_2023"
    bundle_id         = "small_2_0"
  }

  key_pair      = { public_key = var.ssh_public_key }
  auto_snapshot = { snapshot_time = "06:00" }

  disks = {
    data = {
      size_in_gb = 20
      disk_path  = "/dev/xvdf"
    }
  }

  create_static_ip = true

  public_ports = [
    { from_port = 22, to_port = 22, protocol = "tcp", cidrs = ["198.51.100.10/32"] },
    { from_port = 443, to_port = 443, protocol = "tcp", cidrs = ["0.0.0.0/0"] },
  ]

  alarms = {
    cpu-high = {
      metric_name         = "CPUUtilization"
      comparison_operator = "GreaterThanOrEqualToThreshold"
      threshold           = 80
      evaluation_periods  = 2
      datapoints_to_alarm = 2
    }
  }

  tags = {
    environment = "production"
    managed-by  = "terraform"
  }
}

Resource families

Family Enabled by Creates
Instance instance instance, optional key pair, disks, static IP, public ports
Load balancer lb load balancer, instance attachments, certificate, redirection and stickiness policies
Database database managed relational database
Bucket bucket bucket, optional access key, resource access grants
Certificate certificate Lightsail certificate
Distribution distribution CDN distribution
Container service container_service container service and optional deployment version
DNS domain_name DNS zone and domain_entries records
Alarms alarms native Lightsail alarms

Resource naming

Lightsail resource names are unique per Region across resource types, so a single name cannot be shared by an instance, its key pair, a load balancer and a database. The module derives a distinct name per family from name, and the instance keeps the bare value because it is what callers refer to from outside:

Family Default name Override
Instance <name> instance.name
Key pair <name>-key key_pair.name
Static IP <name>-ip static_ip_name
Disk <name>-<disks key> disks[*].name
Load balancer <name>-lb lb.name
Load balancer certificate <name>-lb-cert lb_certificate.name
Database <name>-db database.relational_database_name
Bucket <name>-bucket bucket.name
Certificate <name>-cert certificate.name
Distribution <name>-cdn distribution.name
Container service <name>-cs container_service.name
Alarm <name>-<alarms key> alarms[*].alarm_name

Alarms need a contact method

Lightsail alarms notify a contact method, which is a singleton per account and region. Neither the AWS provider nor Cloud Control exposes it as a resource, so it is not managed here. Create it once before applying, otherwise alarms are created but stay silent:

aws lightsail create-contact-method --protocol Email --contact-endpoint ops@example.com

The email address must then confirm the subscription.

Alarms are created through the awscc provider because the AWS provider has no Lightsail alarm resource. That provider is therefore a hard requirement of the module even when alarms is left empty.

By default alarms monitor the instance this module creates. Point them at another Lightsail resource with alarm_monitored_resource_name.

Regional constraints

Lightsail certificates, CDN distributions and DNS zones are global resources that AWS only exposes through us-east-1. The module deliberately does not declare a provider configuration alias for them, because that would force every consumer to pass a second provider even when only creating an instance.

To manage a regional instance and a global distribution together, call the module twice:

module "app" {
  source = "ganexcloud/lightsail/aws"
  name   = "app-production"

  instance = {
    availability_zone = "sa-east-1a"
    blueprint_id      = "amazon_linux_2023"
    bundle_id         = "small_2_0"
  }
}

module "app_cdn" {
  source    = "ganexcloud/lightsail/aws"
  providers = { aws = aws.us_east_1 }

  name        = "app-production"
  domain_name = "example.com"

  distribution = {
    bundle_id = "small_1_0"
    origin = {
      name        = module.app.instance_name
      region_name = "sa-east-1"
    }
  }
}

Changing user_data

Lightsail runs user_data only on first boot, and the AWS provider forces a replacement whenever the value changes. Editing it would silently destroy a live host without re-running anything, so the module ignores subsequent changes to user_data. Rebuild deliberately when the bootstrap has to run again:

terraform apply -replace='module.lightsail.aws_lightsail_instance.this[0]'

Load balancer certificates

A load balancer certificate can only be attached after it is validated. Create it first, publish the records from the lb_certificate_domain_validation_records output, then set lb_certificate_attach = true on a second apply. lb_https_redirection_enabled requires an attached certificate.

Notes

  • public_ports is authoritative when non-empty: Lightsail replaces the entire rule set, including the ports opened by default at instance creation. Leave it empty to keep the Lightsail defaults.
  • Lightsail accepts a single add-on per instance, which is why auto_snapshot is an object rather than a list.
  • bucket_resource_access accepts the literal "self" as shorthand for the instance created by this module.
  • Each change to container_service_deployment publishes a new immutable deployment version; Lightsail keeps the previous ones.
  • The bucket secret access key and the database master password are stored in Terraform state.

Examples

Requirements

Name Version
terraform >= 1.6.0
aws >= 5.40.0, < 7.0.0
awscc >= 1.0.0, < 2.0.0

Providers

Name Version
aws >= 5.40.0, < 7.0.0
awscc >= 1.0.0, < 2.0.0

Modules

No modules.

Resources

Name Type
aws_lightsail_bucket.this resource
aws_lightsail_bucket_access_key.this resource
aws_lightsail_bucket_resource_access.this resource
aws_lightsail_certificate.this resource
aws_lightsail_container_service.this resource
aws_lightsail_container_service_deployment_version.this resource
aws_lightsail_database.this resource
aws_lightsail_disk.this resource
aws_lightsail_disk_attachment.this resource
aws_lightsail_distribution.this resource
aws_lightsail_domain.this resource
aws_lightsail_domain_entry.this resource
aws_lightsail_instance.this resource
aws_lightsail_instance_public_ports.this resource
aws_lightsail_key_pair.this resource
aws_lightsail_lb.this resource
aws_lightsail_lb_attachment.this resource
aws_lightsail_lb_certificate.this resource
aws_lightsail_lb_certificate_attachment.this resource
aws_lightsail_lb_https_redirection_policy.this resource
aws_lightsail_lb_stickiness_policy.this resource
aws_lightsail_static_ip.this resource
aws_lightsail_static_ip_attachment.this resource
awscc_lightsail_alarm.this resource

Inputs

Name Description Type Default Required
alarm_monitored_resource_name Name of the Lightsail resource the alarms monitor. Defaults to the instance created by this module. string null no
alarms Lightsail alarms to create, keyed by an arbitrary identifier used as the name suffix. Requires a contact method to already exist in the account; see the README.
map(object({
metric_name = string
comparison_operator = string
threshold = number
evaluation_periods = optional(number, 1)
datapoints_to_alarm = optional(number, 1)
contact_protocols = optional(set(string), ["Email"])
notification_enabled = optional(bool, true)
notification_triggers = optional(set(string), ["ALARM"])
treat_missing_data = optional(string, "missing")
alarm_name = optional(string)
}))
{} no
auto_snapshot AutoSnapshot add-on for the instance. Lightsail allows a single add-on per instance. Set to null to disable.
object({
snapshot_time = string
status = optional(string, "Enabled")
})
null no
bucket Object storage bucket to create. Set to null to skip the bucket family.
object({
bundle_id = string
name = optional(string)
force_delete = optional(bool)
})
null no
bucket_resource_access Names of Lightsail resources (for example instances) granted access to the bucket. Use the literal string "self" to reference the instance created by this module. list(string) [] no
certificate Lightsail certificate to create for use with a distribution. Only manageable in us-east-1. Set to null to skip.
object({
domain_name = string
name = optional(string)
subject_alternative_names = optional(set(string))
})
null no
container_service Container service to create. Set to null to skip the container family.
object({
power = string
scale = number
name = optional(string)
is_disabled = optional(bool)
public_domain_names = optional(object({
certificate = list(object({
certificate_name = string
domain_names = list(string)
}))
}))
})
null no
container_service_deployment Deployment version for the container service. Every change creates a new immutable version. Set to null to leave deployments unmanaged.
object({
containers = list(object({
container_name = string
image = string
command = optional(list(string))
environment = optional(map(string))
ports = optional(map(string))
}))
public_endpoint = optional(object({
container_name = string
container_port = number
health_check = optional(object({
healthy_threshold = optional(number)
unhealthy_threshold = optional(number)
interval_seconds = optional(number)
timeout_seconds = optional(number)
path = optional(string)
success_codes = optional(string)
}), {})
}))
})
null no
create_bucket_access_key Whether to create an access key for the bucket. The secret is exposed through the bucket_secret_access_key output and stored in state. bool false no
create_static_ip Whether to allocate a static IP and attach it to the instance. bool false no
database Managed relational database to create. Set to null to skip the database family.
object({
blueprint_id = string
bundle_id = string
master_database_name = string
master_username = string
master_password = string
relational_database_name = optional(string)
availability_zone = optional(string)
apply_immediately = optional(bool)
backup_retention_enabled = optional(bool)
preferred_backup_window = optional(string)
preferred_maintenance_window = optional(string)
publicly_accessible = optional(bool)
skip_final_snapshot = optional(bool)
final_snapshot_name = optional(string)
})
null no
disks Additional block storage disks to create and attach to the instance, keyed by an arbitrary identifier used as the name suffix.
map(object({
size_in_gb = number
disk_path = string
availability_zone = optional(string)
name = optional(string)
}))
{} no
distribution CDN distribution to create. Only manageable in us-east-1. Set to null to skip.
object({
bundle_id = string
origin = object({
name = string
region_name = string
protocol_policy = optional(string)
})
name = optional(string)
certificate_name = optional(string)
ip_address_type = optional(string)
is_enabled = optional(bool)
default_cache_behavior = optional(object({ behavior = string }), { behavior = "cache" })
cache_behaviors = optional(list(object({
behavior = string
path = string
})), [])
cache_behavior_settings = optional(object({
allowed_http_methods = optional(string)
cached_http_methods = optional(string)
default_ttl = optional(number)
maximum_ttl = optional(number)
minimum_ttl = optional(number)
forwarded_cookies = optional(object({
option = optional(string)
cookies_allow_list = optional(set(string))
}))
forwarded_headers = optional(object({
option = optional(string)
headers_allow_list = optional(set(string))
}))
forwarded_query_strings = optional(object({
option = optional(bool)
query_strings_allowed_list = optional(set(string))
}))
}))
})
null no
domain_entries Records to create in the Lightsail DNS zone, keyed by an arbitrary identifier. Requires domain_name.
map(object({
name = string
type = string
target = string
is_alias = optional(bool)
}))
{} no
domain_name Lightsail DNS zone to create. Only manageable in us-east-1. Set to null to skip the DNS family. string null no
instance Instance to create. Set to null to skip the instance family. Changing user_data replaces the instance, so the module ignores subsequent changes to it; see the README.
object({
availability_zone = string
blueprint_id = string
bundle_id = string
name = optional(string)
ip_address_type = optional(string)
user_data = optional(string)
})
null no
key_pair SSH key pair to create for the instance. Omit public_key to have Lightsail generate the pair, exposing it through the key_pair_private_key output. Mutually exclusive with key_pair_name.
object({
name = optional(string)
public_key = optional(string)
pgp_key = optional(string)
})
null no
key_pair_name Name of an existing Lightsail key pair to attach to the instance. Mutually exclusive with key_pair. string null no
lb Load balancer to create. Set to null to skip the load balancer family.
object({
instance_port = number
name = optional(string)
health_check_path = optional(string)
ip_address_type = optional(string)
})
null no
lb_attached_instances Names of the instances to attach to the load balancer. When empty, the instance created by this module is attached, if any. list(string) [] no
lb_certificate TLS certificate to create on the load balancer. Set to null to skip.
object({
domain_name = string
name = optional(string)
subject_alternative_names = optional(set(string))
})
null no
lb_certificate_attach Whether to attach lb_certificate to the load balancer. Attachment only succeeds after the certificate is validated, so this is usually enabled on a second apply. bool false no
lb_https_redirection_enabled Whether to redirect HTTP to HTTPS on the load balancer. Set to null to leave the policy unmanaged. Requires an attached certificate. bool null no
lb_stickiness Session stickiness policy for the load balancer. Set to null to leave it unmanaged.
object({
enabled = bool
cookie_duration = number
})
null no
name Base name for the Lightsail resources created by this module. The instance takes it unchanged; every other family derives a suffixed name from it, because Lightsail resource names are unique per Region across resource types. Each family accepts an optional name of its own that overrides this. string n/a yes
public_ports Public port rules for the instance firewall. An empty list leaves the Lightsail defaults untouched; a non-empty list becomes the authoritative rule set.
list(object({
from_port = number
to_port = number
protocol = string
cidrs = optional(set(string))
ipv6_cidrs = optional(set(string))
cidr_list_aliases = optional(set(string))
}))
[] no
static_ip_name Name of the static IP. Defaults to "-ip". string null no
tags Tags applied to every taggable resource created by this module. map(string) {} no

Outputs

Name Description
alarm_arns ARNs of the Lightsail alarms, keyed by the alarms input key.
alarm_names Names of the Lightsail alarms, keyed by the alarms input key.
bucket_access_key_id Access key ID created for the bucket.
bucket_arn ARN of the object storage bucket.
bucket_name Name of the object storage bucket.
bucket_secret_access_key Secret access key created for the bucket.
bucket_url URL of the object storage bucket.
certificate_arn ARN of the Lightsail certificate.
certificate_domain_validation_options DNS records that must be published to validate the Lightsail certificate.
certificate_name Name of the Lightsail certificate.
container_service_arn ARN of the container service.
container_service_deployment_version Version number of the current container service deployment.
container_service_name Name of the container service.
container_service_private_domain_name Private domain name of the container service.
container_service_url Public URL of the container service.
database_arn ARN of the managed relational database.
database_master_endpoint_address Endpoint address of the managed relational database.
database_master_endpoint_port Endpoint port of the managed relational database.
database_name Name of the managed relational database.
disk_arns ARNs of the block storage disks, keyed by the disks input key.
disk_names Names of the block storage disks, keyed by the disks input key.
distribution_arn ARN of the CDN distribution.
distribution_domain_name Domain name of the CDN distribution.
distribution_name Name of the CDN distribution.
distribution_status Status of the CDN distribution.
domain_arn ARN of the Lightsail DNS zone.
domain_name Name of the Lightsail DNS zone.
instance_arn ARN of the Lightsail instance.
instance_ipv6_addresses IPv6 addresses assigned to the instance.
instance_name Name of the Lightsail instance.
instance_private_ip_address Private IP address assigned to the instance.
instance_public_ip_address Public IP address assigned to the instance.
instance_username Default user name for connecting to the instance.
key_pair_fingerprint Fingerprint of the key pair created by this module.
key_pair_name Name of the key pair attached to the instance, whether created here or supplied.
key_pair_private_key Private key generated by Lightsail when key_pair is created without a public_key.
lb_arn ARN of the load balancer.
lb_certificate_domain_validation_records DNS records that must be published to validate the load balancer certificate before it can be attached.
lb_certificate_name Name of the load balancer TLS certificate.
lb_dns_name DNS name of the load balancer.
lb_name Name of the load balancer.
static_ip_address Static IP address allocated for the instance. Point DNS records here.
static_ip_name Name of the static IP allocated for the instance.

Contributing

See CONTRIBUTING.md.

License

Apache 2.0. See LICENSE.

About

Terraform module to create and manage AWS Lightsail resources: instances, storage, load balancers, databases, buckets, CDN, container services, DNS and alarms

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages