Skip to content

Azure

orientation

  • information on service: Look into the FAQ
  • general health of service: Service Health
  • availability of service
  • automatic analysis of resources: advisor recommendations
  • create graphic: Resource Visualizer (part of Resource Group)
  • IaC:
  • Azure Resource Manager templates (ARM templates)
  • can be used to be copie to pulumi azure native provider
  • UI Azure Portal: in most resources under 'Export template'
  • CLI az:
    • az <service> list <resourcename>
    • az <service> show <resourcename>
    • sometimes as yaml: az <service> export <resourcename>
  • audit and see erros in deployment: Monitor | Activity log
  • AWS to Azure services comparison

terms

  • directory: company
  • tenant id belongs to directory
  • subscription: part of a directory
  • account: me and belongs to one or more directory and has access to one or more subscriptions
  • Object Id = principal id
  • Object Id != client id
  • application ≈ managed identity ≈ service principal
az login
az account list
e --subscription=<id>

scopes

RBAC and Policies can be applied to:

  1. management groups
  2. subscriptions
  3. resource groups
  4. individual resources.

Lower levels inherit settings from higher levels.

management groups

Management groups provide a governance scope above subscriptions. You organize subscriptions into management groups; the governance conditions you apply cascade by inheritance to all associated subscriptions.

generate graphics

Use https://github.com/microsoft/ARI

azure policy vs. azure rbac (governence)

  • Azure RBAC - manages who has access to Azure resources, what areas they have access to and what they can do with those resources.
  • Azure Policy – focus on resource properties during deployment and for already existing resources. They are able to block or allow specific values for the properties or add properties like tags after deployment.

Azure RBAC and Policy

Source: Governance 101: The Difference Between RBAC and Policies

collect logging in resource group

If you want to access all logs on resource group level you need to create a log analytic workspace.

Container apps vs container instances

Use container apps when you

  • need autoscaling
  • want easy loadbalancer integration (each app separately) with azure domain (or custom domain)

Source

Postgres single server vs flex

Flexible server

  • recommended service according to azure portal
  • newer postgres versions available
  • zone replication

Source

blob vs container

Blob are grouped in containers. Containers belong to storage accounts.

list region/location codes

Run az account list-locations -o table or look here

create service account for pulumi/terraform in pipeline:

See here or:

#!/usr/bin/env bash

set -e

SUBSCRIPTION=
NAME=XXXX-pipeline-service-principal
YEARS=10

az ad sp create-for-rbac --name="${NAME}" --role="Contributor" --scopes="/subscriptions/${SUBSCRIPTION}" --years=$YEARS --sdk-auth > .localsecret_pipeline

## to get information on user
# az ad sp list --display-name=${NAME}

## reset password and print it (if old password is lost)
# az ad sp credential reset --name=${NAME}

## delete service principal
# az ad sp delete --id 00000000-0000-0000-0000-00000000000000000

managed identities

Managed identities are an alternative to credentials. They are bound to a resource and allow the resource to interact with other resources with the rights of the identity (similar to aws roles).

  • System-assigned: identities are created by azure and the lifecycle is bound to the resource in which it was created (e.g. the container app)
  • User-assigned: configure a service principal for the resource. Lifecycle is controled by user.

azure exctensions

Some commands az containerapp do not run out of the box. You need to install the extension to use it.

# list extensions and see if they are installed
az extension list-available --output table

# add containerapp extension
az extension add --name containerapp

Official doc

see arm template of resource with az

az containerapp connection list

app registration vs enterprise app / service principal

blog article Create service principal in UI

Container apps comunication

Online as well as communication between to container apps need to use the ingress. You can choose if ingress is public available or only for other container apps.

The url is: CONTAINER_APP_NAME.CONTAINER_APP_ENV_NAME.REGION_NAME.azurecontainerapps.io E.g. can be look like this: app.kindflower-050d0634.germanywestcentral.azurecontainerapps.io

Every container app revision got an URL as well. This URL contains the revision name as subdomain instead of the conainter app name.

container app debugging

It may happen that a container is killed but you got no log entry other than "killed".

Troubleshooting:s set the memory and cpu to max (or check in metrics if the memory metric is too high before it collapesesz

pipelines user for az and pulumi

How to create and use a service principal

az ad sp create-for-rbac --name="myapp-service-principal" --role="Contributor" --scopes="/subscriptions/BLA" --years=10 --sdk-auth

Create sp with --sdk-auth flag so your output looks something like this. Action does not work with the normal outoput of four properties.

 {
 "clientId": "",
 "clientSecret": "",
 "subscriptionId": "",
 "tenantId": "",
 "activeDirectoryEndpointUrl": "",
 "resourceManagerEndpointUrl": "",
 "activeDirectoryGraphResourceId": "",
 "sqlManagementEndpointUrl": "",
 "galleryEndpointUrl": "",
 "managementEndpointUrl": ""
 }
 ```

### example for az

Add the following to a Action Secret `AZURE_CREDENTIALS`:

Pipeline example:

```yaml
name: Deploy Backend feat

on:
  push:
    branches:
      - azure-env
    paths:
      - 'graphql_backend/**/*'
      - '.github/workflows/azure-feat-backend.yml'
env:
  AZURE_REGISTRY_USERNAME: myapp
  REGISTRY: myapp.azurecr.io
  REPOSITORY: myapp-2834-repo
  IMAGE_TAG:  backend-${{github.sha }}
  AZURE_RESOURCE_GROUP: dev-myapp322577c2
  AZURE_CONTAINER_APP_NAME: dev-myapp-app-backend

jobs:
  build:
    name: Build Backend
    runs-on: ubuntu-latest
    environment: dev
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - uses: azure/docker-login@v1
        with:
          login-server: ${{ env.REGISTRY }}
          username: ${{ env.AZURE_REGISTRY_USERNAME }}
          password: ${{ secrets.AZURE_REGISTRY_PASSWORD }}

      - name: Build, tag, and push Backend container registry
        id: build-image-backend
        run: |
          docker build -t ${{ env.REGISTRY }}/${{ env.REPOSITORY}}:${{ env.IMAGE_TAG }} graphql_backend
          docker push ${{ env.REGISTRY }}/${{ env.REPOSITORY}}:${{ env.IMAGE_TAG }}
          echo "::set-output name=image::${{ env.REGISTRY }}/${{ env.REPOSITORY}}:${{ env.IMAGE_TAG }}"    

  deploy:
      name: Deploy Backend
      runs-on: ubuntu-latest
      environment: dev
      needs: build
      steps:
        - name: Azure Login
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}

        - name: Deploy to containerapp
          uses: azure/CLI@v1
          with:
            inlineScript: |
              echo "Installing containerapp extension"
              az extension add --name containerapp
              az config set extension.use_dynamic_install=yes_without_prompt

              # note needed when access is already created
              echo "Configure registry"
              az containerapp registry set -n ${{ env.AZURE_CONTAINER_APP_NAME }} -g ${{ env.AZURE_RESOURCE_GROUP }} --server ${{ env.REGISTRY }} --username  ${{ env.AZURE_REGISTRY_USERNAME }} --password ${{ secrets.AZURE_REGISTRY_PASSWORD }}

              echo "Deploy ${{ env.REGISTRY }}/${{ env.IMAGE_TAG }}:${{ github.sha }}"
              az containerapp update -n ${{ env.AZURE_CONTAINER_APP_NAME }} -g ${{ env.AZURE_RESOURCE_GROUP }} --image ${{ env.REGISTRY }}/${{ env.IMAGE_TAG }}

example for pulumi

If you want to use a service principal with pulumi you need to configure the following configs Source

Depends on backend. If you use multiple backends e.g. azure and azure-native you need to fullfill all login requirements.

pulumi config set azure-native:clientId ""
pulumi config set azure-native:clientSecret "" --secret
pulumi config set azure-native:tenantId ""
pulumi config set azure-native:subscriptionId ""
name: Pulumi
on:
  - pull_request
jobs:
  preview:
    name: Preview
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v3
        with:
          node-version-file: .nvmrc
      - run: npm install
      # see https://github.com/pulumi/actions
      # or for full parameter overview https://github.com/pulumi/actions/blob/master/action.yml
      - uses: pulumi/actions@v3
        with:
          command: preview
          stack-name: staging
          comment-on-pr: true
          cloud-url: azblob://fairmanager-pulumistate
          #github-token: ${{ secrets.GITHUB_TOKEN }}
        env:
          PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }}
          AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
          AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }}

azure logs

KQL reference

Examples:

# container app 

## app log
ContainerAppConsoleLogs_CL
| project TimeGenerated,  Log_s, RevisionName_s, ContainerImage_s
| sort by TimeGenerated desc  

## kubernetes events/logs
ContainerAppConsoleLogs_CL
| project TimeGenerated,  Log_s, RevisionName_s, ContainerImage_s
| sort by TimeGenerated desc  

## example timerange relative
let endDateTime = now();
let startDateTime = ago(1h);
ContainerAppConsoleLogs_CL
| where TimeGenerated >= startDateTime
| where TimeGenerated < endDateTime
| sort by TimeGenerated desc  

delete old images in a repo

on-demand task + az acr purge

brew + az + completion

# workaround no az completion in zsh
# https://medium.com/@MyDiemHo/enable-azure-cli-autocomplete-in-oh-my-zsh-93e79019a20d
autoload -U +X bashcompinit && bashcompinitsource 
source /opt/homebrew/etc/bash_completion.d/az

pulumi examples

Official List

work with userAssignedIdentities in typescript

As long as this issue is not implemented you may need to workaround limitations of dynamic properties in typescript in conjunction with pulumi.Output type.

const userIdentity = new managedidentity.UserAssignedIdentity("uai", {
    resourceGroupName: resourceGroup.name,
    location: resourceGroup.location,
});
// userIdentity.id is from type pulumi.Output<String>

// this does not work
...
userAssignedIdentities: {
  [userIdentity.id]: {}
}
...

// this does
...
identity: {
        type: containerinstance.ResourceIdentityType.UserAssigned,
        userAssignedIdentities: userIdentity.id.apply(id => {
            const dict: { [key: string] : object } = {};
            dict[id] = {};
            return dict;
        }),
    },
...

// translates to this:
userAssignedIdentities: {
  /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}: {}
}

add firewall rule for azure service

To confgure IaC as the azure portal checkbox "Allow public access from any Azure service within Azure to this serve" does you need to add the firewall rule with start ip and end ip address 0.0.0.0

See example in ARM:

        {
            "type": "Microsoft.DBforPostgreSQL/flexibleServers/firewallRules",
            "apiVersion": "2022-01-20-preview",
            "name": "[concat(parameters('flexibleServers_dev_fairmanager_postgres_name'), '/allow_all_azure_resources')]",
            "dependsOn": [
                "[resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('flexibleServers_dev_fairmanager_postgres_name'))]"
            ],
            "properties": {
                "startIpAddress": "0.0.0.0",
                "endIpAddress": "0.0.0.0"
            }
        },

or pulumi

import * as dbforpostgresql from "@pulumi/azure-native/dbforpostgresql";

const pgFirewallRules = [
    { firewallRuleName: "AllowAllAzureServicesAndResourcesWithinAzureIps", startIpAddress: "0.0.0.0", endIpAddress: "0.0.0.0" },
]

pgFirewallRules.forEach((rule, index) => {
    new dbforpostgresql.FirewallRule(`${stack}-postgres-firewall-${index}`, {
        resourceGroupName: resourceGroup.name,
        serverName: pgServer.name,
        firewallRuleName: rule.firewallRuleName,
        endIpAddress: rule.endIpAddress,
        startIpAddress: rule.startIpAddress,
    });
});

application gateway

If you can, avoid this resource at all. It is tedious complex to configure. Use frontdoor instead if possible.

Pitfall: If you got multiple Level 7 routing mechanism e.g. application gateway which points on container apps you need to ensure that the host header is correct otherwise you get a 404 on the gateway probes. In doubt override the host name in the backend setting of the application gateway to the exact dns name of the target application.

Here is a gist which contains pulumi code to create an application gateway with TLS and the necessary certificate generation as well as a vault to save the certificate. At this point it is not possible to import a certificate to a vault via pulumi. See this issue..

pitfalls

Reason: You gave azure an resource group id but it expected a resoure group name.

Message:

 error: cannot check existence of resource '/subscriptions/SUBID/resourceGroups/%2Fsubscriptions%2FSUBID%2FresourceGroups%2FRGNAME/providers/Microsoft.Network/applicationGateways/staging-fairmanager-gateway': status code 400, {"error":{"code":"InvalidApiVersionParameter","message":"The api-version '2020-11-01' is invalid. The supported versions are '2022-09-01,2022-06-01,2022-05-01,2022-03-01-preview,2022-01-01,2021-04-01,2021-01-01,2020-10-01,2020-09-01,2020-08-01,2020-07-01,2020-06-01,2020-05-01,2020-01-01,2019-11-01,2019-10-01,2019-09-01,2019-08-01,2019-07-01,2019-06-01,2019-05-10,2019-05-01,2019-03-01,2018-11-01,2018-09-01,2018-08-01,2018-07-01,2018-06-01,2018-05-01,2018-02-01,2018-01-01,2017-12-01,2017-08-01,2017-06-01,2017-05-10,2017-05-01,2017-03-01,2016-09-01,2016-07-01,2016-06-01,2016-02-01,2015-11-01,2015-01-01,2014-04-01-preview,2014-04-01,2014-01-01,2013-03-01,2014-02-26,2014-04'."}}

container instances

They change their IP Adresse. To expose them in a application gateway you need to:

  • set dns-name-label when they have public ip addresses.
  • if they are in a private vnet you can add a private dns zone and configure a init container which adds its ip adress to the dns

Policies

  • Overview of Azure Policies -Azure Policy is a service in Azure which allows you create polices which enforce and control the properties of a resource
  • An Azure initiative is a collection of Azure policy definitions that are grouped together towards a specific goal or purpose in mind.

private endpoints

The domains of a private endpoint have a public DNS entry and a public IP. If you want to use the endpoint you must override this on the client machiines. If you are inside an Azure vnet you can use a private DNS zone. Otherwise you can follow this guide.

private dns zones

Are linked to one or more vnet. They are account global and can be linked to vnets in different ressource groups or subscriptions. The main features are auto registration of VMs in the network, forward and reverse lookup for all VMs which are in the connected Vnets.

VPN

  • A Virtual Network Gateway is the Azure-side component of a VPN connection. It acts as a gateway for connecting your Azure virtual network to one or more on-premises networks.
  • A Local Network Gateway represents the on-premises network that you want to connect to your Azure virtual network.
  • A Connection in Azure represents the actual link or tunnel between a Virtual Network Gateway (VNG) and a Local Network Gateway (LNG).

services to regularly check