Docker Composeの環境変数ではなくsecretsで秘密情報を扱う

## 概要
Dockerの本番環境で秘密情報を使う際に、環境変数を使うことは推奨されてません。
秘密情報を扱うには、コンテナオーケストレーションのsecret supportを使うことが推奨されてます。
Docker Composeには秘密情報を扱うために、secretsがあります。(Docker ComposeのsecretsはDocker Swarmと併用することが前提の機能です)


## 環境変数で秘密情報を扱う時の問題点
秘密情報を扱う時に、よくある方法として、環境変数を使う方法があります。
(この記事において、秘密情報とはパスワード、APIキーを想定します。)

```yaml:環境変数の例
environment: 
  MYSQL_USER: root
  MYSQL_PASSWORD: password
```

しかし、Dockerのドキュメントhttps://docs.docker.com/get-started/07_multi_container/ には
> While using env vars to set connection settings is generally ok for development, it is HIGHLY DISCOURAGED when running applications in production. Diogo Monica, the former lead of security at Docker, wrote a fantastic blog post explaining why.
>A more secure mechanism is to use the secret support provided by your container orchestration framework. In most cases, these secrets are mounted as files in the running container. You’ll see many apps (including the MySQL image and the todo app) also support env vars with a _FILE suffix to point to a file containing the variable.

著者訳
環境変数を使って接続の設定をすることは開発時には一般的にOKですが、本番環境では**非常にお勧めできません**。Dockerの元セキュリティーリードのDiogo Monicaは、理由について[素晴らしい投稿](https://diogomonica.com/2017/03/27/why-you-shouldnt-use-env-variables-for-secret-data/)をしてます。
より安全な方法は、コンテナオーケストレーションフレームワークによって提供されるsecret supportを使うことです。ほとんどの場合、これらの秘密情報は実行中のコンテナにファイルとしてマウントされます。多くのアプリ(MySQLのイメージやtodo app(DockerのGet Startedで作成するアプリのこと)を含む)では、環境変数に`_FILE`接尾辞ををつけて、変数を含むファイルを示すことができます。

Diogo Monicaの[記事](https://diogomonica.com/2017/03/27/why-you-shouldnt-use-env-variables-for-secret-data/)では、環境変数で秘密情報を扱う問題点として

- 環境はプロセスで暗黙的に利用可能のため、アクセスや利用を追跡することが困難である。
- アプリケーションが環境をデバッグやエラー報告のために出力することはよくある。
- 環境変数は子プロセスに引き継がれるため、意図しないアクセスが可能になる。これは、最小権限の原則を破る。
- アプリケーションがクラッシュした時、デバッグのために、環境変数をログファイルに保存することは一般的であり、これはディスク上に平文の秘密情報があることを意味する。
- 環境変数に秘密情報を入れると、それはすぐにtribal knowledgeになる。特定の環境変数がデリケートをであると認識していない新人のエンジニアは、適切に処理できない。

とあり、コンテナオーケストレーションツールであるDocker SwarmやKubernetesの機能を使って秘密情報を扱うことが推奨されています。

また、余談ですが
Dockerfile（docker-compose.yamlではない）で
`ENV`や`ARG`を使い環境変数を設定すると、Docker imageに変数の中身まで焼き付いてしまうため注意が必要です。


https://qiita.com/KEINOS/items/518610bc2fdf5999acf2


## Docker composeのsecretsで秘密情報を扱う

---
**注意** (2022/8/23追記)
Docker Composeの`secrets`はあくまで、開発用にDocker Swarmの動作結果を模倣しているだけ(マウントしているだけ)で、暗号化などがされていません。本番環境でそのまま使うことはあまりないと思いますが、本番環境で秘密情報は、Docker Swarmやkubernetes(k8s)などの機能を使って取り扱ってください。また、Docker Swarmで秘密情報を扱う場合は、`file`プロパティではなく`docker secret`コマンドを併用してください。

@yuicho さんコメントありがとうございました。

---

Docker SwarmやKubernetesを使わない方法を調べると
Docker Composeには秘密情報を扱う`secrets`というものがあることがわかります。
詳細はhttps://docs.docker.com/compose/compose-file/compose-file-v3/ を参照してください。ここでは１例を紹介します。

使用した環境

- docker desktop version 3.5.2
- macOS 11.4

Docker Composeのファイルフォーマットver3.1以上が必要になります。

```yaml:docker-compose.yaml
version: "3.9"
services:
  app:
    image: busybox:latest
    command: cat -n /run/secrets/my_secret
    secrets:
      - my_secret

secrets:
  my_secret:
    file: my_secret.txt
```

```text:my_secret.txt
hogehoge
```

ファイル構造

```
├── docker-compose.yaml
└── my_secret.txt
```

実行結果

```
⋊> docker compose up 
[+] Running 1/1
 ⠿ Container xxxx_app_1  StartedAttaching to app_1
app_1  |      1	hogehoge
app_1 exited with code 0
```

秘密情報を書いたファイルを`secrets`で指定すると、secretsで指定した名前(例では、my_secret)で、コンテナの`/run/secrets/`以下にマウントされます(例では、/run/secrets/my_scretにマウントされれます)。

マウントされた後は、例えばMySQLでは環境変数に`_FILE`接尾辞をつけて秘密情報のファイルの場所(/run/secrets/ 以下)を指定したり、環境変数で指定できない場合は、ファイルから秘密情報を読み込む処理を書くことで秘密情報を取り扱うことができます。