Cvičení – přidání testovací fáze do kanálu

Dokončeno

Bezpečnostní tým vaší společnosti toy vás požádal, abyste ověřili, že váš web je přístupný jenom přes HTTPS. V tomto cvičení nakonfigurujete kanál tak, aby spustil orientační test, který kontroluje požadavek bezpečnostního týmu.

Během tohoto procesu:

  • Přidejte do úložiště testovací skript.
  • Aktualizujte definici kanálu a přidejte testovací fázi.
  • Spusťte kanál a sledujte selhání testu.
  • Opravte soubor Bicep a sledujte úspěšné spuštění kanálu.

Přidání testovacího skriptu

V této části přidáte testovací skript, který ověří, jestli je web přístupný, když se použije protokol HTTPS a není přístupný při použití nezabezpečeného protokolu HTTP.

  1. V editoru Visual Studio Code vytvořte nový soubor ve složce deploy s názvem Website.Tests.ps1.

    Snímek obrazovky Průzkumníka editoru Visual Studio Code se zobrazenou složkou deploy a testovacím souborem

  2. Do souboru vložte následující testovací kód:

    param(
      [Parameter(Mandatory)]
      [ValidateNotNullOrEmpty()]
      [string] $HostName
    )
    
    Describe 'Toy Website' {
    
        It 'Serves pages over HTTPS' {
          $request = [System.Net.WebRequest]::Create("https://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode |
            Should -Be 200 -Because "the website requires HTTPS"
        }
    
        It 'Does not serves pages over HTTP' {
          $request = [System.Net.WebRequest]::Create("http://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode | 
            Should -BeGreaterOrEqual 300 -Because "HTTP is not secure"
        }
    
    }
    

    Tento kód je testovací soubor Pester. Vyžaduje parametr s názvem $HostName. Spustí dva testy s názvem hostitele:

    • Zkuste se připojit k webu přes HTTPS. Test projde, pokud server odpoví stavovým kódem odpovědi HTTP mezi 200 a 299, což označuje úspěšné připojení.
    • Zkuste se připojit k webu přes HTTP. Test projde, pokud server odpoví stavovým kódem odpovědi HTTP 300 nebo vyšší.

    Pro účely tohoto cvičení není důležité pochopit podrobnosti testovacího souboru a jeho fungování. V souhrnu vám poskytneme odkazy, abyste se mohli dozvědět víc, pokud vás zajímají.

Publikování výstupu souboru Bicep jako výstupní proměnné fáze

Testovací skript, který jste vytvořili v předchozích krocích, vyžaduje k otestování název hostitele. Soubor Bicep už obsahuje výstup, ale než ho budete moct použít v orientačních testech, musíte ho publikovat jako výstupní proměnnou fáze.

  1. V editoru Visual Studio Code otevřete soubor azure-pipelines.yml ve složce deploy .

  2. Ve fázi Nasazení aktualizujte krok nasazení, aby se výstupy publikovaly do proměnné:

    - task: AzureResourceManagerTemplateDeployment@3
      name: DeployBicepFile
      displayName: Deploy Bicep file
      inputs:
        connectedServiceName: $(ServiceConnectionName)
        deploymentName: $(Build.BuildNumber)
        location: $(deploymentDefaultLocation)
        resourceGroupName: $(ResourceGroupName)
        csmFile: deploy/main.bicep
        overrideParameters: >
          -environmentType $(EnvironmentType)
        deploymentOutputs: deploymentOutputs
    

    Teď váš proces nasazení stále používá stejnou úlohu jako předtím, ale výstupy z nasazení jsou uloženy v proměnné kanálu s názvem deploymentOutputs. Výstupní proměnná je formátovaná jako JSON.

  3. Pokud chcete převést výstupy ve formátu JSON na proměnné kanálu, přidejte následující krok skriptu pod krok nasazení:

    - bash: |
        echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')"
      name: SaveDeploymentOutputs
      displayName: Save deployment outputs into variables
      env:
        DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
    

    Pokud se nasazení úspěšně dokončí, skript přistupuje k hodnotě každého výstupu z nasazení Bicep. Skript používá jq nástroj pro přístup k příslušné části výstupu JSON. Pak se hodnota publikuje do výstupní proměnné fáze se stejným názvem jako výstup nasazení Bicep.

    Poznámka:

    Pester i jq jsou předinstalované na agentech hostovaných Microsoftem pro Azure Pipelines. Nemusíte dělat nic zvláštního, abyste je mohli použít v kroku skriptu.

  4. Uložte soubor.

Přidání fáze orientačního testu do kanálu

Teď můžete přidat fázi orientačního testu, která spouští testy.

  1. V dolní části souboru přidejte následující definici pro fázi SmokeTest :

    - stage: SmokeTest
      jobs:
      - job: SmokeTest
        displayName: Smoke test
        variables:
          appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ]
    

    Tento kód definuje fázi a úlohu. Vytvoří také proměnnou v úloze s názvem appServiceAppHostName. Tato proměnná přebírá hodnotu z výstupní proměnné, kterou jste vytvořili v předchozí části.

  2. V dolní části souboru přidejte následující definici kroku do fáze SmokeTest :

    steps:
      - task: PowerShell@2
        name: RunSmokeTests
        displayName: Run smoke tests
        inputs:
          targetType: inline
          script: |
            $container = New-PesterContainer `
              -Path 'deploy/Website.Tests.ps1' `
              -Data @{ HostName = '$(appServiceAppHostName)' }
            Invoke-Pester `
              -Container $container `
              -CI
    

    Tento krok spustí skript PowerShellu pro spuštění testovacího skriptu, který jste napsali dříve pomocí testovacího nástroje Pester.

  3. V dolní části souboru přidejte následující definici kroku do fáze SmokeTest :

    - task: PublishTestResults@2
      name: PublishTestResults
      displayName: Publish test results
      condition: always()
      inputs:
        testResultsFormat: NUnit
        testResultsFiles: 'testResults.xml'
    

    Tento krok provede soubor výsledků testů, který Nástroj Pester vytvoří a publikuje jako výsledky testu kanálu. Brzy uvidíte, jak se výsledky zobrazí.

    Všimněte si, že definice kroku zahrnuje condition: always(). Tato podmínka značí službě Azure Pipelines, že by měla vždy publikovat výsledky testu, i když předchozí krok selže. Tato podmínka je důležitá, protože jakýkoli neúspěšný test způsobí selhání testovacího kroku a kanál se po neúspěšném kroku normálně zastaví.

  4. Uložte soubor.

Ověření a potvrzení definice kanálu

  1. Ověřte, že váš soubor azure-pipelines.yml vypadá jako následující kód:

    trigger:
      batch: true
      branches:
        include:
        - main
    
    pool:
      vmImage: ubuntu-latest
    
    variables:
      - name: deploymentDefaultLocation
        value: westus3
    
    stages:
    
    - stage: Lint
      jobs:
      - job: LintCode
        displayName: Lint code
        steps:
          - script: |
              az bicep build --file deploy/main.bicep
            name: LintBicepCode
            displayName: Run Bicep linter
    
    - stage: Validate
      jobs:
      - job: ValidateBicepCode
        displayName: Validate Bicep code
        steps:
          - task: AzureResourceManagerTemplateDeployment@3
            name: RunPreflightValidation
            displayName: Run preflight validation
            inputs:
              connectedServiceName: $(ServiceConnectionName)
              location: $(deploymentDefaultLocation)
              deploymentMode: Validation
              resourceGroupName: $(ResourceGroupName)
              csmFile: deploy/main.bicep
              overrideParameters: >
                -environmentType $(EnvironmentType)
    
    - stage: Preview
      jobs:
      - job: PreviewAzureChanges
        displayName: Preview Azure changes
        steps:
          - task: AzureCLI@2
            name: RunWhatIf
            displayName: Run what-if
            inputs:
              azureSubscription: $(ServiceConnectionName)
              scriptType: 'bash'
              scriptLocation: 'inlineScript'
              inlineScript: |
                az deployment group what-if \
                  --resource-group $(ResourceGroupName) \
                  --template-file deploy/main.bicep \
                  --parameters environmentType=$(EnvironmentType)
    
    - stage: Deploy
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        environment: Website
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: $(ServiceConnectionName)
                    deploymentName: $(Build.BuildNumber)
                    location: $(deploymentDefaultLocation)
                    resourceGroupName: $(ResourceGroupName)
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType $(EnvironmentType)
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')"
                  name: SaveDeploymentOutputs
                  displayName: Save deployment outputs into variables
                  env:
                    DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
    
    - stage: SmokeTest
      jobs:
      - job: SmokeTest
        displayName: Smoke test
        variables:
          appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ]
        steps:
          - task: PowerShell@2
            name: RunSmokeTests
            displayName: Run smoke tests
            inputs:
              targetType: inline
              script: |
                $container = New-PesterContainer `
                  -Path 'deploy/Website.Tests.ps1' `
                  -Data @{ HostName = '$(appServiceAppHostName)' }
                Invoke-Pester `
                  -Container $container `
                  -CI
    
          - task: PublishTestResults@2
            name: PublishTestResults
            displayName: Publish test results
            condition: always()
            inputs:
              testResultsFormat: NUnit
              testResultsFiles: 'testResults.xml'
    

    Pokud tomu tak není, aktualizujte ho tak, aby odpovídal tomuto příkladu, a pak ho uložte.

  2. Potvrďte a nasdílejte změny do úložiště Git spuštěním následujících příkazů v terminálu editoru Visual Studio Code:

    git add .
    git commit -m "Add test stage"
    git push
    

Spusťte kanál a zkontrolujte výsledek testu.

  1. V prohlížeči přejděte do kanálu.

  2. Vyberte poslední spuštění kanálu.

    Počkejte, až kanál dokončí fáze Lint, Validate a Preview . I když Azure Pipelines stránku automaticky aktualizuje nejnovějším stavem, je vhodné stránku občas aktualizovat.

  3. Vyberte tlačítko Revize a pak vyberte Schválit.

    Počkejte na dokončení spuštění kanálu.

  4. Všimněte si, že fáze nasazení se úspěšně dokončí. Fáze SmokeTest se dokončí chybou.

    Snímek obrazovky s rozhraním Azure DevOps, které zobrazuje fáze spuštění kanálu Fáze SmokeTest hlásí selhání.

  5. Vyberte kartu Testy.

    Snímek obrazovky s rozhraním Azure DevOps, které zobrazuje spuštění kanálu se zvýrazněnou kartou Testy

  6. Všimněte si, že souhrn testu ukazuje, že se spustily dva testy. Jedna byla úspěšná a jedna selhala. Test, který selhal, je uvedený jako Web Toy.Neslouží stránky přes protokol HTTP.

    Snímek obrazovky s rozhraním Azure DevOps, které zobrazuje výsledky testu spuštění kanálu se zvýrazněným neúspěšným testem

    Tento text označuje, že web nebyl správně nakonfigurovaný tak, aby splňoval požadavek vašeho bezpečnostního týmu.

Aktualizace souboru Bicep

Teď, když jste zjistili, že vaše definice Bicep nesplňuje požadavek vašeho bezpečnostního týmu, opravíte ji.

  1. V editoru Visual Studio Code otevřete soubor main.bicep ve složce deploy .

  2. Vyhledejte definici aplikace Aplikace Azure Service a aktualizujte ji tak, aby zahrnovala httpsOnly vlastnost v její properties oblasti:

    resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
      name: appServiceAppName
      location: location
      properties: {
        serverFarmId: appServicePlan.id
        httpsOnly: true
        siteConfig: {
          appSettings: [
            {
              name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
              value: applicationInsights.properties.InstrumentationKey
            }
            {
              name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
              value: applicationInsights.properties.ConnectionString
            }
          ]
        }
      }
    }
    
  3. Uložte soubor.

  4. Potvrďte a nasdílejte změny do úložiště Git spuštěním následujících příkazů v terminálu editoru Visual Studio Code:

    git add .
    git commit -m "Configure HTTPS on website"
    git push
    

Znovu spusťte kanál.

  1. V prohlížeči přejděte do kanálu.

  2. Vyberte poslední spuštění.

    Počkejte, až kanál dokončí fáze Lint, Validate a Preview . I když Azure Pipelines stránku automaticky aktualizuje nejnovějším stavem, je vhodné stránku občas aktualizovat.

  3. Vyberte fázi náhledu a znovu zkontrolujte výsledky citlivostní kontroly.

    Všimněte si, že příkaz what-if zjistil změnu v httpsOnly hodnotě vlastnosti:

    Resource and property changes are indicated with these symbols:
      + Create
      ~ Modify
      = Nochange
    
    The deployment will update the following scope:
    
    Scope: /subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/resourceGroups/ToyWebsiteTest
    
      ~ Microsoft.Web/sites/toy-website-nbfnedv766snk [2021-01-15]
        + properties.siteConfig.localMySqlEnabled:   false
        + properties.siteConfig.netFrameworkVersion: "v4.6"
        ~ properties.httpsOnly:                      false => true
    
      = Microsoft.Insights/components/toywebsite [2020-02-02]
      = Microsoft.Storage/storageAccounts/mystoragenbfnedv766snk [2021-04-01]
      = Microsoft.Web/serverfarms/toy-website [2021-01-15]
    
    Resource changes: 1 to modify, 3 no change.
    
  4. Vraťte se ke spuštění kanálu.

  5. Vyberte tlačítko Revize a pak vyberte Schválit.

    Počkejte na dokončení spuštění kanálu.

  6. Všimněte si, že celý kanál se úspěšně dokončí, včetně fáze SmokeTest . Tento úspěch značí, že oba testy prošly.

    Snímek obrazovky s rozhraním Azure DevOps, které ukazuje úspěšné spuštění kanálu

Vyčištění prostředků

Teď, když jste cvičení dokončili, můžete odebrat prostředky, abyste za ně neúčtoli.

V terminálu editoru Visual Studio Code spusťte následující příkaz:

az group delete --resource-group ToyWebsiteTest --yes --no-wait

Skupina prostředků se odstraní na pozadí.

Remove-AzResourceGroup -Name ToyWebsiteTest -Force