.NET Core で秘密文字を安全に運用する（開発環境編）

# プログラムでの秘密の文字列

 業務系のプログラムでは、何かしらのデータベースやストレージのシステムにアクセスし、データの入出力を行います。データベースなどへの接続の際には、アカウント/パスワードといった機密の文字列を使用することが多いと思いますが、これを開発段階からリリース、運用フェーズまで安全に管理するのは意外と大変です。

　プログラムから見た秘密の文字列の置き場所として、昔ながらの iniファイル、レジストリ、.NetFramework の場合は App.config に記述する方法などがありますが、基本的にプレーンテキストですので、扱いには気を使います。うっかりバージョン管理システムの管理対象にしてしまったり、デプロイ先で見つけられてしまうといったリスクがあります。ソースコードに直に埋め込んで、バイナリの中に隠すという方法も、実のところよく聞く話ですが、バイナリエディタで見れば、あっさりバレてしまいます。

　独自のハッシュ化やエンコード関数を自作されている話も聞きますが、他社との共同開発になった時、ライセンシーや、その関数のソースコードを他社と共有する点で課題が発生することになります。

# Microsoft の秘密文字ソリューション

　秘密文字の管理のソリューションとして、Microsoft から２つの方法が提供されています。一つは、UserSecret を使う方法で、ローカルPC内の指定のディレクトリ内で管理します。管理場所が決まっていますので、うっかりバージョン管理システムにアップしてしまうこともありませんし、実装方法も簡単ですので、とっつきやすいと思います。ただ、暗号化などは行いませんので、Microsoft からは開発環境用としての位置づけとなっています。

もう一つは、Azure Key Vault を使う方法です。Azure Key Vault は、Microsoft のクラウド Azure のサービスの一つで、秘密の文字列をクラウドで管理します。Microsoft で厳重に管理されており、秘密文字へのアクセスには証明書が必要ですし、アクセスログも記録されます。エンタープライズ製品向けといえます。Microsoft では、UserSecret に比べ本番環境用として位置づけられています。

# UserSecret を使った秘密文字の管理

　UserSecret 及び Azure Key Vault での実装方法などを見ていきたいと思います。サンプルプログラムでは、.Net Core のコンソールで行いますが、ASP.NET などでも考え方などは変わりません。

サンプルで使うもの等

- Visual Studio Code
- dotnet code 3.1
- console プログラム
- Windows/MacOS/Linux

### プログラムの準備

dotnet コマンドで新規プロジェクトを作成します。ターミナルから次のコマンドを実行し、コンソールプログラムとして作成しています。

```bash
# mkdir vaultsample
# cd vaultsample
# dotnet new console
```

### パッケージの追加とシークレットマネージャーの初期化

　UserSecrets に関連するパッケージをインストールします。.csproj ファイルがあるパスで次のコマンドを実行します。

```bash
# dotnet add package Microsoft.Extensions.Configuration
# dotnet add package Microsoft.Extensions.Configuration.UserSecrets
```

次に、シークレットマネージャーを初期化します。

```bash
# dotnet user-secrets init
```

 インストールが完了すると、.csproj ファイルに Key Vault へのリファレンスが記述された ItemGroup と、追加されます。

[ASP.NET Core の構成プロバイダーの Azure Key Vault](https://docs.microsoft.com/ja-jp/aspnet/core/security/key-vault-configuration?view=aspnetcore-3.1)
[ASP.NET Core での開発におけるアプリシークレットの安全な保存](https://docs.microsoft.com/ja-jp/aspnet/core/security/app-secrets?view=aspnetcore-3.1&tabs=linux)


```xml
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UserSecretsId>07f81c45-c201-4de5-b9ff-96510163b7d6</UserSecretsId>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.5" />
  </ItemGroup>
</Project>
```

# 秘密文字の登録

次のコマンドで秘密文字を登録します。秘密文字は、シークレット名と値の組み合わせで登録します。

```bash
dotnet user-secrets set "SecretName" "secret_value_1_dev"
dotnet user-secrets set "Section:SecretName" "secret_value_2_dev"
```

なお、削除するときは次のようにコマンドを実行します。

```bash
dotnet user-secrets remove "SecretName" "secret_value_1_dev"
```

dotnet コマンドで作成しても構いませんが、格納先は下の通り、ユーザのホーム領域で、JSON 形式ですので、直接編集することもできます。

```:Windowsの場合
%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json
```
```bash:Linux/MacOSの場合
~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
```

また、Visual Studio Core の拡張ツール [.NET Core User Secrets](https://marketplace.visualstudio.com/items?itemName=adrianwilczynski.user-secrets) を使えば、UI 上で操作できます。

## プログラムから秘密文字を取得する

　次に、登録した秘密文字列を、プログラムから取得する方法です。秘密文字などの管理には、ConfigurationBuilder を使用します。インスタンス化する際に、AddUserSecretsメソッドを呼び出すことで、UserSecret として登録した秘密文字を取得することができるようになります。

```csharp:Program.cs
using System;
using Microsoft.Extensions.Configuration;

namespace vaultsample
{
  class Program
  {
    static void Main(string[] args)
    {
      var cbr = new ConfigurationBuilder()
      .AddUserSecrets<Program>().Build();

      Console.WriteLine($" secret key is {cbr["SecretName"]}");
    }
  }
}
```

これにより、

- 秘密文字 -> ユーザのホームディレクトリ
- 開発ソースコード -> 開発用ディレクトリ

という運用が可能になりました。

次の投稿で、Azure Key Vault を使用した、さらに安全性の高い秘密文字の運用方法を記載します。

（つづく）

＜参考＞

- [ASP.NET Core の構成プロバイダーの Azure Key Vault](https://docs.microsoft.com/ja-jp/aspnet/core/security/key-vault-configuration?view=aspnetcore-3.1)