Webアプリケーションのシークレット管理のあれこれ

# はじめに

この記事は [VR法人HIKKY Advent Calendar 2023](https://qiita.com/advent-calendar/2023/hikky) の8日目の記事です。
前日は [【VketCloud】その壁の設計、抜けられますよ](https://magazine.vket.com/n/na670c53bd2c6) です。VketCloudに限らない、ゲーム制作やワールド制作全般に言える知見でしたね。

# TL;DR
- GitHubにセキュアな文字列を平文でコミットしないためにやった施策の紹介
- 結局環境変数に回帰する運命なのか

# 様々なシークレットの管理方法

リポジトリに機密性の高い情報を平文で上げてはいけないのは、様々な先人の事例から明らかです。
どのように機密情報をCIフレンドリーに扱えばよいか、その方法は様々です。
本稿では最近のプロジェクトで使っている事例を紹介します。

## Case1: Rails credentials

Rails5.2以降で使えるcredentialsに値を格納する方法です。

https://m2wasabi.hatenablog.com/entry/2020/06/15/100000

Rails 7.0.6以降、credentialsのエディタ指定に細かい仕様変更が入り、ファイルで管理する場合のコマンドが影響を受けます

https://github.com/rails/rails/pull/44910/files#diff-352759d9ffcbbe0ddf7f2917f5b850ae42a158936878ed31e3120d7b355a795aR39


7.0.5.1 まで

```shell
EDITOR="cat .credentials_development.yml >" bundle exec rails credentials:edit -e development
```

7.0.6 以降

```shell
EDITOR="ruby -e \"File.write ARGV[0], File.read('.credentials_development.yml')\"" bundle exec rails credentials:edit -e development
```

yamlファイルを展開して使えるようにしたMakefile を作ると楽です。

7.0.5.1 まで

```makefile:Makefile
DEV_YAML = .credentials_development.yml
STG_YAML = .credentials_staging.yml
PRO_YAML = .credentials_production.yml

.PHONY: help
help:
    @echo "make {encode_credentials|decode_credentials}"

.PHONY: encode_credentials
encode_credentials:
    @echo "Encode credentials..."
	EDITOR="cat $(DEV_YAML) >" bundle exec rails credentials:edit -e development
	EDITOR="cat $(STG_YAML) >" bundle exec rails credentials:edit -e staging
	EDITOR="cat $(PRO_YAML) >" bundle exec rails credentials:edit -e production

.PHONY: decode_credentials
decode_credentials:
    @echo "Decode credentials..."
    bundle exec rails credentials:show -e development > $(DEV_YAML).bak
    bundle exec rails credentials:show -e staging > $(STG_YAML).bak
    bundle exec rails credentials:show -e production > $(PRO_YAML).bak
```

7.0.6 以降

```makefile:Makefile
DEV_YAML = .credentials_development.yml
STG_YAML = .credentials_staging.yml
PRO_YAML = .credentials_production.yml

.PHONY: help
help:
    @echo "make {encode_credentials|decode_credentials}"

.PHONY: encode_credentials
encode_credentials:
    @echo "Encode credentials..."
    EDITOR="ruby -e \"File.write ARGV[0], File.read('$(DEV_YAML)')\"" bundle exec rails credentials:edit -e development
    EDITOR="ruby -e \"File.write ARGV[0], File.read('$(STG_YAML)')\"" bundle exec rails credentials:edit -e staging
    EDITOR="ruby -e \"File.write ARGV[0], File.read('$(PRO_YAML)')\"" bundle exec rails credentials:edit -e production

.PHONY: decode_credentials
decode_credentials:
    @echo "Decode credentials..."
    bundle exec rails credentials:show -e development > $(DEV_YAML).bak
    bundle exec rails credentials:show -e staging > $(STG_YAML).bak
    bundle exec rails credentials:show -e production > $(PRO_YAML).bak
```

使い方

**平文のymlファイルをcredentialsに投入する**

```bash
make encode_credentials
```

**credentialsを平文に復号する**

```bash
make decode_credentials
```

### Pros

- 追加で何かインストールする必要が無い
- credential key の扱いについて
  - credential key ファイルは `.gitignore` ファイルには自動的に記載される
  - 暗号化されていないyamlファイルを間違ってコミットしないように注意

### Cons

- Railsでしか使えない

## Case2: ファイルをGPGで暗号化

任意のファイルを GnuPG を使って暗号化してコミットすることで、情報を守る方法です。
例えば `.env` ファイルなどの暗号化しておけば、アプリケーションのデプロイ時に展開することによって、
対応したアプリケーションの環境変数として扱うことができます。

**暗号化するとき**

```shell
gpg -c --cipher-algo AES256 .env
```

**復号化するとき**

```shell
gpg -d .env.gpg 
```

### Pros

- gitを扱うのに必要なので、インストールが不要
- 実装に使っているプログラミング言語に依存しない

### Cons

- パスフレーズの注入方法で結局悩む

## Case3: タスク定義に書く(AWS ECS) + AWS Systems Manager Parameter Store

AWSの場合、AWS Systems Manager を使ってセキュアなパラメータを扱うことが出来ます。
タスク定義に書くだけで簡単に取り出すことが出来ます

```json:taskdef.json
{
  "containerDefinitions": [
    {
      "environment": [
      ],
      "secrets": [
        {
          "name": "SOME_SECRET",
          "valueFrom": "/environment/application/some/secret"
        }
      ],
    }
  ]
}
```

secretsを設定するだけで使えるので特に書くことが無いのですが、具体的な使用例は以下の記事が参考になると思います。

https://dev.classmethod.jp/articles/ecs-secrets/

### Pros

- 簡単かつセキュアに使うことが出来る
- Terraform などで定義自体を管理できる
- 実装に使っているプログラミング言語に依存しない

### Cons

- AWSにベンダーロックイン

# まとめ

- 結局環境変数をどのようにハンドルするかの話題になってしまう
- AWS の場合は AWS Systems Manager Parameter Store で良い
- Railsのcredentials を便利に使うにはコツが必要

# 明日のアドベントカレンダーは…

@called_d さんです。黒魔術の話、気になりますね。