Intro

Netværk. Kedeligt tænker mange: det skal jo bare køre, og da det er i skyen, jamen så er der en anden der går med bipperen. Vi skal jo blot deploye noget kode. Realiteterne er dog en anden, og det opdager man typisk alt for sent. Selvom man er kommet i skyen, skal man stadig tage stilling til:

  1. Netværkssikkerhed
  2. Routing og styring af trafik
  3. Inddæmning af interne API'er, og
  4. Korrekt exposure af public API'er

Hvordan gør man det i Azure? Det har jeg kigget lidt nærmere på. Det her er ikke ment som en serie af blog indlæg, som kommer som pølser på en snor, men det er noget jeg vil blogge om fra tid til anden, og derfor starter jeg også med et intro forløb, hvor terminologien bliver slået fast, og grundstenene lagt. Jeg vil i dette indlæg zoome ind på VNET, og hvordan man bruger det, og derefter snakke lidt om det store billede.

Lets get started.

VNET vs VNET integration

Det første vi skal have aflaret er at der eksisterer to dele:

  1. VNET
  2. VNET integration

Et VNET er et virtuelt netværk, med subnets, hvor resourcerne man propper i dem får tildelt en IP fra en range af IP'ere. Alt der er i VNET'et kan snakke sammen. Har man fx en VPN gateway i sit VNET, kan de andre resourcer i samme VNET altså gøre brug af VPN forbindelsen, og derved nå onprem resourcer, eller resourcer i et andet VNET som er lokaliseret i en anden del af verden. En resource kunne fx være en VM eller en database. De workloads der kører på disse resourcer vil altså kunne snakke sammen og finde hinanden. Meget smart. Hvad med webapps, kan jeg HØRE dig tænke. Ja: hvad med dem. Kan man smide dem i et VNET? Det korte, og næsten sande svar er: nej. Det lidt længere og diffuse svar er: tjaaaooo måske, men det kommer man på. Det tekniske svar er:

  1. for almindelige webapps kan man ikke
  2. for webapps i en ASE, kan man godt

Men betydet det så at man slet ikke kan gøre brug af et VNET når man har almindelige webapps? Det kan man godt: man kan integrerer en webapp med et VNET. Det er dog ikke det samme som at smide ens webapp i et VNET. Lad mig (låne nogen tegninger) tegne det.

VNET

/images/vnet.png

Et VNET består af:

  1. en eller flere subnet, som
  2. hver har nul eller flere NSG'ere

De resourcer som befinder sig i VNET'et får tildelt en IP hver af den IP pulje som er tildelt subnettet ved oprettelse.

ARM

For at oprette et VNET via en ARM template skal man skrive følgende

{
  "apiVersion": "2020-05-01",
  "type": "Microsoft.Network/virtualNetworks",
  "name": "vnet-test",
  "location": "west europe",
  "properties": {
    "addressSpace": {
      "addressPrefixes": [
        "10.1.0.0/16"
      ]
    },
    "subnets": [
      {
        "name": "WebappSubnet",
        "properties": {
          "addressPrefix": "10.1.2.0/24",
          "serviceEndpoints": [
            {
              "service": "Microsoft.Web"
            }
          ],
          "delegations": [
            {
              "name": "delegation",
              "properties": {
                "serviceName": "Microsoft.Web/serverFarms"
              }
            }
          ]
        }
      }
    ]
  }
}

Mere skal der egentligt ikke til. Læg mærke til at jeg i det subnet jeg har oprettet, har delegeret subnettet til serverfarms. På den måde fortæller jeg subnettet at den skal kunne håndtere trafik fra webapps. Bag om ryggen på os installeres der således en NSG som sørger for at styre HTTP trafik korrekt. Meget smart. Vi skal bruge den lige om lidt når vi skal integrere en webapp ind i vores VNET: der blev sagt INTEGRERES!! Djævlen er i detaljen.

bonus info: det er faktisk delegationen der teknisk set er integrationsdelen i VNET /integration/, da det er den som sørger for at bestemte typer af trafik kan integrerer ind i VNET'et. SPÆNDENDE!!

VNET integration

/images/vnetintegration.png

Her skal man bide mærke i:

  1. Ens webapps ligger udenfor det definerede VNET. De webapps man har integrerer sig ind i VNET'et via et dedikeret subnet (som er provisioneret med henblik på at styre trafik fra webapps hvilket betyder at der er opsat nogle NSG'ere som hjælper med at styre trafikken)
  2. Bemærk at trafikken fra internettet rammer de integrerede webapps før de rammer vores VNET hvilket betyder at man ikke kan styre indadgående trafik med NSG'ere, men kun trafik som forlader vores VNET. Det er en meget vigtig pointe: man kan IKKE lukke af for indadgående trafik. Vil man lukke for indadgående trafik kan man heldigvis bruge access restrictions på de webapps man gerne vil skærme af. Husk dog: webapp'en har stadig en offentlig IP, men man har blot fortalt den LB'er der ligger foran webapp'en at den kun må modtage trafik som er hevet gennem VNET'et
  3. Er ens webapp først integreret kan man tilgå alle resourcer på tværs af subnets: det betyder at man kan gøre brug af de VPN'ere der er sat op, eller de databaser som kun er tilgængelig i det pågældende VNET

ARM

For at få en webapp til at integrere op mod et VNET skal man fortælle webapp'en hvad for VNET resource id den skal tilknyttes

{
  "apiVersion": "2020-06-01",
  "name": "webappname",
  "type": "Microsoft.Web/sites",
  "location": "west europe",
  "properties": {
    "name": "webappname",
    "siteConfig": {
      "appSettings": [
          ],
      "ipSecurityRestrictions": [
        {
          "name": "webappSubnetAllowRule",
          "priority": "1",
          "action": "Allow",
          "vnetSubnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'virtual network name', 'WebappSubnet')]"
        }
      ],
    },
    "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'hosting plan name']"
  },
  "resources": [
    {
      "name": "virtualNetwork",
      "type": "networkConfig",
      "apiVersion": "2019-08-01",
      "dependsOn": [
        "[parameters('webappName')]"
      ],
      "properties": {
        "subnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'virtual network name', 'WebappSubnet')]",
        "swiftSupported": true
      }
    }
  ]
}

Jeg har tilladt mig at lade en ipSecurityRestrictions blive, så I også kan se hvordan sådan en ser ud. Der er nogle vigtige deltajer her:

  1. HUSK swiftSupported: true ellers vil integrationen ikke virke. Jeg har endnu ikke fundet ud af hvorfor
  2. HUSK for guds skyld at smide security restrictions på SCM sitet, hvis det i sandheden skal være sikkert (dog skal man også huske på at det giver uforudsete problemer med deploys). Mange tror at hele sitet er lukket af bare man smider det på produktions slottet, men det er det ikke, da SCM sitet stadig kan tilgåes
  3. HUSK: har man flere slots tilknytttet, så skal man også integrere disse

Man har nu fået:

  1. et VNET, og
  2. en webapp som integrerer med den

Man kan nu begynde at bruge fx ip restrictions og afskærme ens indkommende trafik til webapp'en, og skærme den af for omverdenen, eller tilgå VPN forbindelsen, som måske ligger i VNET'et. Wild world indeed!!

De sidste bemærkninger

Det er svært at ramme rigtigt, og det kræver meget planlægning, specielt hvis man gerne vil gøre det ordentligt, og jeg vil sige at hvis man gerne vil lave det helt rigtigt, så kræver det:

  1. et ASE miljø
  2. en dedikeret VM med en DevOps agent, som man kan deploye til

Det overstående giver to udfordringer:

  1. Man har en VM, som skal holdes ved lige, og det kræver meget konfiguration. Azure har utrolig mange lag beskyttelse for VMs, dog er det alle nogen man selv skal aktivere. Jeg vil tro jeg kunne skrive en hel serie bare omkring sikkerhed om VMs, men det må blive en anden gang
  2. Pris: Når man hiver ASE ind i stakken, så stiger prisen også, man får dig et dedikeret VNET, som man kan bruge som ens webapp ligger i, og man er derfor foruden at skulle lave ipRestrictionsSCM sites, slots osv

At lave ordentlig sikkerhed i Azure er altså i bund og grund ikke mere anderledes end sikkerhed onprem: det er dyrt at gøre ordentligt. Man har dog flere stykker værktøj til rådighed i Azure (og for den sags skyld i de andre cloud tjenester).

Jeg har nu dækket to dele af netværket i Azure (faktisk kun en, VNET), men der er mange flere knapper og dimser man kan hive for at

  1. få mere fart på (vil du ikke gerne have at alt dit trafik smutter på Azure backbone fx?)
  2. mere sikkerhed (vil du ikke gerne have at alt dit trafik ikke bliver routed ud på det store Internet?)

Enhver med respekt for sig selv vil svare jo til overstående, men igen: det kommer med en pris: 1) penge 2) der er sindssygt meget man skal have styr på. Disse dimser og knapper ligner derfor også meget onprem verdenen. Azure giver dig kassen, og et færdigbygget skelet, som nemt kan servere data på Internettet (de får noget egress og ingress, og tjener penge, og du får kassen som du kan vælge fra), og det er nu din opgave at gøre det sikkert, og stabilt. Du skal læse lige så meget op på lektien som man skulle i vores gode, gamle, kære onprem verden.

Jeg vil i de efterfølgende afsnit opridse nogle af de andre dimser, som man kan hive ind. Disse dimer og dingenoter er nogen jeg vil blogge om senere: for nu, vil jeg blot nævne dem (så kan du jo selv gå igang). Meget af koden (undtagen ASE og VM) er at finde i linket til sidst i artiklen, så kan du jo selv tage et kig. Husk: KeyVault er noget jeg selv personlig spinner op med nogle scripts, indtil access permissions bliver behandlet ordentligt når man opretter en KeyVault via en ARM template. Mere om det i et andet indlæg.

Ready? Detroit, New York, du er (Mandril joke - se det).

Private link

/images/azure-privatelink.png

Et private link er et sæt af resourcer som man kan bruge til at binde en Azure resource, fx en Azure SQL database, eller en storage account, og et VNET sammen med. Man opnår derved at at databasen eller det storage man har, får en privat IP fra VNET puljen, i stedet for at den URI en database eller en storage account har, bliver resolved til en offentlig IP.

Teknisk set sker der det at:

  1. der oprettes en NIC som placeres i VNET'et og binder sig til fx databasen eller storage account'en i den anden ende
  2. Der oprettes en private DNS zone som sørger for at resolve den interne IP når den givne URI skal slåes op, i stedet for den offentlige IP.

Man opnår derved at alt trafikken travasere over Azures backbone, og aldrig kommer ud på Internettet. En bonus her er at man også undgår SNAT exhaustion (https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-outbound-connections#exhausting-ports), noget du sikkert har oplevet uden du ved det, da man undgår at gå gennem "den store LB'er", som fronter hele Azure (der jo kun en, og du ved det jo godt - computeren ovre i hjørnet som har påklistret production :)).

Service endpoint

/images/azure-serviceendpoint.png

Det er nu det bliver lidt krads, fordi en Service Endpoint er næsten det samme som et private link, næsten. Når man opretter en service endpoint i et VNET, sørger man for at resourcerne som kører ind i dette subnet:

  1. får en privat IP tildelt, og
  2. trafikken bliver tagget, og derved identificerbar, hvilket gør at man kan bygge firewall regler op på baggrund af denne information (bla med de føromtalte ip restrictions på en webapp)

Man bruger derfor service endpoints til at sørge for at trafikken ikke går ud på Internettet, og at man kan identificere trafikken efterfølgende. Det er blandt andet sådan man laver ip restrictions: man fortæller at man kun tillader trafik fra specifikke subnets. Disse subnets skal have en service endpoint enabled. Som man kan se på tegningen betyder det at man, på de resourcer som har en firewall til rådighed (fx en webapp, en storage account eller en SQL server), kan sige: denne og denne trafik må gerne gå igennem til mig, mens alt andet trafik ikke må.

Det lyder unægtelig meget som private links, dog er der den forskel at man

  1. skal have et subnet til hver gruppe af resourcer
  2. man kan ikke bruge private peering fra onprem og op på den private ip som bliver tildelt

der er nok andre forskellige også, men disse to er de væsentlige. Med private links kan man forbinde onprem med skyen, og man sørger faktisk for at man med private links giver den givne resource en ny privat ip fra ens VNET pulje: med service endpoints er det lidt mere skjult, og resourcen har stadig en public ip.

Rent sikkerhedsmæssig bør man vælge private links hvor end man kan, dog er service endpoints gode til at skærme trafik. private links er stadig så ny en fætter i Azure, at man nogen gange bliver nød både at have service endpoints, og private links, for at få det hele til at spille (bla hvis man skal lukke en storage account ordentligt af).

Rent faktisk har jeg et helt indlæg omkring service endpoint vs private links, som kan læses her: https://bl0g.dev/post/arm/service-endpoints-vs-private-links/.

ASE (og alt det andet: VM, DevOps og KeyVault)

/images/azure-ase-internal.png /images/azure-ase-external.png

Den dyre elefant, som giver hele paletten. Her bevæger vi os væk fra delegation og VNET integration og får fuld power på. Der er to typer:

  1. en intern og
  2. en ekstern

Detaljerne vil jeg gemme til en anden dag, men i bund og grund handler det om, om man vil have en offentlig IP eller ej. Med en ASE får man flere ting:

  1. dedikeret jern
  2. mere af alt
  3. og et RIGTIGT VNET til ens resourcer (det vil sige: de webapps man har ligger rent faktisk indeni VNET)

da resourcerne nu ligger inde i selve VNET'et kan man nu bruge NSG'ere til at styre både indgående og udgående trafik. Ens webapps har også fået en intern IP. Skal man lave det helt rigtige setup, med en KeyVault og DevOps er min klare anbefaling at man køre med en ASE som har deployet en VM med en DevOps byggeagent i sig, så man kan skærme sine webapps helt af (OGSÅ SCM sitet). Når man har en dedikeret byggeagent, får den en IP og med denne IP kan man nu bruge KeyVault fuldt ud, og lukke den helt ned.

Teknisk set har man mulighed for at lukke godt af for KeyVault'en, og kun tillade trusted services adgang til valuten. Vil man linke Azure DevOps og KeyVault sammen er det mildest talt umuligt, hvis man kun kører med hosted byggeagenter, da Azure DevOps ikke er en trusted service set med KeyVaults øjne, og det er den ikke af den simple grund, at Microsoft ikke kan styre alt koden som er hosted i en DevOps subscription (du kan jo selv smide scripts osv ind i dine pipelines). Derfor: få en dedikeret byggeagent og drag fuld udnytte af det ekstra sikkerhed det giver dig.

Nogen andet smart er også: har man en dedikeret byggeagent på en VM, kan man smide VM'en ind i et scaleset, og skalere ud når man laver mange deploys. Det er smart, i stedet for at betale for 10 byggeagtenter 24/7, så er det mere on demand. Det betyder dog også at man bliver nød til at vedligeholde byggeagtenten manuelt, og vedligeholde VM'en, men det er nu en gang prisen man må betale, for at få mere sikkerhed (har du 10 byggeagtenter bør du dog kigge ind i VM og scaleset, da det faktisk godt kan gå hen og være billigere i længden).

Closing up

Alt koden, som jeg blogger om i dette indlæg og i de fremtidige kan findes her: https://gitlab.com/mslot/cloud.network.security.

Det er vigtigt at man tager stilling til alle disse ting. Tager man hele paletten får man

  • styring af trafik internt i Azure
  • adgangsgivning baseret på trafik tagging
  • afskærming af kritisk infrastruktur
  • horisontal netværkssegmentering
  • vertikal netværkssegmentering

Hvem vil ikke gerne have det?