ローカルの開発コンテナから、AWS Systems Manager (SSM) のポートフォワードで RDS などのプライベートリソースへ接続したいケースがありました。
当初はenvにアクセスキーとシークレットキーとスイッチロールのARNを含めて、ビルド時にそれらの値を取得してconfigとcredentialsを作成していました。
しかしメンバーにそれぞれ認証情報をenvに入れてもらうのも手間ですし、そもそもホスト側の.awsフォルダをマウントすれば良いと思い、認証情報をDockerfileに渡さずに、ホスト側の .aws(Profile/Role 設定)を 読み取り専用でマウントして利用する方法の紹介です。
前提
- ホスト(macOS 等)に.aws/configと.aws/credentialsがある
- 使いたいプロファイル名がホスト側の AWS 設定に存在している
- Docker コンテナ内に以下が入っている
- AWS CLI v2
- session-manager-plugin
docker-composeファイル
.awsを:roでマウントすると安全ではありますが、AWS CLI はデフォルトで ~/.aws/cli/cacheにキャッシュを書き込みます。
そのままだとRead-only file systemで失敗するため、/root/.aws/cli/cacheだけは書き込み可能なボリュームを重ねます。
【docker-compose.yaml例】
services:
api:
volumes:
- ./app:/app
- ${HOME}/.aws:/root/.aws:ro
- aws-cli-cache:/root/.aws/cli/cache
environment:
AWS_SDK_LOAD_CONFIG: "1"
AWS_CACHE_DIR: /root/.aws/cli/cache
volumes:
aws-cli-cache:
【ポイント】
- ~/.awsは:roのまま
- 書き込みが必要なcli/cacheだけDocker volume で上書き
- AWS_SDK_LOAD_CONFIG=1を明示(SDKにconfigを見に行かせる)
- AWS_CACHE_DIRにてAWS CLI のキャッシュ先を指定
プロファイル名は環境変数で渡す
AWS_PROFILEはenvでコンテナに渡します。
AWS_PROFILE=PROFILE名
コンテナをビルド&起動
docker compose up --build -d
コンテナ内で SSM ポートフォワードを開始
別ターミナルでコンテナに入り、SSM トンネルを起動します。
docker exec -it コンテナ名 /bin/bash
RDS(3306)へフォワードする場合(Fargateを踏み台としてます。)
aws ssm start-session \ --profile "$AWS_PROFILE" \ --target "ecs:<cluster>_<task>_<runtime-id>" \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters 'portNumber=3306,localPortNumber=3306,host=<rds-endpoint>'
localPortNumber=3306はコンテナ内のlocalhost:3306を開きます- コンテナにて
DB_HOST=localhostとDB_PORT=3306でDBに接続できるようになります
今回あったエラー
[Errno 30] Read-only file system: ‘/root/.aws/cli/cache/…json
【原因】
- .awsを:roでマウントしているのに、AWS CLI が~/.aws/cli/cacheに書き込もうとして失敗
【対策】
- aws-cli-cache:/root/.aws/cli/cacheのように、キャッシュディレクトリだけ書き込み可能ボリュームで上書きする
- 併せてAWS_CACHE_DIR=/root/.aws/cli/cacheを指定してキャッシュ先を指定する