Durable Functions ランタイムは、関数パラメーター、戻り値、およびその他の状態を task hub に自動的に永続化して、信頼性の高い実行を提供します。 ただし、永続的なストレージに永続化されるデータの量と頻度は、アプリケーションのパフォーマンスとストレージ トランザクションのコストに影響を与える可能性があります。 アプリケーションで格納されるデータの種類によっては、データ保有とプライバシー ポリシーも考慮する必要があります。
この記事では、保持されるデータ、大きなペイロードと機密データを処理する方法、サポートされている言語ごとにシリアル化をカスタマイズする方法について説明します。
この記事の内容:
- タスク ハブの内容 - 格納されるデータとその方法
- 入力と出力を小さくする - ペイロード サイズを管理するための戦略
- 機密データの操作 - シークレットと個人を特定できる情報を保護する
- タスク ハブ ストレージをセキュリティで 保護する - 未承認のアクセスからストレージ バックエンドを保護する
- シリアル化と逆シリアル化のカスタマイズ - 言語固有のシリアル化オプション
タスク ハブの内容
タスク ハブには、インスタンスの現在の状態と保留中のメッセージが格納されます。
- インスタンスの状態 には、インスタンスの現在の状態と履歴が格納されます。 オーケストレーション インスタンスの場合、この状態にはランタイム状態、オーケストレーションの履歴、入力、出力、カスタム状態が含まれます。 エンティティ インスタンスの場合、エンティティの状態が含まれます。
- "メッセージ" には、関数の入力または出力、イベント ペイロード、ルーティングやエンド ツー エンドの関連付けなどの内部目的で使用するメタデータが格納されます。
メッセージは処理後に削除されますが、インスタンスの状態は、アプリケーションまたはオペレーターによって明示的に削除されない限り保持されます。 特に、オーケストレーションの完了後も、オーケストレーションの履歴はストレージに残ります。
状態とメッセージがオーケストレーションの進行状況を表す方法の例については、 タスク ハブの実行例を参照してください。
ストレージ内の状態とメッセージを表す場所と方法は、 ストレージ プロバイダーによって異なります。 Durable Functionsの既定のプロバイダーは Azure Storage で、指定した Azure Storage アカウント内のキュー、テーブル、BLOB にデータを保持します。
シリアル化および永続化されるデータの種類
次の一覧は、Durable Functionsの機能を使用するときにシリアル化および永続化されるさまざまな種類のデータを示しています。
- オーケストレーター、アクティビティ、およびエンティティ関数のすべての入力と出力には、任意の ID やハンドルされない例外が含まれます。
- オーケストレーター、アクティビティ、およびエンティティ関数の名前
- 外部イベントの名前とペイロード
- カスタム オーケストレーションのステータス ペイロード
- オーケストレーションの終了メッセージ
- 堅牢なタイマー ペイロード
- 持続的な HTTP 要求と応答の URL、ヘッダー、およびペイロード
- エンティティの呼び出しとシグナル ペイロード
- エンティティ状態ペイロード
この一覧のペイロード サイズの管理と機密性の高い項目の保護に関するガイダンスについては、次のセクションを参照してください。
Durable Functionsの入力と出力を小さく保つ
Durable Functions API との間で大きな入力と出力をやり取りすると、メモリの問題が発生する可能性があります。 入力と出力はオーケストレーション履歴にシリアル化されます。つまり、大規模なペイロードは時間の経過と同時に、無制限の履歴の増加に大きく貢献できます。 この増加は 、再生中にメモリ例外を引き起こすリスクがあります。
大きな入力と出力の影響を軽減するには、次の操作を行います。
- サブオーケストレーターに作業を委任して、複数のオーケストレーター間で履歴のメモリ負荷を負荷分散し、個々の履歴のメモリ占有領域を小さく保ちます。
- 外部ストレージ (Azure Blob Storage など) に大きなデータを格納し、必要に応じてアクティビティ関数内でそのデータを取得できるようにする軽量識別子を渡します。
Durable Task Scheduler を使用する場合は、 大きなペイロードのサポート を使用して、より大きなペイロードを Azure Blob Storage にオフロードすることもできます。
Tip
大規模なデータを処理するためのベスト プラクティスは、外部ストレージに保持し、必要に応じてアクティビティ内でのみそのデータを具体化することです。
機密データを操作する
Durable Functions API との間の入力と出力 (例外を含む) は、選択した storage プロバイダーに永続的に保持されます。 これらの入力、出力、または例外に機密データ (シークレット、接続文字列、個人を特定できる情報など) が含まれている場合は、ストレージ プロバイダーのリソースへの読み取りアクセス権を持つすべてのユーザーがそれらを取得できます。
機密データを安全に処理するには、アクティビティ関数内のデータをAzure Key Vaultまたは環境変数からフェッチし、オーケストレーターまたはエンティティとの間でそのデータを直接またはやり取りしないようにします。 この方法は、機密データがストレージ リソースに漏えいするのを防ぐのに役立ちます。
同様に、ストレージ リソースへの書き込みアクセスは厳密に制御する必要があります。ストレージ内の改ざんされたデータによってオーケストレーションの動作が変更される可能性があります。 タスク ハブ ストレージのセキュリティ保護の詳細については、「タスク ハブ ストレージ のセキュリティ保護」を参照してください。
Tip
このガイダンスは、 CallHttp オーケストレーター API にも適用され、要求と応答のペイロードがストレージに保持されます。 ターゲット HTTP エンドポイントで認証が必要な場合は、アクティビティ内に HTTP 呼び出しを実装するか、 CallHttp によって提供される組み込みのマネージド ID サポートを使用します。これは、資格情報をストレージに保持しません。
Note
ログへの読み取りアクセス権を持つすべてのユーザー (Application Insights など) がそれらのシークレットを取得する可能性がある場合は、シークレットを含むデータをログに記録しないようにします。
静止時の暗号化
Azure Storage プロバイダーを使用すると、すべてのデータが保存時に自動的に暗号化されます。 ただし、ストレージ アカウントへのアクセス権を持つユーザーは、暗号化されていない形式でデータを読み取ることができます。 機密データのより強力な保護が必要な場合は、事前に暗号化された形式でデータが永続化されるように、最初に独自の暗号化キーを使用してデータを暗号化することを検討してください。
または、.NETユーザーには、自動暗号化を提供するカスタム シリアル化プロバイダーを実装するオプションがあります。 暗号化を使用したカスタムシリアル化の例は、このGitHubサンプルで確認できます。
Note
アプリケーション レベルの暗号化を実装する場合は、オーケストレーションとエンティティが無期限に存在する可能性があることに注意してください。 オーケストレーションまたはエンティティはキーのローテーション ポリシーよりも長く実行される可能性があるため、暗号化キーをローテーションするときにこれが重要になります。 キーのローテーションが行われると、データの暗号化に使用されたキーが、次にオーケストレーションまたはエンティティを実行したときに復号化できなくなる可能性があります。 そのため、カスタム暗号化は、オーケストレーションとエンティティが比較的短時間実行されることが予想される場合にのみ推奨されます。
タスク ハブ ストレージをセキュリティで保護する
タスク ハブをホストするストレージ バックエンドは、重要な信頼境界です。 Durable Task Framework は、オーケストレーションの再生とメッセージ処理中にストレージから読み取ったデータを信頼します。 タスク ハブ ストレージへの書き込みアクセス権を持つすべてのユーザーは、オーケストレーション状態、保留中のメッセージ、または格納されているペイロードを改ざんできます。 これにより、アプリケーションの動作が変更されたり、意図しないアクションがトリガーされたり、関数アプリのコンテキスト内でリモート でコードが実行されたりする可能性があります。
Important
タスク ハブのストレージ資格情報を公開したり、信頼されていない関係者に書き込みアクセス権を付与したりしないでください。 タスク ハブ ストレージへの書き込みアクセスは、任意のコード実行のトリガーなど、アプリケーションの動作を変更するために使用できます。
共有責任
ストレージ バックエンドのセキュリティ保護は、アプリケーションの状態またはコードを格納するデータベースのセキュリティ保護と同じです。 Durable Task Framework は、保存されたデータに対して整合性検証を実行しないため、未承認の変更を防ぐためにストレージ層のアクセス制御に依存します。
Durable Task Scheduler を使用する場合、ストレージ バックエンドは、マネージド ID 認証とロールベースのアクセス制御 (RBAC) を使用して、サービスによって完全に管理され、セキュリティで保護されます。 Azure Storage、MSSQL、または Netherite などの BYO (Bring Your Own) ストレージ バックエンドの場合は、基になるストレージ リソースを自分でセキュリティで保護する必要があります。
Note
信頼されていないテナント間で 1 つのタスク ハブを共有しないでください。 タスク ハブはユーザー間のアクセス境界を強制しないため、タスク ハブに対して読み取りまたは書き込みを行うことができるテナントは、その中のすべてのオーケストレーションとエンティティに影響を与える可能性があります。 同様に、セキュリティ境界と同じバックエンド内の個別のタスク ハブに依存しないでください。 Durable Task Scheduler は個々のタスク ハブを対象とした RBAC をサポートしますが、IP 許可リストやプライベート エンドポイントなどのネットワーク制御はスケジューラ レベルでのみ適用されるため、スケジューラ内のタスク ハブはセキュリティ分離境界ではありません。 BYO ストレージ プロバイダーについても同様です。ストレージ アカウントまたはデータベースにアクセスできるテナントは、そのバックエンド上のすべてのタスク ハブにアクセスできます。 テナント間でセキュリティを分離する必要がある場合は、テナントごとに個別のインフラストラクチャ (BYO プロバイダー用の個別のストレージ アカウントまたはデータベース、または個別の Durable Task Scheduler インスタンス) をプロビジョニングします。
ストレージのセキュリティ強化チェックリスト
タスク ハブ ストレージを保護するには、次のベスト プラクティスを適用します。
- ストレージ キーを含む接続文字列の代わりに、ID ベースの接続を使用します。 マネージド ID は、きめ細かいアクセス制御を提供し、資格情報漏えいのリスクを排除します。 Durable Functions 用マネージド ID を構成する を参照してください。
- 最小特権 RBAC ロールを適用します。 必要な最小限のアクセス許可のみを付与します。 必要のないユーザーまたはサービスに広範なストレージ アカウントアクセス権を付与することは避けてください。
- プライベート エンドポイントまたはサービス エンドポイントを使用して、ストレージ アカウントへのネットワーク アクセスを制限します。 これにより、タスク ハブ データへの未承認のネットワーク レベルのアクセスが防止されます。
-
ストレージ アクセスを監視するには、ストレージ アカウントで Azure Monitor のリソース ログ、特に
StorageWriteログ カテゴリを有効にします。 これらのログを、Log Analyticsなどの監視対象ストレージ アカウントの外部の宛先にルーティングして、改ざんできないようにします。 ストレージ ログを参照してください。 - 接続文字列を使用する場合は、資格情報を定期的にローテーションします。 ストレージ アカウント キーは、他の高い特権の資格情報と同じ注意を払って扱います。
- マネージド ストレージ バックエンドについて考えてみましょう。 Durable Task Scheduler は、暗号化、認証、ネットワーク分離など、ストレージセキュリティを自動的に処理します。
シリアル化と逆シリアル化をカスタマイズする
シリアル化のカスタマイズ オプションは言語によって異なります。 [言語] タブを選択すると、使用可能なオプションが表示されます。
既定のシリアル化のロジック
.NET 用 Durable Functions のインプロセスでは、内部で Json.NET を使用して、オーケストレーションとエンティティのデータを JSON にシリアル化します。 使用される既定の Json.NET 設定は次のとおりです。
入力、出力、および状態:
JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
DateParseHandling = DateParseHandling.None,
}
例外:
JsonSerializerSettings
{
ContractResolver = new ExceptionResolver(),
TypeNameHandling = TypeNameHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}
JsonSerializerSettings に関する詳細なドキュメントについては、こちらを参照してください。
.NET属性を使用してシリアル化をカスタマイズする
シリアル化時に、Json.NET では、データのシリアル化と JSON からの逆シリアル化の方法を制御するクラスおよびプロパティのさまざまな属性を検索します。 Durable Functions API に渡されるデータ型のソース コードを所有している場合は、シリアル化と逆シリアル化をカスタマイズするために、これらの属性を型に追加することを検討してください。
依存関係挿入を使用してシリアル化をカスタマイズする
.NETを対象とし、Functions V3 ランタイムで実行する関数アプリは、Dependency Injection (DI) を使用して、データと例外のシリアル化方法をカスタマイズできます。 次のサンプル コードは、DI を使用して、IMessageSerializerSettingsFactory および IErrorSerializerSettingsFactory サービス インターフェイスのカスタム実装を使用して、既定の Json.NET シリアル化設定をオーバーライドする方法を示しています。
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Collections.Generic;
[assembly: FunctionsStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IMessageSerializerSettingsFactory, CustomMessageSerializerSettingsFactory>();
builder.Services.AddSingleton<IErrorSerializerSettingsFactory, CustomErrorSerializerSettingsFactory>();
}
/// <summary>
/// A factory that provides the serialization for all inputs and outputs for activities and
/// orchestrations, as well as entity state.
/// </summary>
internal class CustomMessageSerializerSettingsFactory : IMessageSerializerSettingsFactory
{
public JsonSerializerSettings CreateJsonSerializerSettings()
{
// Return your custom JsonSerializerSettings here
}
}
/// <summary>
/// A factory that provides the serialization for all exceptions thrown by activities
/// and orchestrations
/// </summary>
internal class CustomErrorSerializerSettingsFactory : IErrorSerializerSettingsFactory
{
public JsonSerializerSettings CreateJsonSerializerSettings()
{
// Return your custom JsonSerializerSettings here
}
}
}
}