Azure Confidential Ledger-Clientbibliothek für .NET – Version 1.2.0

Azure Confidential Ledger stellt einen Dienst für die Protokollierung bei einem unveränderlichen, manipulationssicheren Ledger bereit. Als Teil des Azure Confidential Computing-Portfolios wird Azure Confidential Ledger in SGX-Enklaven ausgeführt. Es basiert auf dem Confidential Consortium Framework von Microsoft Research.

Quellcode | Paket (NuGet)

Erste Schritte

Dieser Abschnitt sollte alles enthalten, was ein Entwickler tun muss, um seine erste Clientverbindung sehr schnell zu installieren und zu erstellen.

Installieren des Pakets

Installieren Sie die Azure Confidential Ledger-Clientbibliothek für .NET mit NuGet:

dotnet add package Azure.Security.ConfidentialLedger

Voraussetzungen

  • Ein Azure-Abonnement.
  • Ein ausgeführter instance des vertraulichen Azure-Ledgers.
  • Ein registrierter Benutzer im vertraulichen Azure-Ledger mit Administrator Berechtigungen.

Authentifizieren des Clients

Verwenden von Azure Active Directory

In diesem Dokument wird die Verwendung von DefaultAzureCredential zur Authentifizierung beim vertraulichen Ledger über Azure Active Directory veranschaulicht. Alle von Azure.Identity angebotenen Anmeldeinformationen werden jedoch akzeptiert. Weitere Informationen zu anderen Anmeldeinformationen finden Sie in der Dokumentation zu Azure.Identity .

Verwenden eines Clientzertifikats

Alternativ zu Azure Active Directory können Clients ein Clientzertifikat verwenden, um sich über gegenseitiges TLS zu authentifizieren.

Erstellen eines Clients

DefaultAzureCredential verarbeitet die meisten Azure SDK-Clientszenarien automatisch. Legen Sie zunächst Umgebungsvariablen für die AAD-Identität fest, die bei Ihrem vertraulichen Ledger registriert ist.

export AZURE_CLIENT_ID="generated app id"
export AZURE_CLIENT_SECRET="random password"
export AZURE_TENANT_ID="tenant id"

Dann DefaultAzureCredential kann der authentifiziert ConfidentialLedgerClientwerden.

Zum Erstellen des Clients ist auch der URI Ihres vertraulichen Ledgers erforderlich, den Sie über die Seite Azure-Portal für Ihr vertrauliches Ledger im Ledger URI Feld unter dem Properties Abschnitt abrufen können. Wenn Sie den Ledger URIabgerufen haben, verwenden Sie ihn, um es im folgenden Beispiel zu ersetzen "https://my-ledger-url.confidential-ledger.azure.com" .

var ledgerClient = new ConfidentialLedgerClient(new Uri("https://my-ledger-url.confidential-ledger.azure.com"), new DefaultAzureCredential());

Sicherheitshinweis: Wenn ein vertraulicher Ledger-Client erstellt wird, stellt er standardmäßig eine Verbindung mit dem Azure-Identitätsdienst für vertrauliche Ledger her, um das neueste TLS-Dienstzertifikat für Ihren Ledger zu erhalten, um Verbindungen mit Ledgerknoten zu schützen. Die Details zu diesem Prozess sind in diesem Beispiel verfügbar. Dieses Verhalten kann überschrieben werden, indem das options Argument beim Erstellen des Ledgerclients festgelegt wird.

Wichtige Begriffe

Ledgereinträge

Jeder Schreibvorgang in azure confidential ledger generiert einen unveränderlichen Ledgereintrag im Dienst. Schreibvorgänge werden eindeutig durch Transaktions-IDs identifiziert, die mit jedem Schreibvorgang inkrementieren.

Operation postOperation = ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(
        new { contents = "Hello world!" }));

string transactionId = postOperation.Id;
Console.WriteLine($"Appended transaction with Id: {transactionId}");

Da es sich bei Azure Confidential Ledger um ein verteiltes System handelt, können seltene vorübergehende Fehler dazu führen, dass Schreibvorgänge verloren gehen. Bei Einträgen, die beibehalten werden müssen, empfiehlt es sich, zu überprüfen, ob der Schreibvorgang dauerhaft wurde. Hinweis: Es kann erforderlich sein, mehrmals aufzurufenGetTransactionStatus, bis eine "Commit"-status zurückgegeben wird. Beim Aufrufen PostLedgerEntrygibt ein erfolgreiches Ergebnis jedoch an, dass die status "Committ" ist.

Response statusResponse = ledgerClient.GetTransactionStatus(transactionId);

string status = JsonDocument.Parse(statusResponse.Content)
    .RootElement
    .GetProperty("state")
    .GetString();

Console.WriteLine($"Transaction status: {status}");

// Wait for the entry to be committed
while (status == "Pending")
{
    statusResponse = ledgerClient.GetTransactionStatus(transactionId);
    status = JsonDocument.Parse(statusResponse.Content)
        .RootElement
        .GetProperty("state")
        .GetString();
}

Console.WriteLine($"Transaction status: {status}");

Receipts

Zustandsänderungen am vertraulichen Ledger werden in einer Datenstruktur gespeichert, die als Merkle-Struktur bezeichnet wird. Um kryptografisch zu überprüfen, ob Schreibvorgänge ordnungsgemäß gespeichert wurden, kann ein Merkle-Nachweis oder -Beleg für jede Transaktions-ID abgerufen werden.

Response receiptResponse = ledgerClient.GetReceipt(transactionId);
string receiptJson = new StreamReader(receiptResponse.ContentStream).ReadToEnd();

Console.WriteLine(receiptJson);

Sammlungen

Während die meisten Anwendungsfälle ein Ledger umfassen, bieten wir das Auflistungsfeature für den Fall, dass verschiedene logische Datengruppen im selben vertraulichen Ledger gespeichert werden müssen.

ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(
        new { contents = "Hello from Chris!", collectionId = "Chris' messages" }));

ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(
        new { contents = "Hello from Allison!", collectionId = "Allison's messages" }));

Wenn bei Methodenaufrufen keine Sammlungs-ID angegeben wird, geht der Azure Confidential Ledger-Dienst von einer konstanten, vom Dienst bestimmten Sammlungs-ID aus.

postOperation = ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(
        new { contents = "Hello world!" }));

string content = postOperation.GetRawResponse().Content.ToString();
transactionId = postOperation.Id;
string collectionId = "subledger:0";

// Try fetching the ledger entry until it is "loaded".
Response getByCollectionResponse = default;
JsonElement rootElement = default;
bool loaded = false;

while (!loaded)
{
    // Provide both the transactionId and collectionId.
    getByCollectionResponse = ledgerClient.GetLedgerEntry(transactionId, collectionId);
    rootElement = JsonDocument.Parse(getByCollectionResponse.Content).RootElement;
    loaded = rootElement.GetProperty("state").GetString() != "Loading";
}

string contents = rootElement
    .GetProperty("entry")
    .GetProperty("contents")
    .GetString();

Console.WriteLine(contents); // "Hello world!"

// Now just provide the transactionId.
getByCollectionResponse = ledgerClient.GetLedgerEntry(transactionId);

string collectionId2 = JsonDocument.Parse(getByCollectionResponse.Content)
    .RootElement
    .GetProperty("entry")
    .GetProperty("collectionId")
    .GetString();

Console.WriteLine($"{collectionId} == {collectionId2}");

Ledgereinträge werden aus Sammlungen abgerufen. Wenn eine Transaktions-ID angegeben wird, ist der zurückgegebene Wert der Wert, der zu dem zeitpunkt in der angegebenen Auflistung enthalten ist, der durch die Transaktions-ID identifiziert wird. Wenn keine Transaktions-ID angegeben ist, wird der neueste verfügbare Wert zurückgegeben.

Operation firstPostOperation = ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(new { contents = "Hello world 0" }));
ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(new { contents = "Hello world 1" }));
Operation collectionPostOperation = ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(new { contents = "Hello world collection 0" }),
    "my collection");
ledgerClient.PostLedgerEntry(
    waitUntil: WaitUntil.Completed,
    RequestContent.Create(new { contents = "Hello world collection 1" }),
    "my collection");

transactionId = firstPostOperation.Id;

// Wait for the entry to be committed
status = "Pending";
while (status == "Pending")
{
    statusResponse = ledgerClient.GetTransactionStatus(transactionId);
    status = JsonDocument.Parse(statusResponse.Content)
        .RootElement
        .GetProperty("state")
        .GetString();
}

// The ledger entry written at the transactionId in firstResponse is retrieved from the default collection.
Response getResponse = ledgerClient.GetLedgerEntry(transactionId);

// Try until the entry is available.
loaded = false;
JsonElement element = default;
contents = null;
while (!loaded)
{
    loaded = JsonDocument.Parse(getResponse.Content)
        .RootElement
        .TryGetProperty("entry", out element);
    if (loaded)
    {
        contents = element.GetProperty("contents").GetString();
    }
    else
    {
        getResponse = ledgerClient.GetLedgerEntry(transactionId, collectionId);
    }
}

string firstEntryContents = JsonDocument.Parse(getResponse.Content)
    .RootElement
    .GetProperty("entry")
    .GetProperty("contents")
    .GetString();

Console.WriteLine(firstEntryContents); // "Hello world 0"

// This will return the latest entry available in the default collection.
getResponse = ledgerClient.GetCurrentLedgerEntry();

// Try until the entry is available.
loaded = false;
element = default;
string latestDefaultCollection = null;
while (!loaded)
{
    loaded = JsonDocument.Parse(getResponse.Content)
        .RootElement
        .TryGetProperty("contents", out element);
    if (loaded)
    {
        latestDefaultCollection = element.GetString();
    }
    else
    {
        getResponse = ledgerClient.GetCurrentLedgerEntry();
    }
}

Console.WriteLine($"The latest ledger entry from the default collection is {latestDefaultCollection}"); //"Hello world 1"

// The ledger entry written at collectionTransactionId is retrieved from the collection 'collection'.
string collectionTransactionId = collectionPostOperation.Id;

getResponse = ledgerClient.GetLedgerEntry(collectionTransactionId, "my collection");
// Try until the entry is available.
loaded = false;
element = default;
string collectionEntry = null;
while (!loaded)
{
    loaded = JsonDocument.Parse(getResponse.Content)
        .RootElement
        .TryGetProperty("entry", out element);
    if (loaded)
    {
        collectionEntry = element.GetProperty("contents").GetString();
    }
    else
    {
        getResponse = ledgerClient.GetLedgerEntry(collectionTransactionId, "my collection");
    }
}

Console.WriteLine(collectionEntry); // "Hello world collection 0"

// This will return the latest entry available in the collection.
getResponse = ledgerClient.GetCurrentLedgerEntry("my collection");
string latestCollection = JsonDocument.Parse(getResponse.Content)
    .RootElement
    .GetProperty("contents")
    .GetString();

Console.WriteLine($"The latest ledger entry from the collection is {latestCollection}"); // "Hello world collection 1"
Bereichsabfragen

Ledgereinträge in einer Sammlung können über einen Bereich von Transaktions-IDs abgerufen werden. Hinweis: Beide Bereiche sind optional; sie können einzeln oder gar nicht bereitgestellt werden.

ledgerClient.GetLedgerEntries(fromTransactionId: "2.1", toTransactionId: collectionTransactionId);

Benutzerverwaltung

Benutzer werden direkt mit dem vertraulichen Ledger anstatt über Azure verwaltet. Neue Benutzer können AAD-basiert oder zertifikatbasiert sein.

string newUserAadObjectId = "<some AAD user or service princpal object Id>";
ledgerClient.CreateOrUpdateUser(
    newUserAadObjectId,
    RequestContent.Create(new { assignedRole = "Reader" }));

Vertrauliche Konsortiums- und Enklavenüberprüfungen

Möglicherweise möchten Sie Details zum vertraulichen Ledger aus verschiedenen Gründen überprüfen. Sie können beispielsweise Details darüber anzeigen, wie Microsoft Ihr vertrauliches Ledger im Rahmen der Governance des Confidential Consortium Framework verwalten kann, oder überprüfen Sie, ob Ihr vertrauliches Ledger tatsächlich in SGX-Enclaves ausgeführt wird. Für diese Anwendungsfälle werden eine Reihe von Clientmethoden bereitgestellt.

Pageable<BinaryData> consortiumResponse = ledgerClient.GetConsortiumMembers();
foreach (var page in consortiumResponse)
{
    string membersJson = page.ToString();
    // Consortium members can manage and alter the confidential ledger, such as by replacing unhealthy nodes.
    Console.WriteLine(membersJson);
}

// The constitution is a collection of JavaScript code that defines actions available to members,
// and vets proposals by members to execute those actions.
Response constitutionResponse = ledgerClient.GetConstitution();
string constitutionJson = new StreamReader(constitutionResponse.ContentStream).ReadToEnd();

Console.WriteLine(constitutionJson);

// Enclave quotes contain material that can be used to cryptographically verify the validity and contents of an enclave.
Response enclavesResponse = ledgerClient.GetEnclaveQuotes();
string enclavesJson = new StreamReader(enclavesResponse.ContentStream).ReadToEnd();

Console.WriteLine(enclavesJson);

Microsoft Azure Attestation Service ist ein Anbieter von SGX-Enclave-Angeboten.

Threadsicherheit

Wir garantieren, dass alle Client-instance Methoden threadsicher und unabhängig voneinander sind (Richtlinie). Dadurch wird sichergestellt, dass die Empfehlung, Clientinstanzen wiederzuverwenden, immer sicher ist, auch über Threads hinweg.

Zusätzliche Konzepte

Clientoptionen | Zugreifen auf die Antwort | Vorgänge | mit langer AusführungsdauerBehandeln von Fehlern | Diagnose | Spott | Clientlebensdauer

Beispiele

Demnächst...

Problembehandlung

Antwortwerte, die von Azure Confidential Ledger-Clientmethoden zurückgegeben werden, sind Response Objekte, die Informationen zur HTTP-Antwort enthalten, z. B. die http-Eigenschaft Status und ein Headers Objekt, das weitere Informationen zum Fehler enthält.

Einrichten der Konsolenprotokollierung

Die einfachste Möglichkeit, die Protokolle anzuzeigen, besteht darin, die Konsolenprotokollierung zu aktivieren. Verwenden Sie die AzureEventSourceListener.CreateConsoleLogger-Methode, um einen Azure SDK-Protokolllistener zu erstellen, der Nachrichten an die Konsole ausgibt.

// Setup a listener to monitor logged events.
using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();

Weitere Informationen zu anderen Protokollierungsmechanismen finden Sie hier.

Nächste Schritte

Eine ausführlichere Dokumentation zu Azure Confidential Ledger finden Sie in der API-Referenzdokumentation. Sie können auch mehr über das Open-Source Confidential Consortium Framework von Microsoft Research erfahren.

Mitwirken

Beiträge und Vorschläge für dieses Projekt sind willkommen. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. Weitere Informationen finden Sie unter cla.microsoft.com.

Für dieses Projekt gelten die Microsoft-Verhaltensregeln für Open Source (Microsoft Open Source Code of Conduct). Weitere Informationen finden Sie in den häufig gestellten Fragen zum Verhaltenskodex. Sie können sich auch an opencode@microsoft.com wenden, wenn Sie weitere Fragen oder Anmerkungen haben.

Aufrufe