Patrick Kerrigan

Making PHP-FPM use IAM task roles on ECS

by Patrick Kerrigan, . Tags: Aws Php Security

AWS IAM roles provide a way to supply your applications running on AWS infrastructure with the credentials they need to access other AWS resources without having to worry about managing access keys. When you have a single application per EC2 instance, everything "just works", but things get a bit more complex when you start throwing containers in the mix, especially with PHP.

How EC2 IAM roles work

When the AWS SDK needs to call an AWS service, provided you haven't got any hard-coded access keys, it calls the EC2 metadata API to discover what credentials to use. This is an API that's available to all EC2 instances and will return credentials linked to the IAM role of the instance it's called from. You can change the instance's IAM role whenever you like and the credentials returned by the metadata API will reflect any new roles you assign without having to redeploy your application.

If you're using ECS and Docker then this model doesn't quite work. The metadata service has no idea that you're running containers on your EC2 instance, and so any containers trying to retrieve credentials from it will all get the same response - the credentials of the Docker host. These aren't likely to have the same permissions as you'd want to give to your containers. To solve this, ECS supports assigning IAM task roles to each of your tasks, which are then looked up through the ECS agent rather than directly from the metadata service.

PHP-FPM and task roles

If you try running a PHP-FPM container with the default PHP-FPM configuration then you'll probably notice something odd: it will ignore the task role that's been assigned and try to grab the Docker host's credentials directly from the metadata API. If you've blocked the metadata API on your containers as AWS suggests then your AWS SDK calls will fail. If you haven't then they'll use the Docker host's credentials which may or may not work, but definitely isn't what you'd want.

Assuming that you've correctly configured your ECS Docker host, the AWS SDK is told that it's running in an ECS container by means of an environment variable set by ECS. This variable provides the path to the task's IAM credentials within an API exposed by the ECS agent. If the variable is set, then the SDK will attempt to call this API to retrieve the credentials rather than the EC2 metadata service.

PHP-FPM by default will hide the environment variables from your application, meaning the SDK can't tell that it's running in an ECS container. It's possible to disable this behaviour, but a better solution is to allow just those variables that are needed to be passed through by adding the following to your PHP-FPM configuration file:

env[AWS_CONTAINER_CREDENTIALS_RELATIVE_URI] = $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
env[AWS_CONTAINER_CREDENTIALS_FULL_URI] = $AWS_CONTAINER_CREDENTIALS_FULL_URI

Your PHP application should now be able to tell that it's running in an ECS container and retrieve the correct credentials for its ECS task role.