Beveiligingsoverwegingen voor bedrijfskritieke workloads
Bedrijfskritieke workloads moeten inherent worden beveiligd. Als er inbreuk is op een toepassing of infrastructuur, loopt u risico op beschikbaarheid. De focus van deze architectuur is om de betrouwbaarheid te maximaliseren, zodat de toepassing onder alle omstandigheden goed presteert en beschikbaar blijft. Beveiligingscontroles worden voornamelijk toegepast met het doel bedreigingen te beperken die van invloed zijn op beschikbaarheid en betrouwbaarheid.
Notitie
Uw bedrijfsvereisten hebben mogelijk meer beveiligingsmaatregelen nodig. We raden u ten zeerste aan om de besturingselementen in uw implementatie uit te breiden volgens de richtlijnen in Azure Well-Architected Framework-beveiligingsoverwegingen voor bedrijfskritieke workloads.
Identiteits- en toegangsbeheer
Op toepassingsniveau maakt deze architectuur gebruik van een eenvoudig verificatieschema op basis van API-sleutels voor bepaalde beperkte bewerkingen, zoals het maken van catalogusitems of het verwijderen van opmerkingen. Geavanceerde scenario's, zoals gebruikersverificatie en gebruikersrollen, vallen buiten het bereik van de basislijnarchitectuur.
Als voor uw toepassing gebruikersverificatie en accountbeheer is vereist, volgt u de aanbevelingen voor identiteits- en toegangsbeheer. Sommige strategieën omvatten het gebruik van beheerde id-providers, het vermijden van aangepast identiteitsbeheer en het gebruik van verificatie zonder wachtwoord, indien mogelijk.
Toegang tot minimale bevoegdheden
Configureer toegangsbeleid zodat gebruikers en toepassingen het minimale toegangsniveau krijgen dat ze nodig hebben om hun functie te vervullen. Ontwikkelaars hebben doorgaans geen toegang nodig tot de productie-infrastructuur, maar de implementatiepijplijn heeft wel volledige toegang nodig. Kubernetes-clusters pushen containerinstallatiekopieën niet naar een register, maar GitHub-werkstromen kunnen wel. Front-end-API's ontvangen meestal geen berichten van de berichtenbroker en back-endmedewerkers verzenden niet noodzakelijkerwijs nieuwe berichten naar de broker. Deze beslissingen zijn afhankelijk van de workload en het toegangsniveau dat u toewijst, moet de functionaliteit van elk onderdeel weerspiegelen.
Voorbeelden van de essentiële referentie-implementatie van Azure zijn:
- Elk toepassingsonderdeel dat met Azure Event Hubs werkt, maakt gebruik van een verbindingsreeks met de machtigingen Listen (
BackgroundProcessor
) of Send (CatalogService
). Dat toegangsniveau zorgt ervoor dat elke pod alleen de minimale toegang heeft die nodig is om aan de functie te voldoen. - De service-principal voor de AKS-agentgroep (Azure Kubernetes Service) heeft alleen machtigingen ophalen en weergeven voor geheimen in Azure Key Vault.
- De AKS Kubelet-identiteit heeft alleen de AcrPull-machtiging voor toegang tot het globale containerregister.
Beheerde identiteiten
Om de beveiliging van een bedrijfskritieke workload te verbeteren, vermijdt u het gebruik van op services gebaseerde geheimen, zoals verbindingsreeks s of API-sleutels, indien mogelijk. U wordt aangeraden beheerde identiteiten te gebruiken als de Azure-service die mogelijkheid ondersteunt.
De referentie-implementatie maakt gebruik van een door de service toegewezen beheerde identiteit in de AKS-agentgroep ('Kubelet-identiteit') voor toegang tot het globale Azure Container Registry en de sleutelkluis van een stempel. De juiste ingebouwde rollen worden gebruikt om de toegang te beperken. Met deze Terraform-code wordt bijvoorbeeld alleen de AcrPull
rol toegewezen aan de Kubelet-identiteit:
resource "azurerm_role_assignment" "acrpull_role" {
scope = data.azurerm_container_registry.global.id
role_definition_name = "AcrPull"
principal_id = azurerm_kubernetes_cluster.stamp.kubelet_identity.0.object_id
}
Geheimen
Gebruik indien mogelijk Microsoft Entra-verificatie in plaats van sleutels wanneer u toegang hebt tot Azure-resources. Veel Azure-services, zoals Azure Cosmos DB en Azure Storage, ondersteunen de optie om sleutelverificatie volledig uit te schakelen. AKS ondersteunt Microsoft Entra Workload-ID.
Voor scenario's waarin u Microsoft Entra-verificatie niet kunt gebruiken, heeft elke implementatiestempel een toegewezen exemplaar van Key Vault voor het opslaan van sleutels. Deze sleutels worden automatisch gemaakt tijdens de implementatie en worden opgeslagen in Key Vault met Terraform. Geen menselijke operator, behalve ontwikkelaars in end-to-end-omgevingen, kunnen communiceren met geheimen. Daarnaast worden Key Vault-toegangsbeleid geconfigureerd zodat er geen gebruikersaccounts toegang hebben tot geheimen.
Notitie
Deze workload maakt geen gebruik van aangepaste certificaten, maar dezelfde principes zijn van toepassing.
In het AKS-cluster staat de Key Vault-provider voor geheimenarchief de toepassing toe geheimen te gebruiken. Het CSI-stuurprogramma laadt sleutels uit Key Vault en koppelt deze als bestanden in afzonderlijke pods.
#
# /src/config/csi-secrets-driver/chart/csi-secrets-driver-config/templates/csi-secrets-driver.yaml
#
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-kv
spec:
provider: azure
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: {{ .Values.azure.managedIdentityClientId | quote }}
keyvaultName: {{ .Values.azure.keyVaultName | quote }}
tenantId: {{ .Values.azure.tenantId | quote }}
objects: |
array:
{{- range .Values.kvSecrets }}
- |
objectName: {{ . | quote }}
objectAlias: {{ . | lower | replace "-" "_" | quote }}
objectType: secret
{{- end }}
De referentie-implementatie maakt gebruik van Helm met Azure Pipelines om het CSI-stuurprogramma te implementeren dat alle sleutelnamen uit Key Vault bevat. Het stuurprogramma is ook verantwoordelijk voor het vernieuwen van gekoppelde geheimen als deze worden gewijzigd in Key Vault.
Aan het eind van de consument gebruiken beide .NET-toepassingen de ingebouwde mogelijkheid om configuratie van bestanden te lezen (AddKeyPerFile
):
//
// /src/app/AlwaysOn.BackgroundProcessor/Program.cs
// + using Microsoft.Extensions.Configuration;
//
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
// Load values from Kubernetes CSI Key Vault driver mount point.
config.AddKeyPerFile(directoryPath: "/mnt/secrets-store/", optional: true, reloadOnChange: true);
// More configuration if needed...
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
De combinatie van het automatisch laden van het CSI-stuurprogramma en reloadOnChange: true
zorgt ervoor dat wanneer sleutels in Key Vault worden gewijzigd, de nieuwe waarden op het cluster worden gekoppeld. Dit proces garandeert geen geheime rotatie in de toepassing. De implementatie maakt gebruik van een Singleton Azure Cosmos DB-clientinstantie waarvoor de pod opnieuw moet worden opgestart om de wijziging toe te passen.
Aangepaste domeinen en TLS
Webworkloads moeten HTTPS gebruiken om man-in-the-middle-aanvallen op alle interactieniveaus te voorkomen, zoals communicatie van de client naar de API of van API naar API. Zorg ervoor dat u certificaatrotatie automatiseert omdat verlopen certificaten nog steeds een veelvoorkomende oorzaak zijn van storingen en verslechterde ervaringen.
De referentie-implementatie biedt volledige ondersteuning voor HTTPS met aangepaste domeinnamen, zoals contoso.com
. Ook wordt de juiste configuratie toegepast op zowel de int
omgevingen prod
als de omgeving. U kunt ook aangepaste domeinen toevoegen voor e2e
omgevingen. Deze referentie-implementatie gebruikt echter geen aangepaste domeinnamen vanwege de korte levensduur van e2e
en de verhoogde implementatietijd wanneer u aangepaste domeinen met SSL-certificaten in Azure Front Door gebruikt.
Als u volledige automatisering van de implementatie wilt inschakelen, moet u het aangepaste domein beheren via een Azure DNS-zone. Pijplijn voor infrastructuurimplementatie maakt dynamisch CNAME-records in de Azure DNS-zone en wijst deze records automatisch toe aan een Azure Front Door-exemplaar.
Door Azure Front Door beheerde SSL-certificaten zijn ingeschakeld, waardoor handmatige SSL-certificaatvernieuwingen worden verwijderd. TLS 1.2 is geconfigureerd als de minimale versie.
#
# /src/infra/workload/globalresources/frontdoor.tf
#
resource "azurerm_frontdoor_custom_https_configuration" "custom_domain_https" {
count = var.custom_fqdn != "" ? 1 : 0
frontend_endpoint_id = "${azurerm_frontdoor.main.id}/frontendEndpoints/${local.frontdoor_custom_frontend_name}"
custom_https_provisioning_enabled = true
custom_https_configuration {
certificate_source = "FrontDoor"
}
}
Omgevingen die niet zijn ingericht met aangepaste domeinen, zijn toegankelijk via het standaard Azure Front Door-eindpunt. U kunt ze bijvoorbeeld bereiken op een adres zoals env123.azurefd.net
.
Notitie
Op de controller voor inkomend verkeer van het cluster worden aangepaste domeinen in beide gevallen niet gebruikt. In plaats daarvan wordt een door Azure geleverde DNS-naam zoals [prefix]-cluster.[region].cloudapp.azure.com
gebruikt met Let's Encrypt, waarmee gratis SSL-certificaten voor deze eindpunten kunnen worden uitgegeven.
De referentie-implementatie maakt gebruik van Jetstack's cert-manager
voor het automatisch inrichten van SSL/TLS-certificaten van Let's Encrypt voor regels voor inkomend verkeer. Meer configuratie-instellingen, zoals de ClusterIssuer
, die certificaten van Let's Encrypt aanvraagt, worden geïmplementeerd via een afzonderlijke cert-manager-config
Helm-grafiek die is opgeslagen in src/config/cert-manager/chart.
Deze implementatie gebruikt ClusterIssuer
in plaats van Issuer
om verleners voor elke naamruimte te voorkomen. Zie de documentatie voor certificaatbeheer en de opmerkingen bij de release van cert-manager voor meer informatie.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
Configuratie
Alle configuratie van de toepassingsruntime wordt opgeslagen in Key Vault, inclusief geheimen en niet-gevoelige instellingen. U kunt een configuratiearchief, zoals Azure-app Configuratie, gebruiken om de instellingen op te slaan. Als u één winkel hebt, vermindert u echter het aantal mogelijke storingspunten voor bedrijfskritieke toepassingen. Gebruik Key Vault voor runtimeconfiguratie om de algehele implementatie te vereenvoudigen.
Sleutelkluizen moeten worden ingevuld door de implementatiepijplijn. In de implementatie worden de vereiste waarden rechtstreeks afkomstig van Terraform, zoals database-verbindingsreeks s, of doorgegeven als Terraform-variabelen vanuit de implementatiepijplijn.
Infrastructuur- en implementatieconfiguratie van afzonderlijke omgevingen, zoals e2e
, int
en prod
, wordt opgeslagen in variabele bestanden die deel uitmaken van de broncodeopslagplaats. Deze aanpak heeft twee voordelen:
- Alle wijzigingen in een omgeving worden bijgehouden en doorlopen implementatiepijplijnen voordat ze worden toegepast op de omgeving.
- Afzonderlijke
e2e
omgevingen kunnen anders worden geconfigureerd omdat de implementatie is gebaseerd op code in een vertakking.
Een uitzondering hierop is de opslag van gevoelige waarden voor pijplijnen. Deze waarden worden opgeslagen als geheimen in Azure DevOps-variabelegroepen.
Beveiliging van de container
Het is nodig om containerinstallatiekopieën te beveiligen voor alle containerworkloads.
Deze referentie-implementatie maakt gebruik van Workload Docker-containers die zijn gebaseerd op runtime-installatiekopieën, niet sdk, om de footprint en het potentiële kwetsbaarheid voor aanvallen te minimaliseren. Er zijn geen andere hulpprogramma's geïnstalleerd, zoals ping
, wget
of curl
.
De toepassing wordt uitgevoerd onder een niet-gemachtigde gebruiker workload
die is gemaakt als onderdeel van het buildproces voor installatiekopieën:
RUN groupadd -r workload && useradd --no-log-init -r -g workload workload
USER workload
De referentie-implementatie maakt gebruik van Helm om de YAML-manifesten te verpakken die nodig zijn voor het implementeren van afzonderlijke onderdelen. Dit proces omvat hun Kubernetes-implementatie, services, horizontale configuratie voor automatische schaalaanpassing van pods en beveiligingscontext. Alle Helm-grafieken bevatten fundamentele beveiligingsmaatregelen die voldoen aan de aanbevolen procedures van Kubernetes.
Deze beveiligingsmaatregelen zijn:
readOnlyFilesystem
: Het hoofdbestandssysteem/
in elke container is ingesteld op alleen-lezen om te voorkomen dat de container naar het hostbestandssysteem schrijft. Deze beperking voorkomt dat aanvallers meer hulpprogramma's downloaden en code in de container persistent maken. Mappen waarvoor lees-schrijftoegang is vereist, worden als volumes gekoppeld.privileged
: Alle containers worden ingesteld om te worden uitgevoerd als niet-bevoegde containers. Als u een container uitvoert als bevoegd, beschikt u over alle mogelijkheden voor de container en worden ook alle beperkingen opgeheven die de controller voor apparaatbeheergroepen afdwingt.allowPrivilegeEscalation
: Hiermee voorkomt u dat de binnenkant van een container meer bevoegdheden krijgt dan het bovenliggende proces.
Deze beveiligingsmaatregelen worden ook geconfigureerd voor niet-Microsoft-containers en Helm-grafieken, zoals cert-manager
indien mogelijk. U kunt Azure Policy gebruiken om deze beveiligingsmaatregelen te controleren.
#
# Example:
# /src/app/charts/backgroundprocessor/values.yaml
#
containerSecurityContext:
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
Elke omgeving, inclusief prod
, int
en elke e2e
omgeving, heeft een toegewezen exemplaar van Container Registry met globale replicatie naar elke regio waar stempels worden geïmplementeerd.
Notitie
Deze referentie-implementatie maakt geen gebruik van scannen op beveiligingsproblemen van Docker-installatiekopieën. U wordt aangeraden Microsoft Defender te gebruiken voor containerregisters, mogelijk met GitHub Actions.
Inkomend verkeer
Azure Front Door is de wereldwijde load balancer in deze architectuur. Alle webaanvragen worden doorgestuurd via Azure Front Door, waarmee de juiste back-end wordt geselecteerd. Bedrijfskritieke toepassingen moeten profiteren van andere Mogelijkheden van Azure Front Door, zoals WEB Application Firewalls (WAF's).
Web Application Firewall
Een belangrijke Azure Front Door-functie is de WAF, omdat Hiermee Azure Front Door verkeer kan inspecteren dat wordt doorgegeven. In de preventiemodus worden alle verdachte aanvragen geblokkeerd. In de implementatie worden twee regelsets geconfigureerd. Deze regelsets zijn Microsoft_DefaultRuleSet
en Microsoft_BotManagerRuleSet
.
Tip
Wanneer u Azure Front Door implementeert met WAF, raden we u aan om te beginnen met de detectiemodus . Controleer het gedrag ervan nauwkeurig met natuurlijk klantverkeer en verfijn de detectieregels. Nadat u fout-positieven hebt geëlimineerd of als fout-positieven zeldzaam zijn, schakelt u over naar de preventiemodus . Dit proces is nodig omdat elke toepassing anders is en sommige nettoladingen als schadelijk kunnen worden beschouwd, ook al zijn ze legitiem voor die specifieke workload.
Routering
Alleen aanvragen die via Azure Front Door worden verzonden, worden doorgestuurd naar de API-containers, zoals CatalogService
en HealthService
. Gebruik een Nginx-configuratie voor inkomend verkeer om dit gedrag af te dwingen. Er wordt gecontroleerd op de aanwezigheid van een X-Azure-FDID
header en of deze de juiste is voor het globale Azure Front Door-exemplaar van een specifieke omgeving.
#
# /src/app/charts/catalogservice/templates/ingress.yaml
#
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
# ...
annotations:
# To restrict traffic coming only through our Azure Front Door instance, we use a header check on the X-Azure-FDID.
# The pipeline injects the value. Therefore, it's important to treat this ID as a sensitive value.
nginx.ingress.kubernetes.io/modsecurity-snippet: |
SecRuleEngine On
SecRule &REQUEST_HEADERS:X-Azure-FDID \"@eq 0\" \"log,deny,id:106,status:403,msg:\'Front Door ID not present\'\"
SecRule REQUEST_HEADERS:X-Azure-FDID \"@rx ^(?!{{ .Values.azure.frontdoorid }}).*$\" \"log,deny,id:107,status:403,msg:\'Wrong Front Door ID\'\"
# ...
Implementatiepijplijnen helpen ervoor te zorgen dat deze header correct is gevuld, maar deze beperking moet ook worden overgeslagen voor betrouwbaarheidstests, omdat ze elk cluster rechtstreeks testen in plaats van via Azure Front Door. De referentie-implementatie maakt gebruik van het feit dat betrouwbaarheidstests worden uitgevoerd als onderdeel van de implementatie. Met dit ontwerp kan de headerwaarde bekend zijn en worden toegevoegd aan de HTTP-aanvragen voor betrouwbaarheidstests.
#
# /.ado/pipelines/scripts/Run-SmokeTests.ps1
#
$header = @{
"X-Azure-FDID" = "$frontdoorHeaderId"
"TEST-DATA" = "true" # Header to indicate that posted comments and ratings are for tests and can be deleted again by the app.
}
Beveiligde implementaties
Als u de goed ontworpen basisbeginselen voor operationele uitmuntendheid wilt volgen, automatiseert u alle implementaties volledig. Ze moeten geen handmatige stappen vereisen, behalve om de uitvoering te activeren of een poort goed te keuren.
U moet schadelijke pogingen of onbedoelde onjuiste configuraties voorkomen die beveiligingsmaatregelen kunnen uitschakelen. De referentie-implementatie maakt gebruik van dezelfde pijplijn voor zowel infrastructuur- als toepassingsimplementatie, waardoor een geautomatiseerde terugdraaiactie van mogelijke configuratiedrift wordt afgedraaid. Deze terugdraaiactie helpt de integriteit van de infrastructuur en afstemming met de toepassingscode te behouden. Wijzigingen worden verwijderd bij de volgende implementatie.
Terraform genereert gevoelige waarden voor implementatie tijdens de pijplijnuitvoering of Azure DevOps levert ze als geheimen. Deze waarden worden beveiligd met op rollen gebaseerde toegangsbeperkingen.
Notitie
GitHub-werkstromen bieden een vergelijkbaar concept van afzonderlijke winkels voor geheime waarden. Geheimen worden versleuteld, omgevingsvariabelen die GitHub Actions kunnen gebruiken.
Het is belangrijk om aandacht te besteden aan artefacten die door de pijplijn worden geproduceerd, omdat deze artefacten mogelijk geheime waarden of informatie over de interne werking van de toepassing kunnen bevatten. De Azure DevOps-implementatie van de referentie-implementatie genereert twee bestanden met Terraform-uitvoer. Eén bestand is voor stempels en één bestand is voor de globale infrastructuur. Deze bestanden bevatten geen wachtwoorden die de infrastructuur mogelijk in gevaar kunnen maken. Houd er echter rekening mee dat deze bestanden gevoelig zijn omdat ze informatie over de infrastructuur onthullen, waaronder cluster-id's, IP-adressen, opslagaccountnamen, Key Vault-namen, Azure Cosmos DB-databasenamen en Azure Front Door-header-id's.
Voor workloads die Terraform gebruiken, moet u extra moeite doen om het statusbestand te beveiligen, omdat het volledige implementatiecontext bevat, inclusief geheimen. Het statusbestand wordt doorgaans opgeslagen in een opslagaccount dat een afzonderlijke levenscyclus van de workload moet hebben en alleen toegankelijk moet zijn vanuit een implementatiepijplijn. U moet alle andere toegang tot dit bestand vastleggen en waarschuwingen verzenden naar de juiste beveiligingsgroep.
Updates voor afhankelijkheden
Bibliotheken, frameworks en hulpprogramma's die door de toepassing worden gebruikt, worden in de loop van de tijd bijgewerkt. Het is belangrijk om deze updates regelmatig te voltooien, omdat ze vaak oplossingen bevatten voor beveiligingsproblemen die aanvallers onbevoegde toegang tot het systeem kunnen geven.
De referentie-implementatie maakt gebruik van de Dependabot van GitHub voor updates van afhankelijkheidsupdates voor NuGet, Docker, npm, Terraform en GitHub Actions. Het dependabot.yml
configuratiebestand wordt automatisch gegenereerd met een PowerShell-script vanwege de complexiteit van de verschillende onderdelen van de toepassing. Elke Terraform-module heeft bijvoorbeeld een afzonderlijke vermelding nodig.
#
# /.github/dependabot.yml
#
version: 2
updates:
- package-ecosystem: "nuget"
directory: "/src/app/AlwaysOn.HealthService"
schedule:
interval: "monthly"
target-branch: "component-updates"
- package-ecosystem: "docker"
directory: "/src/app/AlwaysOn.HealthService"
schedule:
interval: "monthly"
target-branch: "component-updates"
# ... the rest of the file...
- Updates worden maandelijks geactiveerd als een compromis tussen het hebben van de meest recente bibliotheken en het onderhouden van de overhead. Daarnaast worden belangrijke hulpprogramma's zoals Terraform continu bewaakt en worden belangrijke updates handmatig uitgevoerd.
- Pull-aanvragen (PULL's) richten zich op de
component-updates
vertakking in plaats vanmain
. - Npm-bibliotheken zijn geconfigureerd om alleen afhankelijkheden te controleren die naar de gecompileerde toepassing gaan in plaats van naar ondersteunende hulpprogramma's zoals
@vue-cli
.
Dependabot maakt een afzonderlijke pull-aanvraag voor elke update, waardoor het operations-team overbelast kan worden. De referentie-implementatie verzamelt eerst een batch met updates in de component-updates
vertakking en voert vervolgens tests uit in de e2e
omgeving. Als deze tests zijn geslaagd, wordt er een andere pull-aanvraag gemaakt die is gericht op de main
vertakking.
Defensieve codering
API-aanroepen kunnen om verschillende redenen mislukken, waaronder codefouten, mislukte implementaties en infrastructuurfouten. Als een API-aanroep mislukt, moet de aanroeper of clienttoepassing geen uitgebreide foutopsporingsinformatie ontvangen, omdat deze informatie kwaadwillende gegevenspunten over de toepassing kan geven.
De referentie-implementatie laat dit principe zien door alleen de correlatie-id in het mislukte antwoord te retourneren. De reden van de fout wordt niet gedeeld, zoals uitzonderingsbericht of stacktracering. Met behulp van deze id en met behulp van header kan een operator het incident onderzoeken met behulp van Server-Location
Application Insights.
//
// Example ASP.NET Core middleware, which adds the Correlation ID to every API response.
//
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.Use(async (context, next) =>
{
context.Response.OnStarting(o =>
{
if (o is HttpContext ctx)
{
context.Response.Headers.Add("Server-Name", Environment.MachineName);
context.Response.Headers.Add("Server-Location", sysConfig.AzureRegion);
context.Response.Headers.Add("Correlation-ID", Activity.Current?.RootId);
context.Response.Headers.Add("Requested-Api-Version", ctx.GetRequestedApiVersion()?.ToString());
}
return Task.CompletedTask;
}, context);
await next();
});
// ...
}
Volgende stap
Implementeer de referentie-implementatie om volledig inzicht te krijgen in resources en hun configuratie.