3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

.NET 6 と Daprを使った分散サービス開発 その11 Secret Store

Last updated at Posted at 2022-03-23

Daprでシークレット管理

前回は、Daprに備わっているBinding (バインディング)を用いて、RabbitMQでのPubSubを扱ってきました。今回は、接続文字列やDBなどのパスワード、APIのアクセスキーなどのシークレット管理について触れていきたいと思います。

今までの前提の上でバインディングの機能を追加しますので、このページから読まれている方は、前提として以下を読んできてください。


Daprでシークレット管理

マイクロサービスや分散サービスなどでは様々な言語を用いて、これらシークレットを共通で管理するケースも多く、どの言語からも、ローカルでもKubernetesでも、同じように取得できる必要もあり、どのようにルールを定めて運用するか悩ましい所でもあります。
そして、ハードコードする事だけは避けたいものです。

これらに加えて、AWS、Azure、GCPなどのクラウドでは、これらのHSMキー管理のサービスがありますから、対応していくのも大変面倒ですし、ローカルで自分だけってケースであれば、常にそれらを使うというシチュエーションでもないケースも多分にあります。

Secret store(シークレットストア)コンポーネント

そこで、Daprではシークレット管理を抽象化するコンポーネントがあり、コンポーネント設定によって必要に応じて切り替える事ができます。

普段はローカル環境で環境変数で開発しておき、いざAzureなどにデプロイする際にはAzure Key Vaultで管理するとすれば良い事になります。

  • Environment Variables (環境変数)
  • Local file (ローカルファイル)
  • Kubernetes secrets
  • AWS Secrets Manager
  • Azure Key Vault
  • GCP Secret Manager
  • HashiCorp Vault

コンポーネントを設定

今回は最も簡単なセッティング方法である、ローカルファイルに集約する方法で試します。componentsフォルダに以下のようにファイルを構成しました。
また、nestedSeparatorによって キー名:ネストされたキー名で呼び出す事ができるようになります。

secret.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: daprsecret
spec:
  type: secretstores.local.file
  metadata:
    - name: secretsFile
      value: ./secrets.json
    - name: nestedSeparator
      value: ":"

また、合わせてsecret.jsonをルートフォルダに作ります。パスが解決できていない場合、Dapr側のログにも見つからないとログでますので、ロードできているか確認しましょう。

例として、以下のようなファイルを作成しました。

nestedSeparatorが設定されているので、以下のファイルの場合では、connectionStrings:productdbというキー名での呼び出しも可能です。

secret.json
{
    "azureStorageKey": "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==",
    "redisPassword": "",
    "connectionStrings": {
        "customerdb": "Server=127.0.0.1;Port=3306;Database=customerdb;Uid=guest@localhost;Pwd=Passw0rd!;SslMode=Required;",
        "productdb": "Server=127.0.0.1;Port=3306;Database=productdb;Uid=guest@localhost;Pwd=Passw0rd!;SslMode=Required;"
    }
}

他のコンポーネントから読み出す

daprのコンポーネント設定そのものに、このようなシークレットが含まれています。そこで、まずは他のコンポーネントの設定をこれらのシークレットデータに置き換える方法について確認しましょう。
以下は、今まで設定してきたState Store用のRedisを設定しているコンポーネント設定のYMALです。ローカルからアクセスしていますので、特にパスワードの設定をしていないのですが、ここでは設定していると思ってください。

statestore.yaml (設定前)
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""

設定後は、以下のようになります。

statestore.yaml (設定後)
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    secretKeyRef:
      name: redisPassword
      key: redisPassword
auth:
  secretStore: daprsecret

設定しているキーが同じ名前なので、ちょっと疑問に思うかもしれません。
これはキー設定の環境によっては、異なる為で、これはローカルから今回jsonを設定しているケースの設定だからです。

    secretKeyRef:
      name: redisPassword
      key: redisPassword

Kubernetes やAzure Key Vaultなどの場合は、このnameとkeyは設定が異なる場合があります。
例えば、以下のようにKubernetes でSecretを作って、読み込みたい場合であるとして

(キーの設定)
kubectl create secret generic daprsecrets --from-literal=redisPassword=secretPassword -n appsecret
    secretKeyRef:
      name: daprsecrets 
      key: redisPassword

となります。

アプリケーション側から呼び出す

今回は、前回使ったpub-serviceのプロジェクトを修正して、シークレットをロードしてみます。

Program.cs
using Dapr.Client;

namespace PubService
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string PUBSUB_NAME = "daprpubsub";
            string TOPIC_NAME = "AppStatus";
            while (true)
            {
                System.Threading.Thread.Sleep(3000);
                Random random = new Random();
                int stateId = random.Next(1, 1000);
                CancellationTokenSource source = new CancellationTokenSource();
                CancellationToken cancellationToken = source.Token;
                using var client = new DaprClientBuilder().Build();

                await client.PublishEventAsync(PUBSUB_NAME, TOPIC_NAME, stateId.ToString(), cancellationToken);
                Console.WriteLine("Published data: " + stateId);

                // 以下を新規に追加
                var storageKey = await client.GetSecretAsync("daprsecret", "azureStorageKey");
                Console.WriteLine($"Load secret : {storageKey["azureStorageKey"]}");

                var connStr = await client.GetSecretAsync("daprsecret", "connectionStrings:customerdb");
                Console.WriteLine($"Load connection string : {connStr["connectionStrings:customerdb"]}");

            }
        }
    }
}

tyeの起動と確認

ここまで来たらTyeを起動して、確認しましょう。
サイドカーとして起動したDaprからシークレットを読み取り、コンソールに表示しているログが出力されているはずです。

image.png

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?