diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index bd4c6a4..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: CI - Deploy App and Bicep - -on: - push: - branches: [main] - workflow_dispatch: - -permissions: - id-token: write - pull-requests: write - contents: read - -jobs: - build_and_test: - runs-on: ubuntu-latest - name: Build, Test, Upload Artifact - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup dotnet - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x - - - name: Run dotnet test - run: | - dotnet test -c Release - - - name: Run dotnet publish - run: | - dotnet publish ./src/WorkshopDemo/WorkshopDemo.csproj -c Release -o ./publish - - - name: Update version file with GHA run number and git short SHA - run: echo $(date +'%Y%m%d.%H%M').${{github.run_number}}-$(git rev-parse --short HEAD) > publish/version.txt - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: dotnet-artifact - path: publish/ - - dev: - needs: build_and_test - uses: ./.github/workflows/step-deploy.yml - with: - env: dev - artifact_name: dotnet-artifact - resource_group_name: rg-workshop-dnazghbicep-scottsauber-dev - app_service_name: app-workshop-dnazghbicep-scottsauber-dev - app_service_slot_name: slot - # Note: use GH Environment Secrets if using a Pro/Enterprise version of GH - secrets: - azure_client_id: ${{ secrets.DEV_AZURE_CLIENT_ID }} - azure_subscription_id: ${{ secrets.DEV_AZURE_SUBSCRIPTION_ID }} - azure_tenant_id: ${{ secrets.DEV_AZURE_TENANT_ID }} - - prod: - needs: dev - uses: ./.github/workflows/step-deploy.yml - with: - env: prod - artifact_name: dotnet-artifact - resource_group_name: rg-workshop-dnazghbicep-scottsauber-prod - app_service_name: app-workshop-dnazghbicep-scottsauber-prod - app_service_slot_name: slot - # Note: use GH Environment Secrets if using a Pro/Enterprise version of GH - secrets: - azure_client_id: ${{ secrets.PROD_AZURE_CLIENT_ID }} - azure_subscription_id: ${{ secrets.PROD_AZURE_SUBSCRIPTION_ID }} - azure_tenant_id: ${{ secrets.PROD_AZURE_TENANT_ID }} diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml new file mode 100644 index 0000000..1003260 --- /dev/null +++ b/.github/workflows/dotnet-build.yml @@ -0,0 +1,27 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +jobs: + build: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal diff --git a/.github/workflows/step-deploy.yml b/.github/workflows/step-deploy.yml deleted file mode 100644 index 66afbeb..0000000 --- a/.github/workflows/step-deploy.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: "Step - Deploy" - -on: - workflow_call: - inputs: - env: - required: true - type: string - artifact_name: - required: true - type: string - resource_group_name: - required: true - type: string - app_service_name: - required: true - type: string - app_service_slot_name: - required: true - type: string - secrets: - azure_client_id: - required: true - description: "Client ID for Azure Service Principal" - azure_subscription_id: - required: true - description: "Azure Subscription ID for the targeted Resource Group" - azure_tenant_id: - required: true - description: "Azure Tenant ID for the targeted Resource Group" - -jobs: - deploy: - name: Deploy to Azure - runs-on: ubuntu-latest - - concurrency: - group: deploy-to-azure - cancel-in-progress: false - - steps: - - uses: actions/checkout@v4 - - - name: Log in to Azure - uses: azure/login@v2 - with: - client-id: ${{ secrets.azure_client_id }} - tenant-id: ${{ secrets.azure_tenant_id }} - subscription-id: ${{ secrets.azure_subscription_id }} - - - name: Run Bicep - run: | - az deployment group create \ - --name ${{ inputs.env }}-deployment-${{ github.run_number }} \ - --template-file infrastructure/main.bicep \ - --parameters infrastructure/environments/${{ inputs.env }}.bicepparam \ - --resource-group ${{ inputs.resource_group_name }} \ - --verbose - - - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.artifact_name }} - path: publish - - - name: Get publish profile - id: publishprofile - run: | - profile=$(az webapp deployment list-publishing-profiles --resource-group ${{ inputs.resource_group_name }} --name ${{ inputs.app_service_name }} --slot ${{ inputs.app_service_slot_name }} --xml) - echo "PUBLISH_PROFILE=$profile" >> $GITHUB_OUTPUT - - - name: Deploy to Slot - uses: azure/webapps-deploy@v2 - with: - app-name: ${{ inputs.app_service_name }} - slot-name: ${{ inputs.app_service_slot_name }} - publish-profile: ${{ steps.publishprofile.outputs.PUBLISH_PROFILE }} - package: publish/ - - - name: Swap slots - run: | - az webapp deployment slot swap -g ${{ inputs.resource_group_name }} -n ${{ inputs.app_service_name }} --slot ${{ inputs.app_service_slot_name }} --target-slot production --verbose diff --git a/infrastructure/appservice.bicep b/infrastructure/appservice.bicep index fe957e7..c8be9e4 100644 --- a/infrastructure/appservice.bicep +++ b/infrastructure/appservice.bicep @@ -1,30 +1,30 @@ param location string +param appName string @allowed(['dev', 'prod']) param environment string -param appName string var appServiceProperties = { - serverFarmId: appServicePlan.id - httpsOnly: true - siteConfig: { - http20Enabled: true - linuxFxVersion: 'DOTNETCORE|9.0' - alwaysOn: true - ftpsState: 'Disabled' - minTlsVersion: '1.2' - webSocketsEnabled: true - healthCheckPath: '/api/healthz' - requestTracingEnabled: true - detailedErrorLoggingEnabled: true - httpLoggingEnabled: true - } + serverFarmId: appServicePlan.id + httpsOnly: true + siteConfig: { + http20Enabled: true + linuxFxVersion: 'DOTNETCORE|9.0' + alwaysOn: true + ftpsState: 'Disabled' + minTlsVersion: '1.2' + webSocketsEnabled: true + healthCheckPath: '/api/healthz' + requestTracingEnabled: true + detailedErrorLoggingEnabled: true + httpLoggingEnabled: true + } } resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = { name: 'asp-${appName}' location: location sku: { - name: 'P0V3' + name: 'S1' } kind: 'linux' properties: { @@ -36,7 +36,7 @@ resource appService 'Microsoft.Web/sites@2022-09-01' = { name: 'app-${appName}' location: location identity: { - type: 'SystemAssigned' + type: 'SystemAssigned' } properties: appServiceProperties } @@ -51,13 +51,13 @@ resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = { } resource appServiceSlot 'Microsoft.Web/sites/slots@2022-09-01' = { - location: location - parent: appService - name: 'slot' - identity: { - type: 'SystemAssigned' - } - properties: appServiceProperties + location: location + parent: appService + name: 'slot' + identity: { + type: 'SystemAssigned' + } + properties: appServiceProperties } resource appServiceSlotSetting 'Microsoft.Web/sites/slots/config@2022-09-01' = { @@ -68,8 +68,3 @@ resource appServiceSlotSetting 'Microsoft.Web/sites/slots/config@2022-09-01' = { ASPNETCORE_ENVIRONMENT: environment } } - -output appServiceInfo object = { - appId: appService.identity.principalId - slotId: appServiceSlot.identity.principalId -} diff --git a/infrastructure/environments/prod.bicepparam b/infrastructure/environments/prod.bicepparam index c17d088..f624e05 100644 --- a/infrastructure/environments/prod.bicepparam +++ b/infrastructure/environments/prod.bicepparam @@ -1,3 +1,3 @@ using '../main.bicep' -param environment = 'prod' +param environment = 'prod' diff --git a/infrastructure/keyvault.bicep b/infrastructure/keyvault.bicep deleted file mode 100644 index b809f42..0000000 --- a/infrastructure/keyvault.bicep +++ /dev/null @@ -1,109 +0,0 @@ -param appId string -param slotId string -param location string -param appName string - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { - name: 'kv-${appName}' - location: location - properties: { - tenantId: subscription().tenantId - sku: { - family: 'A' - name: 'standard' - } - accessPolicies: [ - // AppService - { - tenantId: subscription().tenantId - objectId: appId - permissions: { - keys: [ - 'get' - 'list' - 'unwrapKey' - 'wrapKey' - ] - secrets: [ - 'get' - 'list' - ] - certificates: [] - } - } - // AppService Slot - { - tenantId: subscription().tenantId - objectId: slotId - permissions: { - keys: [ - 'get' - 'list' - 'unwrapKey' - 'wrapKey' - ] - secrets: [ - 'get' - 'list' - ] - certificates: [] - } - } - // Myself - normally you wouldn't put a user here, you'd use a Group all the developers are in - { - tenantId: subscription().tenantId - objectId: '25c16810-3e79-460d-89dd-7e22ac610aca' - permissions: { - keys: [ - 'get' - 'list' - 'update' - 'create' - 'import' - 'delete' - 'recover' - 'backup' - 'restore' - 'decrypt' - 'encrypt' - 'unwrapKey' - 'wrapKey' - 'verify' - 'sign' - 'purge' - ] - secrets: [ - 'get' - 'list' - 'set' - 'delete' - 'recover' - 'backup' - 'restore' - 'purge' - ] - certificates: [ - 'get' - 'list' - 'update' - 'create' - 'import' - 'delete' - 'recover' - 'backup' - 'restore' - 'manageContacts' - 'manageIssuers' - 'getIssuers' - 'listIssuers' - 'setIssuers' - 'deleteIssuers' - 'purge' - ] - } - } - ] - } -} - -output keyVaultName string = keyVault.name diff --git a/infrastructure/main.bicep b/infrastructure/main.bicep index c90210e..c40cbd7 100644 --- a/infrastructure/main.bicep +++ b/infrastructure/main.bicep @@ -1,36 +1,13 @@ @allowed(['dev', 'prod']) param environment string -var location = 'centralus' -var myName = 'scottsauber' -var appNameWithEnvironment = 'workshop-dnazghbicep-${myName}-${environment}' - targetScope = 'resourceGroup' -module appService './appservice.bicep' = { - name: 'appservice' +module appService 'appservice.bicep' = { + name: 'appService' params: { - appName: appNameWithEnvironment + appName: 'workshop-dnazghbicep-scottsauber-${environment}' + location: 'centralus' environment: environment - location: location - } -} - -module keyvault './keyvault.bicep' = { - name: 'keyvault' - params: { - appId: appService.outputs.appServiceInfo.appId - slotId: appService.outputs.appServiceInfo.slotId - location: location - appName: '${myName}-${environment}' // key vault has 24 char max so just doing your name, usually would do appname-env but that'll conflict for everyone - } -} - -module monitor './monitor.bicep' = { - name: 'monitor' - params: { - appName: appNameWithEnvironment - keyVaultName: keyvault.outputs.keyVaultName - location: location } } diff --git a/infrastructure/monitor.bicep b/infrastructure/monitor.bicep deleted file mode 100644 index 0773a71..0000000 --- a/infrastructure/monitor.bicep +++ /dev/null @@ -1,30 +0,0 @@ -param location string -param appName string -param keyVaultName string - -resource logWs 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { - name: 'law-${appName}' - location: location -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { - name: 'ai-${appName}' - location: location - kind: 'web' - properties: { - Application_Type: 'web' - WorkspaceResourceId: logWs.id - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} - -resource aiSecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - name: 'ConnectionStrings--ApplicationInsights' - parent: keyVault - properties: { - value: applicationInsights.properties.ConnectionString - } -}