VaultをDockerで管理する方法について

# 概要
[Megazone Japan Advent Calendar 2023](https://qiita.com/advent-calendar/2023/megazonejapan)の7日目に掲載するTech記事を執筆しました。🫡

この記事では、HashiCorpのVaultをDockerコンテナとしてデプロイし、管理する方法について解説します。Vaultは、セキュリティに敏感なアプリケーションにとって不可欠なツールであり、パスワード、APIキー、証明書などの秘密情報を安全に保管し、アクセスを厳格に管理するために設計されています。Vaultの強力な暗号化機能により、これらの機密データは安全に保護され、適切な権限を持つユーザーのみがアクセスできるようになります。

Dockerを使用することで、Vaultのインストール、設定、アップグレードが簡単になり、異なる環境間でのVaultの移植性と一貫性が向上します。Dockerコンテナは軽量であり、必要な依存関係を含んだ独立した環境を提供するため、Vaultサーバーを迅速に起動し、運用することが可能です。

この記事では、以下のトピックに焦点を当てています。

Vaultコンテナのセットアップ: Vaultの公式Dockerイメージを使用して、Vaultサーバーをコンテナとして実行する方法を説明します。

# 環境について

本設定環境は以下の通りです。
- macOS
- Docker Desktop
- Python 3.7.17

# Vaultコンテナのセットアップについて

## Docker pull image 

[vault image](https://hub.docker.com/_/vault)をPullします。

```
$ docker pull vault:1.13.3
```
```
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
vault        1.13.3    80d4968b1bbe   2 months ago   246MB
```

もし、`docker pull vault`　でコマンドを叩いた場合、以下のエラーが起きたら、VaultのDocker HubからVersionを指定してください。
```
Error response from daemon: manifest for vault:latest not found: manifest unknown: manifest unknown
```

Dockerが `vault:latest` というタグを持つイメージのマニフェストを見つけられなかったことを示しています。Dockerイメージは、特定のバージョンやビルドを識別するためにタグを使用します。latestタグは、通常、リポジトリの最新バージョンのイメージを指しますが、すべてのDockerイメージがlatestタグを持っているわけではありません。HashiCorp Vaultの公式Dockerイメージは、特定のバージョンに対してタグ付けされており、latestタグは提供されていない可能性があります。そのため、`docker pull vault:{Version}` バージョン番号でタグ付けてコマンドを実行します。


## Vault起動

Docker Imageを持ってきたので、次はそのImageを起動します。

```
$ docker run -d --rm --name vault-dev-server --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=mydev-token' -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' vault:1.13.3
```
```
$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS        PORTS                    NAMES
ecb1fd17de5c   vault:1.13.3   "docker-entrypoint.s…"   19 hours ago   Up 19 hours   0.0.0.0:8200->8200/tcp   vault-dev-server
```

Docker runコマンドのOptionsは以下の通りです。

- `-d`: コンテナをバックグラウンドで実行
- `--rm`: コンテナが停止した後に自動的に削除されるように指定
- `--name vault-dev-server`: コンテナにvault-dev-serverという名前を指定
- `--cap-add=IPC_LOCK`: Vaultがメモリ内の機密情報をスワップされないようにロック    
（**※VaultのDockerHubによると、このOptionはDev環境のみであり、Prod環境には使用してはいけない。** Dev以外の環境でこのOptionを使用しない場合、Configに`disable_mlock: true`を設定する）
- `-e 'VAULT_DEV_ROOT_TOKEN_ID=mydev-token'`: 開発モードでVaultを実行する際に使用されるルートトークンID
- `e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200'`: Vaultがリッスンするアドレスとポートを`0.0.0.0:8200`に設定。`0.0.0.0`はすべてのネットワークインターフェースでリッスンすることを意味
- `vault:1.13.3`: 使用するDockerイメージとタグを指定

## Vaultサーバーアドレス指定

VAULT_ADDR は、HashiCorp Vaultを使用する際に設定する環境変数の一つで、Vaultサーバーのアドレスを指定するために使用されます。この環境変数は、VaultクライアントがVaultサーバーに接続する際に、サーバーのURLを知るために必要です。

Docker環境でVaultを実行している場合、VAULT_ADDR環境変数は、VaultサーバーのDockerコンテナがリッスンしているホストとポートに対応するURLを設定するために使用されます。例えば、Vaultサーバーがローカルマシン上で動作している場合、VAULT_ADDR 環境変数は通常 http://127.0.0.1:8200 のように設定されます。

```
$ export VAULT_ADDR='http://127.0.0.1:8200'
```

## Vault UI

では、`http://localhost:8200/ui/` にアクセスすると、次のように、VaultのLoginページに移動します。    
Token IDは`docker run`を実行する際に設定した`mydev-token`を入力し、`Sign in`ボタンをクリックします。

![Vault-03](https://github.com/jeayoon/myWork/assets/17561411/eb1413da-98de-4494-a43d-a48a8dd3e1ba)

`Sign in`すると、`Secrets Engines`ページに移動します。これでVault UIへのアクセスがでしました。
![vault-04](https://github.com/jeayoon/myWork/assets/17561411/ff566a2f-bd45-4e93-a665-7c6b996d6f46)

本記事ではUIに関する詳細な説明は行いませんが、タブメニューの操作方法については確認していきましょう。    

`Access`ページ
![vault-04-2](https://github.com/jeayoon/myWork/assets/17561411/6695a4c2-b45d-4a2f-9cf4-baa97617e6d3)

`Policies`ページ
![vault-04-3](https://github.com/jeayoon/myWork/assets/17561411/34ee7307-be06-4a16-83b3-305be52a11fa)

`Tools`ページ
![vault-04-4](https://github.com/jeayoon/myWork/assets/17561411/fabfc31b-def1-49aa-8361-f822da7022f8)

## 動作確認：Vault Secrets

`Secrets`の`secret/`に移動し、`Create secret`ページでSecretsを追加してみます。    
![vault-06](https://github.com/jeayoon/myWork/assets/17561411/5609e71b-d77e-4793-90b9-54ad145f11cb)

```
Path for this secret: test
Secret data: mykey / test1234
```
値を入力したら、`Save`ボタンをクリックします。次のように`test`というDirが確認できます。
![vault-07](https://github.com/jeayoon/myWork/assets/17561411/06d28588-5acf-4784-b9f3-b9e8a5189f94)

次は`Secret data`を取ってみます。    
Pythonの[hvac](https://pypi.org/project/hvac/)を使用します。hvacはHashiCorp Vaultとやり取りするためのPythonライブラリです。hvacは "HashiCorp Vault API client" の略で、VaultのHTTP APIに対するPythonインターフェースを提供します。このライブラリを使用することで、PythonスクリプトやアプリケーションからVaultの機能をプログラム的に利用することができます。

hvacライブラリをインストールするには、通常のPythonパッケージと同様にpipを使用します。
```
pip install hvac
```

その後、ライブラリをインポートし、Vaultサーバーに接続して操作を行うことができます。例えば、Vaultに認証してシークレットを取得する基本的なコードは以下のようになります。    
```py
import hvac

# Create Vault Client
client = hvac.Client(url='http://127.0.0.1:8200',token="mydev-token")

# Check if authentication is successful
if client.is_authenticated():
  # Read the secret
  read_response = client.secrets.kv.read_secret_version(path='test', raise_on_deleted_version=True)
  print(read_response['data']['data']['mytest'])
```
            

Pythonコードを実行した結果、Vault UI上で追加されたmykeyの値を取得できることを確認しました。

![vault-08](https://github.com/jeayoon/myWork/assets/17561411/534ebaf3-c048-4678-8d51-680e1459323b)

# 最後に

VaultをDockerで運用することで、セキュリティと便利さが手に入りました。設定や管理が簡単になり、開発環境を迅速に構築できるようになったのは大きな利点です。この柔軟性は、今後のプロジェクトにおいても大いに役立つでしょう。     
以上、VaultをDockerで管理する方法についての記事でした。ありがとうございました！