Configurare l'insieme di credenziali delle chiavi di Azure con rotazione e controllo delle chiavi end-to-endSet up Azure Key Vault with end-to-end key rotation and auditing

IntroduzioneIntroduction

Dopo aver creato l'insieme di credenziali delle chiavi sarà possibile iniziare a usarlo per archiviare le chiavi e i segreti.After creating your key vault, you will be able to start using that vault to store your keys and secrets. Le applicazioni non devono più rendere persistenti le chiavi o i segreti, ma li richiederanno all'insieme di credenziali delle chiavi in base alle esigenze.Your applications no longer need to persist your keys or secrets, but rather will request them from the key vault as needed. In questo modo è possibile aggiornare le chiavi e i segreti senza influenzare il comportamento dell'applicazione. Si apre così un ampio ventaglio di possibilità per la gestione di chiavi e segreti.This allows you to update keys and secrets without affecting the behavior of your application, which opens up a breadth of possibilities around your key and secret management.

Importante

Gli esempi inclusi in questo articolo vengono forniti solo a scopo illustrativo.The examples in this article are provided for illustration purposes only. Non sono destinati all'uso in ambienti di produzione.They are not intended for production use.

Questo articolo illustra un esempio di uso dell'insieme di credenziali delle chiavi di Azure per archiviare un segreto, in questo caso una chiave dell'account di archiviazione di Azure a cui accede un'applicazione.This article walks through an example of using Azure Key Vault to store a secret, in this case an Azure Storage Account key that is accessed by an application. Dimostra anche l'implementazione di una rotazione pianificata della chiave dell'account di archiviazione.It also demonstrates implementation of a scheduled rotation of that storage account key. Illustra infine come monitorare i log di controllo dell'insieme di credenziali delle chiavi e generare avvisi in caso di richieste impreviste.Finally, it walks through a demonstration of how to monitor the key vault audit logs and raise alerts when unexpected requests are made.

Nota

Questa esercitazione non illustra nei dettagli la configurazione iniziale dell'insieme di credenziali delle chiavi.This tutorial is not intended to explain in detail the initial setup of your key vault. Per altre informazioni, vedere Introduzione all'insieme di credenziali delle chiavi di Azure.For this information, see Get started with Azure Key Vault. Per le istruzioni relative all'interfaccia della riga di comando multipiattaforma, vedere Gestire l'insieme di credenziali delle chiavi tramite l'interfaccia della riga di comando.For Cross-Platform Command-Line Interface instructions, see Manage Key Vault using CLI.

Configurare l'insieme di credenziali delle chiaviSet up Key Vault

Per consentire a un'applicazione di recuperare un segreto dall'insieme di credenziali delle chiavi, è prima necessario creare il segreto e caricarlo nell'insieme di credenziali.To enable an application to retrieve a secret from Key Vault, you must first create the secret and upload it to your vault. Per eseguire queste operazioni, avviare una sessione di Azure PowerShell e accedere all'account Azure con il comando seguente:This can be accomplished by starting an Azure PowerShell session and signing in to your Azure account with the following command:

Connect-AzureRmAccount

Nella finestra del browser a comparsa, immettere il nome utente e la password dell'account Azure.In the pop-up browser window, enter your Azure account user name and password. PowerShell recupera tutte le sottoscrizioni associate a questo account ePowerShell will get all the subscriptions that are associated with this account. usa la prima per impostazione predefinita.PowerShell uses the first one by default.

Se sono disponibili più sottoscrizioni, potrebbe essere necessario specificare quella usata per creare l'insieme di credenziali delle chiavi.If you have multiple subscriptions, you might have to specify the one that was used to create your key vault. Immettere il comando seguente per visualizzare le sottoscrizioni relative all'account:Enter the following to see the subscriptions for your account:

Get-AzureRmSubscription

Per specificare la sottoscrizione associata all'insieme di credenziali delle chiavi da registrare, immettere:To specify the subscription that's associated with the key vault you will be logging, enter:

Set-AzureRmContext -SubscriptionId <subscriptionID>

Dato che questo articolo illustra l'archiviazione di una chiave dell'account di archiviazione come segreto, è necessario ottenere la chiave dell'account di archiviazione.Because this article demonstrates storing a storage account key as a secret, you must get that storage account key.

Get-AzureRmStorageAccountKey -ResourceGroupName <resourceGroupName> -Name <storageAccountName>

Dopo aver recuperato il segreto, in questo caso la chiave dell'account di archiviazione, è necessario convertirlo in una stringa sicura e quindi creare un segreto con quel valore nell'insieme di credenziali delle chiavi.After retrieving your secret (in this case, your storage account key), you must convert that to a secure string and then create a secret with that value in your key vault.

$secretvalue = ConvertTo-SecureString <storageAccountKey> -AsPlainText -Force

Set-AzureKeyVaultSecret -VaultName <vaultName> -Name <secretName> -SecretValue $secretvalue

Ottenere quindi l'URI per il segreto creato.Next, get the URI for the secret you created. L'URI viene usato in un secondo momento, quando si chiama l'insieme di credenziali delle chiavi per recuperare il segreto.This is used in a later step when you call the key vault to retrieve your secret. Eseguire questo comando PowerShell e prendere nota del valore ID, che rappresenta l'URI del segreto:Run the following PowerShell command and make note of the ID value, which is the secret URI:

Get-AzureKeyVaultSecret –VaultName <vaultName>

Configurare l'applicazioneSet up the application

Ora che il segreto è stato archiviato è possibile usare il codice per recuperarlo e usarlo.Now that you have a secret stored, you can use code to retrieve and use it. Per ottenere questo risultato, sono necessari alcuni passaggi.There are a few steps required to achieve this. Il primo e più importante è registrare l'applicazione in Azure Active Directory e quindi indicare le informazioni sull'applicazione All'insieme di credenziali delle chiavi in modo da consentire richieste dall'applicazione.The first and most important step is registering your application with Azure Active Directory and then telling Key Vault your application information so that it can allow requests from your application.

Nota

L'applicazione deve essere creata nello stesso tenant di Azure Active Directory dell'insieme di credenziali delle chiavi.Your application must be created on the same Azure Active Directory tenant as your key vault.

Aprire la scheda Applicazioni di Azure Active Directory.Open the applications tab of Azure Active Directory.

Aprire applicazioni in Azure Active Directory

Scegliere Aggiungi per aggiungere un'applicazione in Azure Active Directory.Choose ADD to add an application to your Azure Active Directory.

Scegliere Aggiungi

Lasciare il tipo di applicazione Applicazione Web e/o API Web e immettere un nome per l'applicazione.Leave the application type as WEB APPLICATION AND/OR WEB API and give your application a name.

Assegnare un nome all'applicazione

Immettere URL accesso e URI ID app per l'applicazione.Give your application a SIGN-ON URL and an APP ID URI. È possibile usare qualsiasi valore per questa demo. Sarà comunque possibile modificarli in un secondo momento se necessario.These can be anything you want for this demo, and they can be changed later if needed.

Specificare gli URI necessari

Dopo aver aggiunto l'applicazione ad Azure Active Directory verrà visualizzata la pagina dell'applicazione.After the application is added to Azure Active Directory, you will be brought into the application page. Fare clic sulla scheda Configura e quindi trovare e copiare il valore ID client.Click the Configure tab and then find and copy the Client ID value. Annotare l'ID client per i passaggi successivi.Make note of the client ID for later steps.

Generare quindi una chiave per l'applicazione in modo che possa interagire con Azure Active Directory.Next, generate a key for your application so it can interact with your Azure Active Directory. La chiave può essere creata nella sezione Chiavi della scheda Configurazione. Prendere nota della chiave appena generata dall'applicazione di Azure Active Directory per usarla in un secondo momento.You can create this under the Keys section in the Configuration tab. Make note of the newly generated key from your Azure Active Directory application for use in a later step.

Chiavi delle applicazioni di Azure Active Directory

Prima di stabilire chiamate dall'applicazione nell'insieme di credenziali delle chiavi è necessario fornire informazioni sull'applicazione e le relative autorizzazioni all'insieme di credenziali delle chiavi.Before establishing any calls from your application into the key vault, you must tell the key vault about your application and its permissions. Il comando seguente recupera il nome dell'insieme di credenziali e l'ID client dall'app di Azure Active Directory e concede l'accesso Get all'insieme di credenziali delle chiavi per l'applicazione.The following command takes the vault name and the client ID from your Azure Active Directory app and grants Get access to your key vault for the application.

Set-AzureRmKeyVaultAccessPolicy -VaultName <vaultName> -ServicePrincipalName <clientIDfromAzureAD> -PermissionsToSecrets Get

A questo punto è possibile iniziare a creare le chiamate dell'applicazione.At this point, you are ready to start building your application calls. Nell'applicazione è necessario installare i pacchetti NuGet necessari per interagire con l'insieme di credenziali delle chiavi di Azure e Azure Active Directory.In your application, you must install the NuGet packages required to interact with Azure Key Vault and Azure Active Directory. Immettere i comandi seguenti nella console di Gestione pacchetti di Visual Studio.From the Visual Studio Package Manager console, enter the following commands. Al momento della stesura di questo articolo la versione corrente del pacchetto di Azure Active Directory è 3.10.305231913, quindi si consiglia di verificare la versione più recente e aggiornare di conseguenza.At the writing of this article, the current version of the Azure Active Directory package is 3.10.305231913, so you might want to confirm the latest version and update accordingly.

Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory -Version 3.10.305231913

Install-Package Microsoft.Azure.KeyVault

Nel codice dell'applicazione creare una classe che contenga il metodo per l'autenticazione di Azure Active Directory.In your application code, create a class to hold the method for your Azure Active Directory authentication. In questo esempio, la classe è denominata Utils.In this example, that class is called Utils. Aggiungere l'istruzione using seguente:Add the following using statement:

using Microsoft.IdentityModel.Clients.ActiveDirectory;

Aggiungere quindi il metodo seguente per recuperare il token JWT da Azure Active Directory.Next, add the following method to retrieve the JWT token from Azure Active Directory. Per ottimizzare la gestione, è consigliabile trasferire i valori di stringa hardcoded nella configurazione Web o dell'applicazione.For maintainability, you may want to move the hard-coded string values into your web or application configuration.

public async static Task<string> GetToken(string authority, string resource, string scope)
{
    var authContext = new AuthenticationContext(authority);

    ClientCredential clientCred = new ClientCredential("<AzureADApplicationClientID>","<AzureADApplicationClientKey>");

    AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);

    if (result == null)

    throw new InvalidOperationException("Failed to obtain the JWT token");

    return result.AccessToken;
}

Aggiungere il codice necessario per chiamare l'insieme di credenziali delle chiavi e recuperare il valore del segreto.Add the necessary code to call Key Vault and retrieve your secret value. Aggiungere prima di tutto l'istruzione using seguente:First you must add the following using statement:

using Microsoft.Azure.KeyVault;

Aggiungere le chiamate di metodo per richiamare l'insieme di credenziali delle chiavi e recuperare il segreto.Add the method calls to invoke Key Vault and retrieve your secret. In questo metodo viene specificato l'URI del segreto salvato in un passaggio precedente.In this method, you provide the secret URI that you saved in a previous step. Si noti l'uso del metodo GetToken dalla classe Utils creata in precedenza.Note the use of the GetToken method from the Utils class created previously.

var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(Utils.GetToken));

var sec = kv.GetSecretAsync(<SecretID>).Result.Value;

Quando si esegue l'applicazione, verrà eseguita l'autenticazione in Azure Active Directory e quindi verrà recuperato il valore del segreto dall'insieme di credenziali delle chiavi di Azure.When you run your application, you should now be authenticating to Azure Active Directory and then retrieving your secret value from Azure Key Vault.

Rotazione delle chiavi con Automazione di AzureKey rotation using Azure Automation

Sono disponibili diverse opzioni per l'implementazione di una strategia di rotazione per i valori memorizzati come segreti dell'insieme di credenziali delle chiavi di Azure.There are various options for implementing a rotation strategy for values you store as Azure Key Vault secrets. La rotazione dei segreti può essere eseguita nell'ambito di un processo manuale, a livello di codice usando chiamate API oppure con uno script di automazione.Secrets can be rotated as part of a manual process, they may be rotated programmatically by using API calls, or they may be rotated by way of an Automation script. In questo articolo verrà usato Azure PowerShell insieme ad Automazione di Azure per modificare una chiave di accesso dell'account di archiviazione di Azure.For the purposes of this article, you will be using Azure PowerShell combined with Azure Automation to change an Azure Storage Account access key. Verrà quindi aggiornato un segreto dell'insieme di credenziali delle chiavi con la nuova chiave.You will then update a key vault secret with that new key.

Per consentire ad Automazione di Azure di impostare i valori del segreto nell'insieme di credenziali delle chiavi, è necessario ottenere l'ID client per la connessione denominata AzureRunAsConnection, creata al momento della definizione dell'istanza di Automazione di Azure.To allow Azure Automation to set secret values in your key vault, you must get the client ID for the connection named AzureRunAsConnection, which was created when you established your Azure Automation instance. È possibile trovare l'ID scegliendo Asset dall'istanza di Automazione di Azure.You can find this ID by choosing Assets from your Azure Automation instance. Scegliere quindi Connessioni e selezionare l'entità servizio AzureRunAsConnection.From there, you choose Connections and then select the AzureRunAsConnection service principle. Prendere nota del valore di ID applicazione.Take note of the Application ID.

ID client di Automazione di Azure

In Asset scegliere Moduli.In Assets, choose Modules. In Moduli selezionare Raccolta e quindi cercare e importare le versioni aggiornate di ognuno dei moduli seguenti:From Modules, select Gallery, and then search for and Import updated versions of each of the following modules:

Azure
Azure.Storage
AzureRM.Profile
AzureRM.KeyVault
AzureRM.Automation
AzureRM.Storage

Nota

Al momento della stesura di questo articolo è necessario aggiornare solo i moduli indicati in precedenza per lo script seguente.At the writing of this article, only the previously noted modules needed to be updated for the following script. Se si verificano errori nel processo di automazione, verificare di avere importato tutti i moduli necessari e le relative dipendenze.If you find that your automation job is failing, confirm that you have imported all necessary modules and their dependencies.

Dopo aver recuperato l'ID applicazione per la connessione di Automazione di Azure è necessario indicare all'insieme di credenziali delle chiavi che l'applicazione è autorizzata ad aggiornare i segreti dell'insieme di credenziali.After you have retrieved the application ID for your Azure Automation connection, you must tell your key vault that this application has access to update secrets in your vault. A tale scopo è possibile usare il comando PowerShell seguente:This can be accomplished with the following PowerShell command:

Set-AzureRmKeyVaultAccessPolicy -VaultName <vaultName> -ServicePrincipalName <applicationIDfromAzureAutomation> -PermissionsToSecrets Set

Selezionare quindi Runbook nell'istanza di Automazione di Azure e quindi selezionare Aggiungi runbook.Next, select Runbooks under your Azure Automation instance, and then select Add a Runbook. Selezionare Creazione rapida.Select Quick Create. Assegnare un nome al runbook e selezionare PowerShell come tipo di runbook.Name your runbook and select PowerShell as the runbook type. È possibile aggiungere una descrizione.You have the option to add a description. Fare infine clic su Crea.Finally, click Create.

Creare un runbook

Incollare lo script di PowerShell seguente nel riquadro dell'editor per il nuovo runbook:Paste the following PowerShell script in the editor pane for your new runbook:

$connectionName = "AzureRunAsConnection"
try
{
    # Get the connection "AzureRunAsConnection "
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

    "Logging in to Azure..."
    Connect-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
    "Login complete."
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

#Optionally you may set the following as parameters
$StorageAccountName = <storageAccountName>
$RGName = <storageAccountResourceGroupName>
$VaultName = <keyVaultName>
$SecretName = <keyVaultSecretName>

#Key name. For example key1 or key2 for the storage account
New-AzureRmStorageAccountKey -ResourceGroupName $RGName -Name $StorageAccountName -KeyName "key2" -Verbose
$SAKeys = Get-AzureRmStorageAccountKey -ResourceGroupName $RGName -Name $StorageAccountName

$secretvalue = ConvertTo-SecureString $SAKeys[1].Value -AsPlainText -Force

$secret = Set-AzureKeyVaultSecret -VaultName $VaultName -Name $SecretName -SecretValue $secretvalue

Nel riquadro dell'editor scegliere Riquadro di test per testare lo script.From the editor pane, choose Test pane to test your script. Dopo aver eseguito lo script senza errori è possibile selezionare Pubblica e quindi applicare una pianificazione per il runbook nel riquadro di configurazione del runbook.Once the script is running without error, you can select Publish, and then you can apply a schedule for the runbook back in the runbook configuration pane.

Pipeline di controllo dell'insieme di credenziali delle chiaviKey Vault auditing pipeline

Quando si configura un insieme di credenziali delle chiavi è possibile attivare il controllo per raccogliere log relativi alle richieste di accesso all'insieme di credenziali delle chiavi.When you set up a key vault, you can turn on auditing to collect logs on access requests made to the key vault. Questi log vengono archiviati in un apposito account di archiviazione di Azure e possono essere estratti, monitorati e analizzati.These logs are stored in a designated Azure Storage account and can be pulled out, monitored, and analyzed. Lo scenario seguente usa le funzioni di Azure, le app per la logica di Azure e i log di controllo dell'insieme di credenziali delle chiavi per creare una pipeline per l'invio di un messaggio di posta elettronica quando i segreti dell'insieme di credenziali vengono recuperati da un'app che corrisponde all'ID app dell'app Web.The following scenario uses Azure functions, Azure logic apps, and key vault audit logs to create a pipeline to send an email when an app that does match the app ID of the web app retrieves secrets from the vault.

È prima di tutto necessario abilitare la registrazione per l'insieme di credenziali delle chiavi.First, you must enable logging on your key vault. Questa operazione può essere eseguita tramite i comandi di PowerShell seguenti (per i dettagli completi, vedere key-vault-logging):This can be done via the following PowerShell commands (full details can be seen at key-vault-logging):

$sa = New-AzureRmStorageAccount -ResourceGroupName <resourceGroupName> -Name <storageAccountName> -Type Standard\_LRS -Location 'East US'
$kv = Get-AzureRmKeyVault -VaultName '<vaultName>'
Set-AzureRmDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -Enabled $true -Categories AuditEvent

Dopo aver abilitato la registrazione, i log di controllo iniziano la raccolta di informazioni nell'account di archiviazione designato.After this is enabled, audit logs start collecting into the designated storage account. Questi log contengono eventi relativi alla modalità di accesso all'insieme di credenziali delle chiavi, a quando avviene l'accesso e a chi lo esegue.These logs contain events about how and when your key vaults are accessed, and by whom.

Nota

È possibile accedere alle informazioni di registrazione dopo 10 minuti dall'operazione sull'insieme di credenziali delle chiavi,You can access your logging information 10 minutes after the key vault operation. ma in genere saranno disponibili anche prima.It will usually be quicker than this.

Il passaggio successivo consiste nella creazione di una coda del bus di servizio di Azure.The next step is to create an Azure Service Bus queue. Questa è la posizione in cui verrà eseguito il push dei log di controllo dell'insieme di credenziali delle chiavi.This is where key vault audit logs are pushed. Quando i messaggi del log di controllo sono nella coda, l'app per la logica li preleva e interviene su di essi.When the audit log messages are in the queue, the logic app picks them up and acts on them. Creare un bus di servizio seguendo questa procedura:Create a service bus with the following steps:

  1. Creare uno spazio dei nomi del bus di servizio. Se è già presente uno spazio dei nomi da usare a questo scopo, andare direttamente al passaggio 2.Create a Service Bus namespace (if you already have one that you want to use for this, skip to Step 2).
  2. Passare al bus di servizio nel portale di Azure e selezionare lo spazio dei nomi nel quale creare la coda.Browse to the service bus in the Azure portal and select the namespace you want to create the queue in.
  3. Selezionare Crea una risorsa, Integrazione aziendale, Bus di servizio, quindi immettere i dettagli richiesti.Select Create a resource, Enterprise Integration, Service Bus, and then enter the required details.
  4. Selezionare le informazioni di connessione del bus di servizio scegliendo lo spazio dei nomi e facendo clic su Informazioni di connessione.Select the Service Bus connection information by choosing the namespace and clicking Connection Information. Queste informazioni saranno necessarie per la sezione successiva.You will need this information for the next section.

Creare una funzione di Azure per eseguire il polling dei log dell'insieme di credenziali delle chiavi nell'account di archiviazione e selezionare i nuovi eventi.Next, create an Azure function to poll key vault logs within the storage account and pick up new events. Questa funzione verrà attivata in base alla pianificazione.This will be a function that is triggered on a schedule.

Per creare una funzione di Azure, scegliere Crea una risorsa, cercare App per le funzioni nel Marketplace e fare clic su Crea.To create an Azure function, choose Create a resource, search the marketplace for Function App, and click Create. Durante la creazione è possibile usare un piano di hosting esistente o crearne uno nuovo.During creation, you can use an existing hosting plan or create a new one. È anche possibile optare per l'hosting dinamico.You could also opt for dynamic hosting. Altre informazioni sulle opzioni di hosting delle funzioni sono disponibili in Scalabilità di Funzioni di Azure.More details on Function hosting options can be found at How to scale Azure Functions.

Dopo aver creato la funzione di Azure, passare alla funzione e scegliere una funzione timer e C#,When the Azure function is created, navigate to it and choose a timer function and C#. quindi fare clic su Creare questa funzione.Then click Create this function.

Pannello iniziale di Funzioni di Azure

Nella scheda Sviluppo sostituire il codice run.csx con il seguente:On the Develop tab, replace the run.csx code with the following:

#r "Newtonsoft.Json"

using System;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.ServiceBus.Messaging;
using System.Text;

public static void Run(TimerInfo myTimer, TextReader inputBlob, TextWriter outputBlob, TraceWriter log)
{
    log.Info("Starting");

    CloudStorageAccount sourceStorageAccount = new CloudStorageAccount(new StorageCredentials("<STORAGE_ACCOUNT_NAME>", "<STORAGE_ACCOUNT_KEY>"), true);

    CloudBlobClient sourceCloudBlobClient = sourceStorageAccount.CreateCloudBlobClient();

    var connectionString = "<SERVICE_BUS_CONNECTION_STRING>";
    var queueName = "<SERVICE_BUS_QUEUE_NAME>";

    var sbClient = QueueClient.CreateFromConnectionString(connectionString, queueName);

    DateTime dtPrev = DateTime.UtcNow;
    if(inputBlob != null)
    {
        var txt = inputBlob.ReadToEnd();

        if(!string.IsNullOrEmpty(txt))
        {
            dtPrev = DateTime.Parse(txt);
            log.Verbose($"SyncPoint: {dtPrev.ToString("O")}");
        }
        else
        {
            dtPrev = DateTime.UtcNow;
            log.Verbose($"Sync point file didnt have a date. Setting to now.");
        }
    }

    var now = DateTime.UtcNow;

    string blobPrefix = "insights-logs-auditevent/resourceId=/SUBSCRIPTIONS/<SUBSCRIPTION_ID>/RESOURCEGROUPS/<RESOURCE_GROUP_NAME>/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/<KEY_VAULT_NAME>/y=" + now.Year +"/m="+now.Month.ToString("D2")+"/d="+ (now.Day).ToString("D2")+"/h="+(now.Hour).ToString("D2")+"/m=00/";

    log.Info($"Scanning:  {blobPrefix}");

    IEnumerable<IListBlobItem> blobs = sourceCloudBlobClient.ListBlobs(blobPrefix, true);

    log.Info($"found {blobs.Count()} blobs");

    foreach(var item in blobs)
    {
        if (item is CloudBlockBlob)
        {
            CloudBlockBlob blockBlob = (CloudBlockBlob)item;

            log.Info($"Syncing: {item.Uri}");

            string sharedAccessUri = GetContainerSasUri(blockBlob);

            CloudBlockBlob sourceBlob = new CloudBlockBlob(new Uri(sharedAccessUri));

            string text;
            using (var memoryStream = new MemoryStream())
            {
                sourceBlob.DownloadToStream(memoryStream);
                text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
            }

            dynamic dynJson = JsonConvert.DeserializeObject(text);

            //required to order by time as they may not be in the file
            var results = ((IEnumerable<dynamic>) dynJson.records).OrderBy(p => p.time);

            foreach (var jsonItem in results)
            {
                DateTime dt = Convert.ToDateTime(jsonItem.time);

                if(dt>dtPrev){
                    log.Info($"{jsonItem.ToString()}");

                    var payloadStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonItem.ToString()));
                    //When sending to ServiceBus, use the payloadStream and set keeporiginal to true
                    var message = new BrokeredMessage(payloadStream, true);
                    sbClient.Send(message);
                    dtPrev = dt;
                }
            }
        }
    }
    outputBlob.Write(dtPrev.ToString("o"));
}

static string GetContainerSasUri(CloudBlockBlob blob)
{
    SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();

    sasConstraints.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
    sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
    sasConstraints.Permissions = SharedAccessBlobPermissions.Read;

    //Generate the shared access signature on the container, setting the constraints directly on the signature.
    string sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);

    //Return the URI string for the container, including the SAS token.
    return blob.Uri + sasBlobToken;
}

Nota

Assicurarsi di sostituire le variabili nel codice precedente in modo che puntino all'account di archiviazione in cui vengono scritti i log dell'insieme di credenziali delle chiavi, al bus di servizio creato in precedenza e al percorso specifico dei log di archiviazione dell'insieme di credenziali delle chiavi.Make sure to replace the variables in the preceding code to point to your storage account where the key vault logs are written, the service bus you created earlier, and the specific path to the key vault storage logs.

La funzione seleziona il file del log più recente dall'account di archiviazione in cui vengono scritti i log dell'insieme di credenziali delle chiavi, acquisisce gli eventi più recenti dal file e ne effettua il push in una coda del bus di servizio.The function picks up the latest log file from the storage account where the key vault logs are written, grabs the latest events from that file, and pushes them to a Service Bus queue. Dato che un singolo file può avere più eventi, è necessario creare un file sync.txt anch'esso esaminato dalla funzione per determinare il timestamp dell'ultimo evento selezionato.Since a single file could have multiple events, you should create a sync.txt file that the function also looks at to determine the time stamp of the last event that was picked up. In questo modo è possibile assicurarsi di non effettuare il push dello stesso evento più volte.This ensures that you don't push the same event multiple times. Questo file sync.txt contiene un timestamp per l'ultimo evento rilevato.This sync.txt file contains a timestamp for the last encountered event. I log, quando caricati, devono essere ordinati in base al timestamp per far sì che vengano ordinati correttamente.The logs, when loaded, have to be sorted based on the timestamp to ensure they are ordered correctly.

Per questa funzione si fa riferimento a un paio di altre librerie non disponibili per impostazione predefinita in Funzioni di Azure.For this function, we reference a couple of additional libraries that are not available out of the box in Azure Functions. Per includerle è necessario che Funzioni di Azure le recuperi tramite NuGet.To include these, we need Azure Functions to pull them using NuGet. Scegliere l'opzione Visualizza file.Choose the View Files option.

Opzione Visualizza file

Aggiungere poi un file denominato project.json con il contenuto seguente:And add a file called project.json with following content:

    {
      "frameworks": {
        "net46":{
          "dependencies": {
                "WindowsAzure.Storage": "7.0.0",
                "WindowsAzure.ServiceBus":"3.2.2"
          }
        }
       }
    }

Dopo aver fatto clic su Salva , Funzioni di Azure scaricherà i file binari necessari.Upon Save, Azure Functions will download the required binaries.

Passare alla scheda Integra e assegnare al parametro timer un nome significativo da usare all'interno della funzione.Switch to the Integrate tab and give the timer parameter a meaningful name to use within the function. Nel codice precedente è previsto che il timer si chiami myTimer.In the preceding code, it expects the timer to be called myTimer. Specificare un'espressione CRON come segue: 0 * * * * * per il timer che attiverà l'esecuzione della funzione una volta al minuto.Specify a CRON expression as follows: 0 * * * * * for the timer that will cause the function to run once a minute.

Nella stessa scheda Integra aggiungere un input di tipo Archiviazione BLOB di Azure.On the same Integrate tab, add an input of the type Azure Blob Storage. Questo punterà al file sync.txt che contiene il timestamp dell'ultimo evento esaminato dalla funzione.This will point to the sync.txt file that contains the timestamp of the last event looked at by the function. L'input sarà disponibile all'interno della funzione in base al nome del parametro.This will be available within the function by the parameter name. Nel codice precedente, l'input Archiviazione BLOB di Azure prevede che il nome del parametro sia inputBlob.In the preceding code, the Azure Blob Storage input expects the parameter name to be inputBlob. Scegliere l'account di archiviazione in cui risiederà il file sync.txt. Può essere lo stesso account di archiviazione o un account diverso.Choose the storage account where the sync.txt file will reside (it could be the same or a different storage account). Nel campo del percorso specificare il percorso in cui si trova il file, nel formato {nome-contenitore}/path/to/sync.txt.In the path field, provide the path where the file lives in the format {container-name}/path/to/sync.txt.

Aggiungere un output di tipo Archiviazione BLOB di Azure.Add an output of the type Azure Blob Storage output. Anche questo punterà al file sync.txt appena definito nell'input.This will point to the sync.txt file you defined in the input. Viene usato dalla funzione per scrivere il timestamp dell'ultimo evento esaminato.This is used by the function to write the timestamp of the last event looked at. Il codice precedente prevede che questo parametro sia denominato outputBlob.The preceding code expects this parameter to be called outputBlob.

A questo punto la funzione è pronta.At this point, the function is ready. Assicurarsi di tornare alla scheda Sviluppo e salvare il codice.Make sure to switch back to the Develop tab and save the code. Verificare se nella finestra di output sono presenti errori di compilazione ed eventualmente correggerli.Check the output window for any compilation errors and correct them accordingly. Dopo la compilazione, il codice controllerà i log dell'insieme di credenziali delle chiavi ogni minuto, effettuando il push di eventuali nuovi eventi nella coda del bus di servizio definito.If the code compiles, then the code should now be checking the key vault logs every minute and pushing any new events onto the defined Service Bus queue. Le informazioni di registrazione verranno scritte nella finestra del log ogni volta che la funzione viene attivata.You should see logging information write out to the log window every time the function is triggered.

App per la logica di AzureAzure logic app

A questo punto è necessario creare un'app per la logica di Azure che seleziona gli eventi di cui la funzione effettua il push nella coda del bus di servizio, analizza il contenuto e invia un messaggio di posta elettronica in base alla soddisfazione di una condizione.Next you must create an Azure logic app that picks up the events that the function is pushing to the Service Bus queue, parses the content, and sends an email based on a condition being matched.

Per creare un'app per la logica passare a Nuovo -> App per la logica.Create a logic app by going to New > Logic App.

Dopo averla creata, passare all'app per la logica e scegliere modifica.Once the logic app is created, navigate to it and choose edit. Nell'editor di app per la logica scegliere Coda del bus di servizio e immettere le credenziali del bus di servizio per connetterlo alla coda.Within the logic app editor, choose Service Bus Queue and enter your Service Bus credentials to connect it to the queue.

Bus di servizio dell'app per la logica di Azure

Scegliere quindi Aggiungi una condizione.Next choose Add a condition. Nella condizione passare all'editor avanzato e immettere il codice seguente, sostituendo APP_ID con l'effettivo APP_ID dell'app Web:In the condition, switch to the advanced editor and enter the following code, replacing APP_ID with the actual APP_ID of your web app:

@equals('<APP_ID>', json(decodeBase64(triggerBody()['ContentData']))['identity']['claim']['appid'])

Questa espressione restituisce essenzialmente false se il valoreappid dell'evento in ingresso, ovvero il corpo del messaggio del bus di servizio, non è l'appid dell'app.This expression essentially returns false if the appid from the incoming event (which is the body of the Service Bus message) is not the appid of the app.

Creare ora un'azione in Se no, non fare nulla .Now, create an action under If no, do nothing.

Scelta dell'azione per l'app per la logica di Azure

Per l'azione, scegliere Office 365 - send email.For the action, choose Office 365 - send email. Compilare i campi per creare un messaggio di posta elettronica da inviare quando la condizione specificata restituisce false.Fill out the fields to create an email to send when the defined condition returns false. Se non si ha Office 365 è possibile valutare alternative per ottenere lo stesso risultato.If you do not have Office 365, you could look at alternatives to achieve the same results.

A questo punto è disponibile una pipeline end-to-end che controlla se sono disponibili nuovi log di controllo dell'insieme di credenziali delle chiavi ogni minuto.At this point, you have an end to end pipeline that looks for new key vault audit logs once a minute. La pipeline effettua il push dei nuovi log trovati in una coda del bus di servizio.It pushes new logs it finds to a service bus queue. L'app per la logica viene attivata quando arriva un nuovo messaggio nella coda.The logic app is triggered when a new message lands in the queue. Se l'appid all'interno dell'evento non corrisponde all'ID app dell'applicazione chiamante, invia un messaggio di posta elettronica.If the appid within the event does not match the app ID of the calling application, it sends an email.