~/.aws/credentials file into the container using the volumes property in devcontainer.json. This approach ensures that sensitive data never leaves your host machine while allowing any developer to run the same environment without committing secrets to version control.
The Security Problem with Shared Credentials
In collaborative development environments, sharing access keys is a common but dangerous practice. Developers often copy-paste their AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY into shared environment variables or commit them directly into repository files. This creates significant security risks, including accidental exposure of private keys in git history and the inability to easily rotate credentials when an employee leaves the organization.
Furthermore, hardcoding credentials makes it difficult to switch between different AWS profiles (such as dev, staging, and production) without modifying the container configuration every time. By keeping credentials on the host machine, each developer retains full control over their own authentication, and changes to permissions are reflected immediately across all team members' local environments.
Developing using Remote SSH and VS Code provides context for how remote development workflows manage local state versus remote state, which is conceptually similar to managing local credentials within a containerized environment.Configuring the Bind-Mount
The core solution involves editing the devcontainer.json file located in the .devcontainer directory at the root of your project. You need to add a volumes array that maps the specific path of your AWS credentials file from the host filesystem to a corresponding path inside the container.
The standard location for AWS CLI credentials on Linux and macOS is ~/.aws/credentials. Inside the container, the AWS CLI expects this file to be available at the same absolute path. Therefore, the mount point should mirror the host structure exactly.
{
"name": "AWS Development Environment",
"image": "python:3.9-slim",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {}
},
"volumes": [
"${localEnv:HOME}/.aws:/home/vscode/.aws"
]
}
In the example above, we use the variable substitution syntax ${localEnv:HOME} to dynamically resolve the current user's home directory. This is critical because the home directory path differs between users (e.g., /Users/alice vs /Users/bob). Without this dynamic resolution, the bind-mount would fail if another colleague tried to open the container, as the hardcoded path would not exist on their machine.
Note that we map the directory to /home/vscode/.aws rather than just /.aws. In most official Microsoft Dev Containers, the default non-root user is named vscode, and its home directory is /home/vscode. If your base image uses a different user or UID, you must adjust the target path accordingly to ensure the AWS CLI process has read permissions to the mounted file.
Handling Permissions and Ownership
One common issue arises when the container runs processes as a different user than the one mounting the volume. While the bind-mount itself usually preserves permissions, ensuring that the container user can read the file is essential. The ~/.aws/credentials file typically has restrictive permissions (600) owned by the host user.
If you encounter permission denied errors when running aws s3 ls inside the container, verify that the target directory in the container allows reading by the executing user. Since the vscode user in standard dev containers is part of the primary group, and the mount is read-only by default in many configurations, this usually works out of the box. However, if you need write access (for example, to generate new temporary tokens), you may need to adjust the mount options to allow writing, though this is generally discouraged for security reasons.
It is also important to note that environment variables set on the host will not automatically pass into the container unless explicitly mapped. If you rely on AWS_PROFILE to select which credentials to use, ensure that this variable is exported in your shell profile on the host, or set it in the envFile section of devcontainer.json.
Alternative: Using IAM Roles for Service Accounts
While bind-mounting is ideal for local development, it is not suitable for production deployments. For workloads running on AWS services like ECS or EKS, you should use IAM Roles for Service Accounts (IRSA) or instance profiles instead. This eliminates the need for long-term access keys entirely.
For local development, however, bind-mounting remains the most practical solution. It requires zero additional setup from colleagues, works seamlessly with Git, and keeps secrets out of the repository. Always ensure that your .gitignore file includes .aws/credentials and .aws/config to prevent accidental commits of sensitive data.
Frequently Asked Questions
Why does my AWS CLI return "Unable to locate credentials" inside the container?
This error usually occurs because the path mapping in devcontainer.json is incorrect. Ensure that the source path on the host matches your actual ~/.aws directory and that the destination path inside the container matches the home directory of the user running the AWS CLI command.
Can I use this method with Windows WSL2?
Yes, but the path syntax differs slightly. On WSL2, you should use ${localWorkspaceFolder} or explicit WSL paths like //wsl$/Ubuntu/home/user/.aws. Avoid using Windows-style paths (C:\Users\...) directly, as they can cause permission issues within the Linux container.
Is it safe to commit the devcontainer.json file with these volumes?
Yes, it is safe. The devcontainer.json file only contains configuration instructions for the mount; it does not contain the actual secret keys. As long as you do not commit the .aws/credentials file itself, your secrets remain secure on each developer's local machine.
How do I switch between multiple AWS profiles locally?
You can specify which profile to use by setting the AWS_PROFILE environment variable in your shell or in the devcontainer.json remoteEnv section. The bind-mounted config file will handle the mapping of profile names to specific access keys.
What if my colleague uses a different operating system?
The ${localEnv:HOME} variable handles cross-platform differences for the home directory. However, if you are mixing macOS/Linux hosts with Windows hosts using Docker Desktop, ensure that the Docker Desktop settings allow access to the respective drive where the .aws folder resides.