Bearbeiten

Muster „Valet-Schlüssel“

Azure
Azure Storage

Verwenden Sie ein Token, das Clients eingeschränkten direkten Zugriff auf eine bestimmte Ressource gewährt, um die Datenübertragung der Anwendung auszulagern. Dies ist besonders nützlich bei Anwendungen, die in der Cloud gehostete Speichersysteme oder Warteschlangen verwenden, und kann die Skalierbarkeit und Leistung bei gleichzeitiger Kostensenkung maximieren.

Kontext und Problem

Clientprogramme und Webbrowser müssen oft Dateien oder Datenströme aus dem bzw. in den Speicher einer Anwendung lesen oder schreiben. In der Regel führt die Anwendung die Verschiebung der Daten aus – entweder durch Abrufen dieser Daten aus dem Speicher und Streamen zum Client oder durch Lesen des hochgeladenen Datenstroms vom Client und Speichern im Datenspeicher. Bei dieser Vorgehensweise werden jedoch wertvolle Ressourcen wie Compute-, Speicher- und Bandbreitenressourcen in Anspruch genommen.

Datenspeicher sind in der Lage, Datenuploads und -downloads direkt zu verarbeiten, ohne dass die Anwendung Verarbeitungskapazitäten für die Verschiebung dieser Daten aufwenden muss. Hierfür muss der Client jedoch in der Regel Zugriff auf die Sicherheitsanmeldeinformationen für den Speicher haben. Dies kann eine nützliche Methode sein, um die Kosten für die Datenübertragung und die Anforderungen hinsichtlich der horizontalen Skalierung der Anwendung und Maximierung der Leistung zu minimieren. Das bedeutet jedoch, dass die Anwendung nicht mehr in der Lage ist, die Sicherheit der Daten zu gewährleisten. Nachdem der Client eine Verbindung mit dem Datenspeicher für den direkten Zugriff hergestellt hat, kann die Anwendung nicht mehr als Gatekeeper fungieren. Er hat keine Kontrolle mehr über den Prozess und kann nachfolgende Uploads oder Downloads aus dem Datenspeicher nicht verhindern.

Dies ist keine realistische Vorgehensweise in verteilten Systemen, die Anforderungen von nicht vertrauenswürdigen Clients verarbeiten müssen. Stattdessen müssen Anwendungen in der Lage sein, den Zugriff auf Daten granular und sicher zu steuern, aber dennoch die Auslastung des Servers zu reduzieren. Hierfür müssen sie diese Verbindung einrichten und anschließend dem Client die direkte Kommunikation mit dem Datenspeicher ermöglichen, damit die erforderlichen Lese- oder Schreibvorgänge durchgeführt werden können.

Lösung

Sie müssen das Problem bezüglich der Steuerung des Zugriffs auf einen Datenspeicher lösen, in dem der Speicher die Authentifizierung und Autorisierung von Clients nicht verwalten kann. Eine typische Lösung besteht darin, den Zugriff auf die öffentliche Verbindung des Datenspeichers zu beschränken und dem Client einen Schlüssel oder ein Token zur Verfügung zu stellen, den bzw. das der Datenspeicher überprüfen kann.

Der Schlüssel bzw. das Token wird üblicherweise als „Valet-Schlüssel“ bezeichnet. Dieser bietet zeitlich begrenzten Zugriff auf bestimmte Ressourcen und erlaubt nur vordefinierte Vorgänge, wie das Lesen und Schreiben von Daten aus oder in Speicher(n) oder Warteschlangen oder das Hochladen in einen und Herunterladen von einem Webbrowser. Anwendungen können schnell und einfach Valet-Schlüssel für Clientgeräte und Webbrowser erstellen und ausstellen, sodass Clients die erforderlichen Vorgänge durchführen können, ohne dass die Anwendung die Datenübertragung direkt verarbeiten muss. Dadurch entfallen der Verarbeitungsaufwand und die Auswirkungen auf die Leistung und Skalierbarkeit der Anwendung und des Servers.

Der Client verwendet dieses Token, um nur für einen bestimmten Zeitraum und mit bestimmten Einschränkungen der Zugriffsberechtigungen auf eine bestimmte Ressource im Datenspeicher zuzugreifen, wie in der Abbildung dargestellt wird. Nach Ablauf des angegebenen Zeitraums wird der Schlüssel ungültig und erlaubt keinen Zugriff auf die Ressource.

Abbildung 1: Übersicht über das Muster

Es ist auch möglich, einen Schlüssel mit anderen Abhängigkeiten wie dem Geltungsbereich der Daten zu konfigurieren. Je nach den Datenspeicherfunktionen kann der Schlüssel beispielsweise eine komplette Tabelle in einem Datenspeicher oder nur bestimmte Zeilen in einer Tabelle angeben. In Cloudspeichersystemen kann der Schlüssel einen Container oder nur ein bestimmtes Element in einem Container angeben.

Der Schlüssel kann auch von der Anwendung ungültig gemacht werden. Dies ist eine hilfreiche Vorgehensweise, wenn der Client dem Server mitteilt, dass der Datenübertragungsvorgang abgeschlossen ist. Der Server kann diesen Schlüssel dann ungültig machen, um weitere Zugriffe zu verhindern.

Die Verwendung dieses Musters kann die Verwaltung des Zugriffs auf Ressourcen vereinfachen, da es nicht erforderlich ist, einen Benutzer zu erstellen und zu authentifizieren, Berechtigungen zu erteilen und den Benutzer dann wieder zu entfernen. Zudem ist damit auch einfach, den Speicherort, die Berechtigung und die Gültigkeitsdauer zu begrenzen, indem man zur Runtime einfach einen Schlüssel generiert. Wichtig ist es, die Gültigkeitsdauer und insbesondere den Speicherort der Ressource so weit wie möglich zu begrenzen, damit der Empfänger diese nur für den vorgesehenen Zweck nutzen kann.

Probleme und Überlegungen

Beachten Sie die folgenden Punkte bei der Entscheidung, wie dieses Muster implementiert werden soll:

Verwalten Sie den Gültigkeitsstatus und die Gültigkeitsdauer des Schlüssels. Im Falle eines Verlusts oder einer Gefährdung entsperrt der Schlüssel effektiv das Zielelement und stellt es im Zeitraum der Gültigkeitsdauer für die böswillige Verwendung zur Verfügung. Ein Schlüssel kann in der Regel widerrufen oder deaktiviert werden, je nachdem, wie er ausgestellt wurde. Serverseitige Richtlinien können geändert werden oder der Serverschlüssel, mit dem er signiert wurde, kann ungültig gemacht werden. Geben Sie eine kurze Gültigkeitsdauer an, um das Risiko zu minimieren, dass nicht autorisierte Vorgänge für den Datenspeicher durchgeführt werden. Wenn die Gültigkeitsdauer jedoch zu kurz ist, kann es vorkommen, dass der Client den Vorgang nicht vor Ablauf der Gültigkeitsdauer des Schlüssels abschließen kann. Erlauben Sie autorisierten Benutzern, den Schlüssel vor Ablauf der Gültigkeitsdauer zu verlängern, wenn mehrere Zugriffe auf die geschützte Ressource erforderlich sind.

Steuern Sie die Zugriffsebene, die der Schlüssel gewährt. Der Schlüssel sollte dem Benutzer in der Regel erlauben, nur die Aktionen auszuführen, die für die Durchführung des Vorgangs notwendig sind, wie z.B. einen schreibgeschützten Zugriff, wenn der Client keine Daten in den Datenspeicher hochladen können soll. Bei Dateiuploads ist es üblich, einen Schlüssel, der nur zum Schreiben berechtigt, sowie den Speicherort und die Gültigkeitsdauer anzugeben. Es ist wichtig, die Ressource oder die Gruppe von Ressourcen, auf die der Schlüssel angewendet wird, exakt anzugeben.

Überlegen Sie, wie Sie das Verhalten der Benutzer steuern können. Die Implementierung dieses Musters ist mit einem gewissen Verlust der Kontrolle über die Ressourcen, für die dem Benutzer Zugriff gewährt wurde, verbunden. Der Grad der Kontrolle, der ausgeübt werden kann, wird durch die Funktionen der Richtlinien und Berechtigungen begrenzt, die für den Dienst oder den Zieldatenspeicher eingerichtet wurden. Beispielsweise ist es in der Regel nicht möglich, einen Schlüssel zu erstellen, der die Größe der in den Speicher zu schreibenden Daten oder die Häufigkeit, mit der anhand des Schlüssels auf eine Datei zugegriffen werden kann, begrenzt. Selbst wenn der Schlüssel vom vorgesehenen Client genutzt wird, kann dies zu enormen, unerwarteten Datenübertragungskosten führen, die möglicherweise durch wiederholte Uploads oder Downloads aufgrund eines Fehlers im Code verursacht werden. Um die Anzahl der Uploads einer Datei zu begrenzen, erzwingen Sie nach Möglichkeit, dass der Client die Anwendung über den Abschluss eines Vorgangs benachrichtigt. Beispielsweise lösen einige Datenspeicher Ereignisse aus, mit denen der Anwendungscode Vorgänge überwachen und das Benutzerverhalten steuern kann. Es ist jedoch schwierig, in einem mandantenfähigen Szenario, in dem derselbe Schlüssel von allen Benutzern eines Mandanten verwendet wird, Quoten für einzelne Benutzer durchzusetzen.

Überprüfen und bereinigen Sie optional alle hochgeladenen Daten. Ein böswilliger Benutzer, der Zugriff auf den Schlüssel erhält, könnte Daten, die auf die Gefährdung des Systems abzielen, hochladen. Alternativ können autorisierte Benutzer ungültige Daten hochladen, die bei der Verarbeitung zu Fehlern oder einem Systemfehler führen könnten. Um sich davor zu schützen, stellen Sie sicher, dass alle hochgeladenen Daten vor der Verwendung überprüft und auf schadhafte Inhalte geprüft werden.

Überwachen Sie alle Vorgänge. Viele schlüsselbasierten Mechanismen können Vorgänge wie Uploads, Downloads und Fehler protokollieren. Diese Protokolle können in der Regel in einen Überwachungsprozess eingebunden werden und auch für die Abrechnung des Benutzers verwendet werden, sofern diese basierend auf Dateigröße oder Datenvolumen erfolgt. Verwenden Sie die Protokolle, um Authentifizierungsfehler zu erkennen, die durch Probleme mit dem Schlüsselanbieter oder durch versehentliches Entfernen einer gespeicherten Zugriffsrichtlinie verursacht werden können.

Übermitteln Sie den Schlüssel auf sichere Weise. Dieser kann in eine URL eingebettet werden, die der Benutzer auf einer Webseite aktiviert, oder in einem Serverumleitungsvorgang verwendet werden, sodass der Download automatisch erfolgt. Verwenden Sie immer HTTPS, um den Schlüssel über einen sicheren Kanal zu übermitteln.

Schützen Sie sensible Daten bei der Übertragung. Vertrauliche Daten, die durch die Anwendung übermittelt werden, werden in der Regel über SSL oder TLS übertragen, und dies sollte auch bei Clients mit direktem Zugriff auf den Datenspeicher erzwungen werden.

Bei der Implementierung dieses Musters sind außerdem folgende weitere Probleme zu beachten:

  • Wenn der Client den Server nicht über den Abschluss des Vorgangs informiert oder nicht benachrichtigen kann und die einzige Einschränkung der Ablaufzeitraum des Schlüssels darstellt, kann die Anwendung keine Überwachungsvorgänge durchführen, wie das Nachverfolgen der Upload- oder Downloadhäufigkeit oder die Vermeidung mehrfacher Uploads oder Downloads.

  • Die Flexibilität der Schlüsselrichtlinien, die generiert werden können, ist möglicherweise begrenzt. Einige Mechanismen erlauben beispielsweise nur die Verwendung eines begrenzten Ablaufzeitraums. Andere Mechanismen können wiederum keine ausreichende Granularität für Schreib-/Leseberechtigungen bereitstellen.

  • Wenn die Startzeit für die Gültigkeitsdauer des Schlüssels oder Tokens festgelegt ist, stellen Sie sicher, dass sie diese etwas früher als die aktuelle Serverzeit einstellen, um geringfügige Abweichungen bei Clientuhren zu berücksichtigen. Falls nicht anderes festgelegt ist, ist in der Regel standardmäßig die aktuelle Serverzeit eingestellt.

  • Die URL mit dem Schlüssel wird in Serverprotokolldateien aufgezeichnet. Der Schlüssel wird zwar normalerweise abgelaufen sein, bevor die Protokolldateien für die Analyse verwendet werden, Sie sollten jedoch den Zugriff darauf auf jeden Fall einschränken. Wenn die Protokolldaten an ein Überwachungssystem übertragen oder an einem anderen Speicherort gespeichert werden, sollten Sie eine Verzögerung implementieren, um einen Verlust der Schlüssel nach Ablauf der Gültigkeitsdauer zu verhindern.

  • Wenn der Clientcode in einem Webbrowser ausgeführt wird, muss der Browser möglicherweise Unterstützung für CORS (Cross-Origin Resource Sharing) bieten, damit im Webbrowser ausgeführte Codes auf Daten in einer anderen Domäne als derjenigen, die die Seite bedient, zugreifen können. Einige ältere Browser und einige Datenspeicher unterstützen CORS nicht, und Code, der in diesen Browsern ausgeführt wird, kann ggf. nicht mithilfe eines Valet-Schlüssels auf Daten in einer anderen Domäne (beispielsweise ein Cloudspeicherkonto) zugreifen.

Verwendung dieses Musters

Dieses Muster ist in folgenden Situationen nützlich:

  • Zur Minimierung der Ressourcenauslastung und Maximierung der Leistung und Skalierbarkeit. Für die Verwendung eines Valet-Schlüssels ist weder eine Sperrung der Ressource noch ein Remoteserveraufruf erforderlich. Zudem gibt es keine Begrenzung bezüglich der Anzahl der Valet-Schlüssel, die ausgestellt werden können, und es verhindert einen Single Point of Failure, der aus der Durchführung der Datenübertragung über den Anwendungscode resultiert. Bei der Erstellung eines Valet-Schlüssels handelt es sich in der Regel um einen einfachen kryptographischen Vorgang, bei dem eine Zeichenfolge mit einem Schlüssel signiert wird.

  • Zur Minimierung der Betriebskosten. Der direkte Zugriff auf Speicher und Warteschlangen ist ressourcen- und kosteneffizient – so können die Anzahl der Netzwerkroundtrips und der benötigten Rechenressourcen reduziert werden.

  • Wenn Clients regelmäßig Daten hoch- oder herunterladen, insbesondere bei großen Datenmengen oder bei Vorgängen mit großen Dateien.

  • Wenn die Anwendung aufgrund von Hostingeinschränkungen oder Kostenüberlegungen nur über begrenzte Rechenressourcen verfügt. In diesem Szenario ist das Muster bei vielen gleichzeitigen Datenuploads oder -downloads noch hilfreicher, da es die Anwendung von der Verarbeitung der Datenübertragung entlastet.

  • Wenn die Daten in einem Remotedatenspeicher oder einem anderen Rechenzentrum gespeichert werden. Wenn die Anwendung als Gatekeeper fungieren sollte, könnte die zusätzliche Bandbreite für die Übertragung der Daten zwischen Rechenzentren oder über öffentliche oder private Netzwerke zwischen dem Client und der Anwendung und dann zwischen der Anwendung und dem Datenspeicher kostenpflichtig sein.

Dieses Muster ist in den folgenden Situationen eventuell nicht nützlich:

  • Wenn die Anwendung vor dem Speichern oder Senden von Daten an den Client einen Task für die Daten ausführen muss. Dies ist beispielsweise der Fall, wenn die Anwendung eine Überprüfung ausführen, erfolgte Zugriffe protokollieren oder eine Transformation der Daten ausführen muss. Einige Datenspeicher und Clients sind jedoch in der Lage, einfache Transformationen wie Komprimierungen und Dekomprimierungen auszuhandeln und durchzuführen (z. B. kann ein Webbrowser in der Regel GZip-Formate verarbeiten).

  • Wenn der Entwurf einer bestehenden Anwendung die Einbindung des Musters erschwert. Die Verwendung dieses Musters erfordert in der Regel einen anderen architektonischen Ansatz für die Bereitstellung und den Empfang von Daten.

  • Wenn Audit-Trails verwaltet oder die Anzahl der ausgeführten Datenübertragungsvorgänge kontrolliert werden muss und der verwendete Valet-Schlüsselmechanismus keine Benachrichtigungen unterstützt, anhand derer der Server diese Vorgänge verwalten kann.

  • Wenn die Größe der Daten begrenzt werden muss, insbesondere bei Uploadvorgängen. Die einzige Lösung hierfür besteht darin, dass die Anwendung die Datengröße nach Abschluss des Vorgangs überprüft oder die Größe der Uploads nach einem bestimmten Zeitraum oder nach einem Zeitplan überprüft.

Workloadentwurf

Ein Architekt sollte evaluieren, wie das Valet Key-Pattern im Design seines Workloads verwendet werden kann, um die Ziele und Prinzipien zu erreichen, die in den Säulen des Azure Well-Architected Framework behandelt werden. Zum Beispiel:

Säule So unterstützt dieses Muster die Säulenziele
Sicherheitsdesignentscheidungen tragen dazu bei, die Vertraulichkeit, Integrität und Verfügbarkeit der Daten und Systeme Ihrer Workload sicherzustellen. Dieses Muster ermöglicht es einem Client, direkt auf eine Ressource zuzugreifen, ohne dass er dauerhafte oder ständige Anmeldedaten benötigt. Alle Zugangsanfragen beginnen mit einer prüfbaren Transaktion. Der gewährte Zugang ist dann sowohl in seinem Umfang als auch in seiner Dauer begrenzt. Dieses Muster macht es auch einfacher, den gewährten Zugang zu widerrufen.

- SE:05 Identitäts- und Zugriffsmanagement
Die Kostenoptimierung konzentriert sich auf Erhaltung und Verbesserung der Rendite Ihrer Workload. Dieses Design entlastet die Verarbeitung als exklusive Beziehung zwischen dem Client und der Ressource, ohne eine Komponente hinzuzufügen, die alle Client-Anfragen direkt bearbeitet. Der Vorteil ist besonders groß, wenn die Kundenanfragen häufig oder groß genug sind, um erhebliche Proxy-Ressourcen zu benötigen.

- CO:09 Flowkosten
Die Leistungseffizienz hilft Ihrer Workload, Anforderungen effizient durch Optimierungen in Skalierung, Daten und Code zu erfüllen. Der Verzicht auf eine zwischengeschaltete Ressource für den Proxy-Zugriff entlastet die Verarbeitung als ausschließliche Beziehung zwischen dem Client und der Ressource, ohne dass eine Botschafterkomponente erforderlich ist, die alle Client-Anfragen auf performante Weise bearbeiten muss. Der Nutzen dieses Musters ist am größten, wenn der Bevollmächtigte keinen Mehrwert für die Transaktion schafft.

- PE:07 Code und Infrastruktur

Berücksichtigen Sie wie bei jeder Designentscheidung alle Kompromisse im Hinblick auf die Ziele der anderen Säulen, die mit diesem Muster eingeführt werden könnten.

Beispiel

Azure unterstützt SAS (Shared Access Signature) in Azure Storage für die granulare Zugriffssteuerung von Daten in Blobs, Tabellen und Warteschlangen sowie für Service Bus-Warteschlangen und -Themen. Ein SAS-Token kann so konfiguriert werden, dass es spezielle Zugriffsrechte gewährt, z.B. das Lesen, Schreiben, Aktualisieren und Löschen einer bestimmten Tabelle sowie eines Schlüsselbereichs in einer Tabelle, einer Warteschlange, einem Blob oder einem Blobcontainer. Die Gültigkeit kann eine bestimmte Zeitspanne betragen. Diese Funktion eignet sich gut für den Zugang mit einem Valet Key.

Stellen Sie sich eine Arbeitsbelastung vor, bei der Hunderte von mobilen oder Desktop-Clients häufig große Binärdateien hochladen. Ohne dieses Muster hat die Arbeitsbelastung im Wesentlichen zwei Möglichkeiten. Die erste besteht darin, allen Clients einen ständigen Zugang und eine ständige Konfiguration zu bieten, um Uploads direkt auf ein Speicherkonto durchzuführen. Die andere Möglichkeit besteht darin, das Gateway Routing-Muster zu implementieren, um einen Endpunkt einzurichten, an dem die Clients den Proxy-Zugriff auf den Speicher nutzen, was jedoch möglicherweise keinen zusätzlichen Wert für die Transaktion darstellt. Bei beiden Ansätzen gibt es Probleme, die im Zusammenhang mit dem Muster angesprochen werden:

  • Lange bestehende, gemeinsame Geheimnisse. Möglicherweise ohne die Möglichkeit, verschiedene Schlüssel für verschiedene Kunden bereitzustellen.
  • Zusätzliche Kosten für den Betrieb eines Rechendienstes, der über ausreichende Ressourcen verfügt, um den aktuellen Empfang großer Dateien zu bewältigen.
  • Potenzielle Verlangsamung der Client-Interaktionen durch Hinzufügen einer zusätzlichen Rechen- und Netzwerkebene zum Upload-Prozess.

Die Verwendung des Valet-Key-Musters erfüllt die Anforderungen an Sicherheit, Kostenoptimierung und Leistung.

Diagramm, das zeigt, wie ein Client auf ein Speicherkonto zugreift, nachdem er zunächst ein Zugriffstoken von einer API erhalten hat.

  1. Die Clients authentifizieren sich im letzten verantwortlichen Moment bei einer leichtgewichtigen, skalierbaren, von Azure Function gehosteten API, um den Zugriff anzufordern.

  2. Die API validiert die Anfrage und erhält dann ein zeitlich & begrenztes SaS-Token zurück.

    Das von der API generierte Token schränkt den Client auf die folgenden Einschränkungen ein:

    • Welches Speicherkonto verwendet werden soll. Das heißt, der Kunde braucht diese Informationen nicht im Voraus zu kennen.
    • Ein bestimmter Container und ein Dateiname, die verwendet werden sollen, um sicherzustellen, dass das Token mit höchstens einer Datei verwendet werden kann.
    • Ein kurzes Zeitfenster, z. B. drei Minuten. Diese kurze Zeitspanne stellt sicher, dass die Token eine TTL haben, die ihren Nutzen nicht übersteigt.
    • Berechtigung, nur einen Blob zu erstellen und nicht herunterzuladen, zu aktualisieren oder zu löschen.
  3. Dieses Token wird dann vom Kunden innerhalb des engen Zeitfensters verwendet, um die Datei direkt auf das Speicherkonto hochzuladen.

Die API generiert diese Token für autorisierte Clients unter Verwendung eines Benutzerdelegationsschlüssels basierend auf der API-eigenen Microsoft Entra ID verwalteten Identität. Die Protokollierung ist sowohl für das/die Speicherkonto(s) als auch für die Token-Generierungs-API aktiviert, um eine Korrelation zwischen Token-Anforderungen und Token-Nutzung zu ermöglichen. Die API kann Client-Authentifizierungsinformationen oder andere ihr zur Verfügung stehende Daten verwenden, um zu entscheiden, welches Speicherkonto oder welcher Container verwendet werden soll, z. B. in einer mandantenfähigen Situation.

Ein vollständiges Beispiel ist auf GitHub unter Valet Key pattern example verfügbar. Die folgenden Codeschnipsel sind diesem Beispiel entnommen. Das erste Beispiel zeigt, wie die Azure-Funktion (zu finden unter ValetKey.Web) ein vom Benutzer delegiertes gemeinsames Zugriffssignatur-Token unter Verwendung der eigenen verwalteten Identität der Azure-Funktion generiert.

[Function("FileServices")]
public async Task<StorageEntitySas> GenerateTokenAsync([HttpTrigger(...)] HttpRequestData req, ..., 
                                                        CancellationToken cancellationToken)
{
  // Authorize the caller, select a blob storage account, container, and file name.
  // Authenticate to the storage account with the Azure Function's managed identity.
  ...

  return await GetSharedAccessReferenceForUploadAsync(blobContainerClient, blobName, cancellationToken);
}

/// <summary>
/// Return an access key that allows the caller to upload a blob to this
/// specific destination for about three minutes.
/// </summary>
private async Task<StorageEntitySas> GetSharedAccessReferenceForUploadAsync(BlobContainerClient blobContainerClient, 
                                                                            string blobName,
                                                                            CancellationToken cancellationToken)
{
  var blobServiceClient = blobContainerClient.GetParentBlobServiceClient();
  var blobClient = blobContainerClient.GetBlockBlobClient(blobName);

  // Allows generating a SaS token that is evaluated as the union of the RBAC permissions on the managed identity
  // (for example, Blob Data Contributor) and then narrowed further by the specific permissions in the SaS token.
  var userDelegationKey = await blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow.AddMinutes(-3),
                                                                            DateTimeOffset.UtcNow.AddMinutes(3),
                                                                            cancellationToken);

  // Limit the scope of this SaS token to the following:
  var blobSasBuilder = new BlobSasBuilder
  {
      BlobContainerName = blobContainerClient.Name,     // - Specific container
      BlobName = blobClient.Name,                       // - Specific filename
      Resource = "b",                                   // - Blob only
      StartsOn = DateTimeOffset.UtcNow.AddMinutes(-3),  // - For about three minutes (+/- for clock drift)
      ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(3),  // - For about three minutes (+/- for clock drift)
      Protocol = SasProtocol.Https                      // - Over HTTPS
  };
  blobSasBuilder.SetPermissions(BlobSasPermissions.Create);

  return new StorageEntitySas
  {
      BlobUri = blobClient.Uri,
      Signature = blobSasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName).ToString();
  };
}

Der folgende Ausschnitt ist das Datenübertragungsobjekt (DTO), das sowohl von der API als auch vom Client verwendet wird.

public class StorageEntitySas
{
  public Uri? BlobUri { get; internal set; }
  public string? Signature { get; internal set; }
}

Der Client (zu finden unter ValetKey.Client) verwendet dann den von der API zurückgegebenen URI und das Token, um den Upload ohne zusätzliche Ressourcen und mit voller Client-to-Storage-Leistung durchzuführen.

...

// Get the SaS token (valet key)
var blobSas = await httpClient.GetFromJsonAsync<StorageEntitySas>(tokenServiceEndpoint);
var sasUri = new UriBuilder(blobSas.BlobUri)
{
    Query = blobSas.Signature
};

// Create a blob client using the SaS token as credentials
var blob = new BlobClient(sasUri.Uri);

// Upload the file directly to blob storage
using (var stream = await GetFileToUploadAsync(cancellationToken))
{
    await blob.UploadAsync(stream, cancellationToken);
}

...

Nächste Schritte

Die folgenden Informationen sind unter Umständen bei der Implementierung dieses Musters relevant:

Die folgenden Muster sind unter Umständen bei der Implementierung dieses Musters ebenfalls relevant:

  • Muster „Gatekeeper“: Dieses Muster kann in Verbindung mit dem Muster „Valet-Schlüssel“ verwendet werden, um Anwendungen und Dienste durch Verwendung einer dedizierten Hostinstanz zu schützen, die als Broker zwischen Clients und der Anwendung oder dem Dienst fungiert. Der Gatekeeper überprüft und bereinigt Anforderungen und leitet Anforderungen und Daten zwischen dem Client und der Anwendung weiter. Dies kann eine zusätzliche Sicherheitsschicht schaffen und die Angriffsfläche des Systems reduzieren.
  • Muster „Hosten von statischen Inhalten“: Dieses Muster beschreibt, wie statische Ressourcen für einen cloudbasierten Speicherdienst bereitgestellt werden, der diese Ressourcen zur Verringerung des Bedarfs an kostspieligen Serverinstanzen direkt an den Client übermitteln kann. Wenn die Ressourcen nicht öffentlich zugänglich sein sollen, können diese mit dem Muster „Valet-Schlüssel“ geschützt werden.