【.NET 6.0】SecretManagerを使ってみた

### はじめに

こんにちは、株式会社ベーシックの川上です。今回GCPのSecretManagerを使用することがありましたので、SecretManagerの作成と、CloudRun上で実行しているASP.NETCoreアプリケーションからSecretManagerを参照した手順をまとめておこうと思います。

## SecretManagerとは

> SecretManagerとはAPIキーやパスワードなどの機密情報を管理するためのサービスです。
SecretManagerを利用することで、アプリケーション側で機密情報を保持する必要がなくなるため、セキュリティが高くなります。
Google Cloudで使用する機密データ（API キー、パスワード、証明書）を保存するための安全で便利なストレージシステムです。管理したい値を「シークレット」と呼び、一元的に管理、アクセス、監査することが可能になります。シークレットのデータは不変で、バージョンに対して操作を行います。

[公式ドキュメント](https://cloud.google.com/secret-manager/docs?hl=ja)

アプリケーション側では保持したくない機密情報を、GCP側でセキュアに管理することができるサービスです。
機密情報として扱いたい値が多数ある場合、それらをまとめて管理することができ、アクセス管理にかかる工数を削減できます。
アプリケーション側は機密情報を参照するだけでよくなります。


### シークレットの作成
シークレットの作成は、「セキュリティ」=> 「SecretManager」=> 「シークレットの作成」から行います。

![スクリーンショット (116).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/c3b40e1c-8547-7617-b178-b8f4553d5804.png)



シークレットの値は直接入力か、ファイルインポートすることができます。<br />
今回はテスト用の適当な値を入力しておきました。
![スクリーンショット (117).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/5d37b7d7-ec20-1a91-062b-dbba3fd1345f.png)


最初に作成したSecretはバージョン1で作成されます。今回はバージョン2のSecretも作成しておきます。<br />
別バージョンのSecretの追加は「新しいバージョン」から値を入力して作成します。

![スクリーンショット (118).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/168c6b1e-7e46-b7cd-0273-5b6ed7930a53.png)


### サンプルプログラム
- 単純にSecret名とバージョンを指定して、取得してきたSecretの値を返却するだけのプログラムです。
- Google.Cloud.SecretManager.V1のver2.0.0を使用しています。

```csharp
using Google.Apis.Auth.OAuth2;
using Google.Cloud.SecretManager.V1;
using System;
using System.Text;

namespace ~~~~~
{
    public class SecretManagerService
    {
        /// <summary>SecretManagerServiceクライアント</summary>
        private SecretManagerServiceClient SecretManagerClient { get; set; }

        private readonly string _projectId;

        public SecretManagerService()
        {
            SecretManagerClient = SecretManagerServiceClient.Create();
            _projectId = Environment.GetEnvironmentVariable("ProjectId");
        }

        public string GetSecret()
        {
            AccessSecretVersionResponse result = null;
            try
            {
                SecretVersionName secretVersionName = new SecretVersionName(_projectId, "TestSecret", "1");
                result = SecretManagerClient.AccessSecretVersion(secretVersionName);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"SecretManagerへのアクセスで例外が発生しました。: {ex}");
            }
            // ペイロードはデフォルトではバイトのため、文字列に変換して返却する
            return result.Payload.Data.ToStringUtf8();
        }
    }
}
```

- projectIdにはプロジェクト一覧に表示されるIDを指定します。<br />
![スクリーンショット (122).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/8b8d7ff9-3cde-eb64-bc20-526324b15180.png)


- 上記のプログラムを実行すると、Secretのバージョン「1」である「Hello」を取得できます。
![スクリーンショット (120).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/5914448f-5d13-9f38-810a-cf0e92e0c388.png)


- new SecretVersionName(_projectId, "TestSecret", "2")にして実行すると、以下の結果になります。
![スクリーンショット (121).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1076043/75e4ab0d-029c-360e-3cc1-ae39c796bc02.png)


## より安全に機密情報を管理する

今回は使用していませんが、SecretManagerについて調査しているとより安全な使用方法が記載されていたので、将来的に使用することも考慮してメモしておこうと思います。

### Cloud IAMを使用した明示的な権限の付与

SecretManagerへのアクセスは初期状態ではプロジェクトオーナーのみとなっています。Cloud IAMを利用することで、シークレットへのアクセス許可を明示的に付与することができます。

### Cloud Loggingとの併用
SecretManagerはCloud Loggingを利用することで、より安全に利用できます。SecretManagerとのやりとりをすべて監査ログに記録することで、異常なアクセスパターンを検知した場合にはアラートを発生させ、指定したユーザーに通知します。

<br />

以上のサービスを利用することで、より安全にアプリの機密情報を管理することができます。今回はGCPのSecretManagerに焦点を当てましたが、今後もGCPテーマの記事を投稿する予定です。


### 参考
- https://cloud.google.com/secret-manager/docs?hl=ja
- https://zenn.dev/nananaoto/articles/43e3414fdb1da37b377e