MS Certificering: AZ-204, overnieuw beginnen, deel 07

Ingediend door Dirk Hornstra op 21-dec-2021 15:30

Na het 1e blok: Azure App Service web apps (link), het 2e blok: Implement Azure Functions (link), het 3e blok: Develop solutions that use Blob Storage (link) en het 4e blok: Develop solutions that use Azure Cosmos DB (link), het 5e blok: Implement infrastructure as a service solutions: (link), het 6e blok Implement user authentication and authorization (link) is het nu tijd voor het 7e learning-block: Implement secure cloud solutions, link.

Module 1: Implement Azure Key Vault, link.

We beginnen met Key Vault. Zijn we al eens eerder tegen gekomen, een prima manier om je gegevens die "gevoelig" zijn op een veilige manier op te slaan. Azure Key Vault ondersteunt 2 type containers, vaults (dus een gewoon soort opslag) en managed hardware security module (HSM) pools. In een vault kun je software, certificaten en sleutels die met HSM opgebouwd worden opslaan. HSM pools ondersteunen alleen door HSM opgebouwde sleutels.

Key Vault lost deze problemen op:

  • beheer van "geheimen", je kunt hier tokens, wachtwoorden, certicaten, API sleutels en andere "geheimen" opslaan.
  • beheer van sleutels, Key Vault maakt het makkelijk om sleutels aan te maken en te beheren die je gebruikt om je data te encrypten.
  • beheer van certificaten, je kunt hier publieke en private SSL certificaten provisionen, beheren en deployen.


Er zijn 2 type abonnementen, standard: encrypt met een software key en premium: deze kan ook HSM-beschermde sleutels bevatten. Je kunt deze 2 hier vergelijken: link.

Belangrijkste voordelen:

  • een centrale plek voor je geheimen, zodat je de distributie kunt beheren. De apps halen de secret op met een bepaalde URI.
  • het veilig opslaan van geheimen en sleutels, je krijgt alleen toegang via authenticatie (Azure Active Directory). Authorizatie kan via rollen ingeregeld worden (RBAC) of key vault access policy. RBAC is voor het beheer van de vault (dus als je in de portal zaken aanpast), access policy is voor het opvragen van de data. Een vault kan beschermd zijn via software of als je premium hebt via hardware door de hardware security module.
  • monitoren van toegang en gebruik, door logging aan te zetten in je vault kun je zien wie wanneer toegang heeft. Je kunt de logs ook opruimen/verwijderen. Je hebt een aantal opties, logs kunnen opgeslagen worden in een storage account, gestreamd worden naar een event hub of naar de Azure Monitor Logs.
  • simpeler maken van beheer van je "geheimen", gevoelige data moet beveiligd worden, het moet een life-cycle volgen en moet een hoge beschikbaarheid hebben. Azure Key Vault kan dit door
  1. als je een hardware security module nodig hebt, hoef je dat niet zelf uit te zoeken, premium biedt je dit.
  2. als er ineens meer aanvragen zijn kun je opschalen.
  3. replicatie van je key vault binnen een regio en naar een secundaire regio.
  4. standaard beheer-opties via de portal, Azure CLI en PowerShell.
  5. automatiseren van bepaalde taken, zoals het installeren en vernieuwen van certificaten.


Vervolgens krijgen we de "best practises" om met Key Vault te werken:

Authenticatie
Je moet je eerst authenticeren, dat kan op 3 manieren

  • managed identities, als je een app naar een VM deployed, kun je een identity aan de VM toewijzen die toegang heeft tot de Key Vault. Je kunt ook identiteiten toewijzen aan andere Azure resources. Hierdoor hoef je je niet druk te maken over het "roteren van het eerste geheim", omdat Azure automatisch rotatie uitvoert bij de client secret van service principal. Daarom raadt Microsoft deze implementatie aan.
  • service principal en certificaat, niet aangeraden door Microsoft omdat de eigenaar of ontwikkelaar zelf het certificaat moet "roteren".
  • service principal en geheim, ook dit wordt niet aangeraden. Volgens Microsoft is het moeilijk om rotatie van het geheim te automatiseren.


Verkeer van en naar de vault gaat via HTTPS (TLS wordt genoemd). Connecties tussen client systemen en Microsoft cloud services is op basis van perfect forward secrecy (PFS) verbindingen. Deze verbindingen gebruiken RSA 2.048 bit geëncrypte sleutellengtes.

  • Gebruik losse key vaults, gebruik een vault per applicatie per omgeving (dev, test, prod), hiermee voorkom je het delen van geheimen tussen omgevingen en beperkt problemen bij een "security breach".
  • Beheer de toegang tot de vault, sta alleen geautoriseerde applicaties en gebruikers toe.
  • Back-up, maak regelmatig backups op momenten dat er een update/delete/create actie uitgevoerd wordt.
  • Logging, zet het aan, zorg voor logging en alerts.
  • Herstelopties, zet soft-delete en purge protection aan als je wilt voorkomen dat dat per ongeluk verwijderd wordt: link.
     

Authenticatie werkt samen met Azure Active Directory. Je kunt een systeem-toegewezen managed identity aan de applicatie koppelen. Hiermee kan Azure intern de service principal beheren en de applicatie authenticeren bij andere diensten van Azure. Als dat niet lukt, dan kun je de applicatie registreren met je Azure AD tenant. Dat maakt een 2e applicatie object aan welke de app indentificeert bij andere tenants.
De systeem-toegewezen identity heeft de voorkeur van Microsoft.

En ook hier heb je weer SDK's voor de programmeertalen, .NET (link), Python (link), Java (link) en JavaScript (link).

Voorbeeld hoe je dit met REST doet:


PUT /keys/MYKEY?api-version=<api_version>  HTTP/1.1  
Authorization: Bearer <access_token>


// En als authenticatie niet lukt krijg je dit terug

401 Not Authorized  
WWW-Authenticate: Bearer authorization="…", resource="…"

In die WWW-header zit in de authorization het adres van de OAuth2 dienst waar je een token kunt krijgen en resource is de naam van de resource die je aan wilt roepen (in dit geval https://vault.azure.net/)

Hier meer informatie voor developers (link) en meer over beschikbaarheid en redundantie (link).

Hierna volgt een oefening hoe je via de Azure CLI een "secret" opvraagt;


// maak een key vault
myKeyVault=az204vault-$RANDOM
myLocation=<myLocation>

az group create --name az204-vault-rg --location $myLocation

az keyvault create --name $myKeyVault --resource-group az204-vault-rg --location $myLocation

// voeg een secret toe en vraag het op

az keyvault secret set --vault-name $myKeyVault --name "ExamplePassword" --value "hVFkk965BuUv"

az keyvault secret show --name "ExamplePassword" --vault-name $myKeyVault

// en weer opruimen

az group delete --name az204-vault-rg --no-wait


Module 2: Implement managed identities, link.

We komen nog even terug op de system-assigned managed identity en de user-assigned managed identity. Bij een systeem-identity maakt Azure deze aan en koppelt deze aan een instantie van een dienst waar deze bij hoort. Als deze instantie verwijderd wordt, wordt ook deze identity verwijderd. Bij een user-assigned identity is dit niet het geval. En hier hoort nog bij dat een system-assigned identity bij die resource hoort en niet gedeeld kan worden met andere resources, wat een user-assigned identity wel kan.

In de voorbeelden gaan we kijken naar Virtuele Machines, maar ook andere diensten ondersteunen de managed identities, dat kun je nalezen in deze lijst: link.

Stel dat je dit bij een VM wilt gebruiken. Dan krijg de Azure Resource Manager het verzoek binnen dat er een system-assigned managed identity aan die VM moet komen. RM maakt een service principal in Azure Active Directory voor de identity van de VM. RM configureert deze identity op de VM door de Azure Instance Metadata Service identity endpoint in te stellen op de principal client ID en certificaat. Hierna kun je de VM via de principal toegang geven aan andere resources. Als je code in de VM hebt, die kan een token op vragen door een interne call te doen naar http://169.254.169.254/metadata/identity/oauth2/token
Onder water gaat er een call naar Active Directory om een token op te vragen met client ID en crtificaat. AD geeft een JSON Web Token terug.
Jouw code kan dat token gebruiken voor calls naar andere diensten.

Als je een user-assigned identity wil gebruiken, komt dat verzoek ook binnen bij de Azure Resource Manager. RM maakt een service principal in AD aan. Ook hier wordt het endpoint door RM aangepast. Hierna (maar schijnbaar ook hiervoor) kun je via de service principal toegang geven. De rest van de stappen lijken gelijk te zijn.

Als je een VM aan wilt maken met een system-assigned managed identity, dan moet jouw account de Virtual Machine Contributor rol hebben (anders kan/mag het niet).

Voorbeeld voor het aanmaken:


az vm create --resource-group myResourceGroup \
    --name myVM --image win2016datacenter \
    --generate-ssh-keys \
    --assign-identity \
    --admin-username azureuser \
    --admin-password myPassword12

Als je na de tijd op een bestaande VM dit wil toevoegen, dan doe je deze aanroep:


az vm identity assign -g myResourceGroup -n myVm

Als je een user-assigned identity wilt koppelen, dan moet jouw account de rollen Virtual Machine Contributor en Managed Identity Operator hebben.

Maak eerst de identity aan en geef deze als parameter mee:


az identity create -g myResourceGroup -n myUserAssignedIdentity

az vm create \
--resource-group <RESOURCE GROUP> \
--name <VM NAME> \
--image UbuntuLTS \
--admin-username <USER NAME> \
--admin-password <PASSWORD> \
--assign-identity <USER ASSIGNED IDENTITY NAME>
 

En als je deze op een later tijdstip wilt toevoegen:


az vm identity assign \
    -g <RESOURCE GROUP> \
    -n <VM NAME> \
    --identities <USER ASSIGNED IDENTITY>

Er zijn SDK's beschikbaar om dit werkend te krijgen: link.
En hierbij nog even wat voorbeelden:

SDK Sample
.NET Manage resource from a virtual machine enabled with managed identities for Azure resources enabled
Java Manage storage from a virtual machine enabled with managed identities for Azure resources
Node.js Create a virtual machine with system-assigned managed identity enabled
Python Create a virtual machine with system-assigned managed identity enabled
Ruby Create Azure virtual machine with an system-assigned identity enabled

Een applicatie kan een token aanvragen bij een managed identity om toegang te krijgen tot een bepaalde resource.

De voorbeelden die we zien, daarbij is de aanname dat de client in een VM uitgevoerd wordt met managed identities.


// vraag het token op
GET 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' HTTP/1.1 Metadata: true

// response
HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJ0eXAi...",
  "refresh_token": "",
  "expires_in": "3599",
  "expires_on": "1506484173",
  "not_before": "1506480273",
  "resource": "https://management.azure.com/",
  "token_type": "Bearer"
}

// opvragen met C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;

// Build request to acquire managed identities for Azure resources token
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/");
request.Headers["Metadata"] = "true";
request.Method = "GET";

try
{
    // Call /token endpoint
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    // Pipe response Stream to a StreamReader, and extract access token
    StreamReader streamResponse = new StreamReader(response.GetResponseStream());
    string stringResponse = streamResponse.ReadToEnd();
    JavaScriptSerializer j = new JavaScriptSerializer();
    Dictionary<string, string> list = (Dictionary<string, string>) j.Deserialize(stringResponse, typeof(Dictionary<string, string>));
    string accessToken = list["access_token"];
}
catch (Exception e)
{
    string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
}

Het advies is om tokens te cachen. Dan heb je dus wel de kans dat een token niet meer geldig is (is verlopen).

Als je een foutcode krijgt 404, 429, 5xx is het advies om een retry te doen. Door throtteling kan iets tijdelijk afgesloten zijn (je zult een 429 terug krijgen).


Module 3: Implement Azure App Configuration, link.

Met Azure App Configuration heb je een dienst waarmee je centraal je app-settings en feature-flags kunt beheren.

Je kent het wel, een dienst die door meerdere programma's gebruikt wordt en daardoor op meerdere plekken in configuratiebestanden staat. Wijzigt daar iets, dan moet je het dus "overal" aanpassen.

App Configuration biedt:

  • een uitgebreide dienst die in minuten opgezet kan worden
  • flexibele representatie en mapping van sleutels
  • taggen met labels
  • point-in-time weergave van instellingen (hoe was het vorige week?)
  • UI voor feature flag beheer
  • vergelijken van 2 configuratie-sets op eigen gedefinieerde dimensies
  • uitgebreid beveiligd dankzij de managed identity
  • tijdens opslag en transport geëncrypt
  • geïntegreerd met veel frameworks

App Configuration is een toevoeging op de Key Vault. Je hebt een centraal beheersysteem voor distributie en een hiërarchische configuratie voor data voor verschillende omgevingen en landen, pas dynamisch de configuratie aan zonder een redeploy of herstart te hoeven forceren en beheer features in "real time".

Je hoeft geen dingen zelf te bouwen, gebruik de beschikbare bibliotheken:

  • .NET Core and ASP.NET Core: App Configuration provider for .NET Core
  • .NET Framework and ASP.NET:  App Configuration builder for .NET
  • Java Spring: App Configuration client for Spring Cloud
  • Anderen: App Configuration REST API


Data wordt opgeslagen als key-value paren. Je kunt deze hiërarchisch weergeven met een bepaald scheidingsteken, zoals een / of :
Maak zelf hier afspraken over wat jij/jouw bedrijf gaat gebruiken. Sleutels zijn case-sensitive en unicode-gebaseerd. app1 en App1 zijn 2 verschillende sleutels. Je kunt elk unicode-karakter gebruiken voor de sleutelnaam behalve * , en \ Als je deze wel nodig hebt, moet je deze escapen met een \
Het totaal van een sleutel en een waarde kan maximaal 10.000 karakters bevatten.

Met een hiërarchische weergave is uiteindelijk je intentie beter leesbaar, beter te gebruiken in je code (hoe bouw ik dit ook alweer op?) en beter te onderhouden. Je kunt deze scheiden:


// op basis van component services
AppName:Service1:ApiEndpoint
AppName:Service2:ApiEndpoint

// op basis van deploymet regions
AppName:Region1:DbEndpoint
AppName:Region2:DbEndpoint

Met labels kun je een onderscheid maken tussen sleutels die dezelfde key hebben.

Key = AppName:DbEndpoint & Label = Test
Key = AppName:DbEndpoint & Label = Staging
Key = AppName:DbEndpoint & Label = Production

Er wordt niet automatisch een versie aan een sleutel gekoppeld. Ook dat kun je met een label doen, door daar een applicatie versie nummer of GIT commit ID in mee te nemen.

Ook de waardes kunnen alle unicode-karakters bevatten (geen uitzonderingen).

En een goede tip: dit is geen vervanger voor Key Vault dus sla geen "echte" geheimen hierin op!

Er volgt een korte uitleg over feature flags, iets wat we al eerder gezien hebben. Zo is een feature flag een boolean, hij is aan of uit. Met de feature manager beheer je al deze features. En met een filter kun je controleren welke waarde een feature flag heeft.


// feature flag in code:

if (featureFlag) {
    // Run the following code
}

// configuratie in appsettings.json
"FeatureManagement": {
    "FeatureA": true, // Feature flag set to on
    "FeatureB": false, // Feature flag set to off
    "FeatureC": {
        "EnabledFor": [
            {
                "Name": "Percentage",
                "Parameters": {
                    "Value": 50
                }
            }
        ]
    }
}

De data van App Configuration wordt in rust opgeslagen met 256 bit AES encryptie. Als je de optie customer-managed key capability aan hebt staan gebruikt App Configuration een managed identity om met AD te authenticeren. Die roept Key Vault aan en "wrapt" de encryptie-sleutel. Die wordt opgeslagen en de plain versie wordt voor 1 uur gecached in App Configuration. Deze wordt elk uur ververst. Dit garandeert beschikbaarheid onder normale omstandigheden.

Als je die customer-managed key capability aan wilt zetten moet je een standard tier Azure App Configuration instance hebben, Azure Key Vault met soft-delete en purge-protection aan, een RSA of RSA-HSM sleutel in de key vault hebben, deze moet niet verlopen, actief zijn en moet zowel "wrap" als ook "unwrap" mogelijkheden actief hebben.

Hierna moet je nog 2 dingen doen:

  • wijs een managed identity toe aan de Azure App Configuration instantie
  • Geef in de Key Vault access policy rechten aan deze identity op GET, WRAP en UNWRAP.


Gebruik private endpoints (een virtual network, VNet) om veilig data uit te wisselen. Hiermee:

  • beveilig je de configuratie details door de firewall opdracht te geven alle connecties vanuit publieke endpoints te blokkeren
  • verhoog veiligheid voor het virtual network (VNet) om te verzekeren dat data niet uit het VNet lekt
  • verbind op een veilige manier de App Configuration store van on-premise netwerken binnnen jouw bedrijf die via VPN of ExpressRoutes bij het VNet kunnen komen.


Als je een private endpoint gebruikt, dan moet je aangeven met welke store je connect. Als je meerdere hebt, moet je voor elke een eigen private endpoint instellen. Connectiestrings kun je vinden via Settings - Access Keys.

Als je een private endpoint gebruikt wordt er een alias in het subdomein met een CNAME met prefix privatelink toegevoegd: link.

Voorbeeld toevoegen system-assigned identity:


az appconfig identity assign \
    --name myTestAppConfigStore \
    --resource-group myResourceGroup

Voorbeeld user-assigned identity:


az identity create -resource-group myResourceGroup --name myUserAssignedIdentity

az appconfig identity assign --name myTestAppConfigStore \
    --resource-group myResourceGroup \
    --identities /subscriptions/[subscription id]/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity