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.
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 ConfidentialLedgerClient
werden.
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 URI
abgerufen 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 PostLedgerEntry
gibt 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.
Azure SDK for .NET