EC2 instances only accrue instance hours when they are turned on. We can take advantage of this by shutting down instances when not in use and booting them on demand through our VPN. Like socket activation, but for whole instances!
autostart
monitors for TCP SYN and ICMP (ping) packets on a Wireguard
interface. When it receives these, it checks if the IP belongs to a stopped EC2
instance in one of the AWS accounts specified in the config file, and if so
starts it.
Usage:
autostart [wg_interface] [mapping_json]
wg_interface: Interface to listen on. E.g.: wg0
mapping_json: Path to the JSON mapping config file. E.g.: /etc/autostart/mapping.json
Example: autostart wg0 /etc/autostart/mapping.json
autostart
limits its search to EC2 instances that have a tag autostart=true
set.
autostart
will automatically assume the IAM role of the VPN EC2 instance it is
executed on.
- To start instances under the same main AWS account the VPN EC2 instance is
running, you should assign a policy with at least the following permissions:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:StartInstances", "ec2:DescribeInstances" ], "Resource": "*" } ] }
- Add the corresponding configuration to the
mapping.json
file on your VPN EC2 instance (Ec2InstanceMetadata
instructsautostart
to use the IAM role directly attached to the VPN EC2 instance):{ "ipRange": "192.0.2.0/24", "arnRole": "Ec2InstanceMetadata" }
To start EC2 instances into other AWS account(s) as well, you will need to do the following for each new AWS account:
-
On the new AWS account, create an IAM policy with the following permissions:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:StartInstances", "ec2:DescribeInstances" ], "Resource": "*" } ] }
Note: do not restrict the
Resource
field with an ARN role, otherwise this will prevent us from assuming the corresponding role from the main AWS account. -
On the new AWS account, create a new IAM role and attach to it the previously created IAM policy. Configure this new IAM role, so that the IAM role on your main account that is attached to your VPN EC2 isntance can assume this role on your new account:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<MAIN-ACCOUNT-ID>:role/<MAIN-ACCOUNT-IAM-VPN-ROLE>" }, "Action": "sts:AssumeRole" } ] }
-
On your main AWS account under which your VPN EC2 instance is deployed, add a new IAM policy to the IAM role that is attached to your VPN EC2 instance, so that it can assume the IAM role created in your new account:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": [ "sts:AssumeRole" ], "Resource": [ "arn:aws:iam::<NEW-ACCOUNT-ID>:role/<NEW-ACCOUNT-IAM-AUTOSTART-ROLE>" ] } ] }
-
Add the corresponding configurations for your new AWS account to the
mapping.json
file on your VPN EC2 instance:{ "ipRange": "203.0.113.0/24", "arnRole": "arn:aws:iam::<NEW-ACCOUNT-ID>:role/<NEW-ACCOUNT-IAM-AUTOSTART-ROLE>" }
- Install the
autostart
binary on your VPN EC2 instance and create/editmapping.json
andautostart.service
go build -o autostart autostart.go sudo mv autostart /usr/bin/autostart sudo chmod +x /usr/bin/autostart sudo nano /etc/autostart/mapping.json sudo nano /etc/systemd/system/autostart.service
- Enable and start the
autostart.service
, or if you just added a new AWS account reload and restart it:orsudo systemctl enable autostart.service sudo systemctl start autostart.service
sudo systemctl daemon-reload sudo systemctl restart autostart.service
- Test that a stopped instance (tagged with
autostart = true
)autostarts when you try to ssh into it through your VPN.
TCP clients will automatically retry connections while the instance is booting,
but connection refused
(TCP RST
) packets can occur if the system starts but
the desired service is not yet started. To deal with this, autostart
automatically creates iptables
rules that suppress RST
packets for 30
seconds after booting each instance.
autostop
automatically shuts down an EC2 instance when there is no activity.
It is designed for instances that are primarily used for SSH (or VSCode over
SSH) and background tasks via screen
.
Usage:
autostop [duration] [cmd]
duration: Duration of inactivity before shutdown. E.g.: 10m
cmd: Command to run to shutdown. E.g.: /usr/bin/systemctl poweroff
Example: /usr/bin/autostop 10m /usr/bin/systemctl poweroff
Easy install script (run as root):
curl -L "https://github.com/ericpauley/ec2-autostart/releases/latest/download/autostop-`uname -m`" -o /usr/bin/autostop
chmod +x /usr/bin/autostop
curl -L "https://github.com/ericpauley/ec2-autostart/releases/latest/download/autostop.service" -o /etc/systemd/system/autostop.service
systemctl enable autostop.service && systemctl start autostop.service
Most default sshd
configurations will not end inactive sessions, such as if
you close your laptop without explicitly closing SSH or VSCode. The following
lines in sshd_config
will end these sessions (after roughly 3*60=180 seconds):
ClientAliveInterval 60
ClientAliveCountMax 3
Because EC2 instances take some time to boot (usually under 30s to receiving SSH
connections), SSH needs to be configured to wait longer before timing out. You
can set ConnectTimeout 30
in for a host in .ssh/config
on the client to
increase this timeout.