Safe and simple AWS credential management for your Symfony/PHP application
Tags: webdev, devops, aws, php
Published: 2021-10-10 16:15:04

## Introduction

If you have a Symfony/PHP application which needs to connect to AWS and use some of its services (S3, Secrets Manager,...) and you want to avoid pushing credentials to your Git repository or revealing them to any third party (ex. deployment, testing or code review tools), then follow this guide. 

This guide will show you how to quickly and safely integrate AWS authentication both on your local development environment and on the server, both on bare metal and by using Docker.

Note that this is all available on the official AWS Documentation portal... scattered across multiple pages and documentation sections and buried in walls of text.

## AWS SDK for PHP

[AWS SDK for PHP](https://aws.amazon.com/sdk-for-php/) (install in your project with `composer require aws/aws-sdk-php`) is a library which you'll use the most when working with AWS services in your PHP application. The SDK has several built-in method for connecting to AWS and authenticating your application - you only need to know how best to use it.

---

## Local development environment - bare metal

Steps:

- Install AWS CLI;
- Configure AWS CLI;
- AWS SDK for PHP will pick up credentials stored in `~/.aws` directory and automatically use them.

### Step 1. Install AWS CLI

#### Windows - default installation method

- Download the installer from https://awscli.amazonaws.com/AWSCLIV2.msi and run it.

#### Windows - Scoop (my preferred method)

Scoop is a Windows package manager which provides many CLI tools, including those from Linux. If you don't know about it and would like to know more, check out my article on Scoop: [Using Scoop and Cmder to make PHP development on Windows bearable](https://dev.to/nikolastojilj12/using-scoop-and-cmder-to-make-php-development-on-windows-bearable-8pd)

Install AWS CLI with:

```bash
scoop install aws
```

#### Other operating systems

Follow the official guide for your operating system at: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html

### Step 2. Configure AWS CLI

Run:

```bash
aws configure
```

and complete the questions from the prompt. This will store your AWS login credentials to your user's `~/.aws` directory.

When your application tries to use AWS SDK, the SDK will automatically look whether credentials are stored in this directory and will try to use them.

---

## Local development environment - Docker

Steps:

- Add `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to `.env.local` file;
- AWS SDK for PHP will pick them up and use them to connect to AWS services from your Docker container.

Apart from reading credentials from the `~/.aws` directory, AWS SDK for PHP supports reading credentials from the mentioned environment variables.

If you're running your application in Docker locally, open the `.env.local` file and add `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to it (of course, fill the values with your AWS access key ID and AWS secret access key).

Symfony's `.env.local` file is excluded from Git by default, so these values will not leave your computer.

---

## Server - AWS EC2

You don't need to configure anything. EC2 instances can connect to other AWS services by default by using AWS metadata service to retrieve credentials from an IAM role.

---

## Server - non-AWS bare metal server

If you are running your Symfony application on a server which is not hosted on AWS:

- Open terminal and open `ssh` connection to your server;
- Download and install AWS CLI on your server. Guide: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html#cliv2-linux-install ;
- Run `aws configure` and add your credentials. They will be stored on the server in your user's `~/.aws` directory;
- Make sure that a user on your server which has PHP execution rights (for example: apache) has access to the `.aws` directory;
- AWS SDK for PHP will pick up credentials stored in `~/.aws` directory and use them to connect to AWS services.

---

## Server - Dockerized environment on AWS

Steps:

- Use the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable during `docker build`;
- Add `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` argument to your `Dockerfile`;

### Step 1. Add `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` in `docker build`

Open your project's `buildspec.yml` file and edit the `docker build` to include `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable. It should look something like this:

```yaml
phases:
    build:
        commands:
            ...
            docker build --build-arg AWS_CONTAINER_CREDENTIALS_RELATIVE_URI=$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI -t myapp:latest .
```

### Step 2. Add an argument to your `Dockerfile`

Open your project's `Dockerfile` and add `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` argument before the first `RUN` command:

```
ARG AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
```

AWS SDK for PHP will handle the rest. The app in your Docker container can now connect to AWS services by using AWS metadata service to retrieve credentials from an IAM role.

---

## Server - Dockerized environment outside of AWS

To be completely honest, I didn't have an opportunity to work on this setup directly. Having that in mind, let's proceed.

The method of integrating AWS credentials in this case really depends on your CI/CD pipeline and tools. By reading this article you probably already have an idea how to add credentials to a Dockerized server environment, but here's some of the options anyway:

#### Option 1. - AWS CLI + Docker volume

Just like a bare metal non-AWS server (described above), you can open an `ssh` session to your server and install/configure AWS CLI on the server. You can then add a Docker volume pointing to `~/.aws` directory on the server which will transfer credentials into the container.

#### Option 2. - Use `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables

This option is based on the same method as the local Dockerized environment.

Depending on your CI/CD pipeline and tools, you might consider using `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. Of course, you have to make sure that no third-party *server* has access to these values. If you are controlling your own CI/CD pipeline, for example by using a self-hosted GitLab instance, you can add these values in it.

#### Note: You can't use `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`

`AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` is populated by AWS services (ECS and CodeBuild). Using this environment variable makes sense when you are deploying using AWS CodeBuild, but if you are building and deploying outside of AWS, then it's not available to you.

---

## Conclusion

You should now have an idea on how to set up your environment(s) so that your project can use AWS services securely without exposing credentials.

Let me know in the comments if you have a more elegant solution.