Dynamic ACL for EC2 with Dancer

An in-house Dancer webapp that's running on EC2 needed an ACL (Access Control List): a list of IPs that are allowed to access the application. Here is how we've accomplished it in a few lines.

Creating the ACL
We wanted to probe EC2 for all the machines on all regions that have a specific name. We're using VM::EC2, which can probe the regions to give us all regions dynamically, and can search for instances in a region. The only consideration is that you have to initialize VM::EC2 objects with a region (or full endpoint) when you want to find instances.

The code looks like this:


my @acl = map { $_->ipAddress }
map {
VM::EC2->new( -region => $_->regionName )
->describe_instances(
-filter => { 'tag:Name' => 'worker' }
)
} VM::EC2->new->describe_regions;

We create a new VM::EC2 object, and call the describe_regions method, which retrieves the list of available regions in EC2. Then we go over reach region and create a new VM::EC2 object for that region and search for all instances that match a specific Name tag. Then we access the ipAddress attribute to get the public given IP address that EC2 has given that instance. It all funnels into an array, so we end up with an array of IP addresses.

Enforcing the ACL
NOTE: this could also be done using Plack::Middleware::Access, but it still provides some insight into Dancer, and gives you more finer-grained control over the result.

To make sure Dancer enforces the ACL for each and every request, we simply add a before hook that checks if the IP is acceptable. If it is not, we return a Dancer::Error response.

This is what Plack::Middleware::Access does, but if we wanted, we could go beyond and log it, and forward it to a login page which will create a cookie and start checking for that cookie in the before hook, or... well, there are a lot of ideas. I'll leave them to you.

The code looks like this:


hook before => sub {
my $address = request->remote_address;

grep { $_ eq $address } @acl
or return Dancer::Error->new(
code => 403,
message => 'Access denied',
)->render;
};

Enjoy.

Leave a comment

About Sawyer X

user-pic Gots to do the bloggingz