Quickstart mit Azure und Terraform

Was braucht es dazu?

Folgende Voraussetzungen müssen gegeben sein:

  1. Erstellen einer app im Azure Portal.
  2. Kopieren der Schlüssel
  3. Verifizierung des Zugriffes mit den Azure Cli Tools.
  4. Terraform muss installiert sein.

Erstellen einer App im Azure Portal

Um automatisiert Ressourcen auf Azure erstellen zu können, muss vorgängig eine App im Active Directory erstellt werden.

  1. Im Azure Portal Active Directory, App Registrierung auswählen.
Azure: App Registrierung
  1. Nun wählt man neue Registrierung hinzufügen.
Azure: App Registrierung hinzufügen.
  1. Anschliessend im Menü Zertifikate und Geheimnisse ein neuer Geheimer Clientschlüssel erstellen ein.
Azure: Geheimer Schlüssel erstellen.
  1. Nun ist es wichtig, beide Schlüssel zu notieren.
  1. Nun muss noch die Client Id aufgeschrieben werden. Diese findet man in der App Registrierungs-Übersicht.
Azure: Schlüssel erstellen.

Diese können, wenn man sich mit den Azure Cli Tools einmal angemeldet hat mit folgendem Befehl herausgefunden werden:

az account list
  1. Nun muss über das Abonnement und die Zugriffsteuerung der erstellten App eine Rolle zugewiesen werden, damit diese funktioniert. In diesem Beispiel ist die Rolle "Mitwirkender" verwendet worden (Hängt vom Anwendungsfall in der Firma ab, welche tatsächliche Rolle vergeben wird.) Dies geschieht über "Rollenzuweisung hinzufügen".
Azure: Rollenzuweisung hinzufügen.
  1. Anschliessend muss man die zuvor erstellte App hinzufügen. Diese kann mittels Suchfeld gesucht und hinzugefügt werden.
Azure: Applikation hinzufügen.

Verifizierung des Zugriffes mit den Azure Cli Tools

Als erstes müssen die Azure Cli Tools bereits installiert sein.

Sobald die Azure Cli Tools installiert sind, kann man sich mit dem Service Principal versuchen anzumelden.

PS C:\Git-Repos\blogposts> az login --service-principal -u "YOUR APP ID"  -p "APP ID SECRET" --tenant "YOUR TENANT ID"
[
  {
    "cloudName": "AzureCloud",
    "homeTenantId": "YOUR TENANT",
    "id": "YOUR SUBSCRIPTION",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Pay-As-You-Go",
    "state": "Enabled",
    "tenantId": "YOUR TENANT",
    "user": {
      "name": "YOUR APP ID",
      "type": "servicePrincipal"
    }
  }
]
PS C:\Git-Repos\blogposts> 

Terraform SetUp

Damit Terraform funktioniert, müssen die zuvor heruntergeladenen Schlüssel eingetragen werden. Diese Konfiguration sieht dann wie folgt aus:

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}

  subscription_id = "ABONNEMENT ID"
  client_id       = "ZUVOR ERSTELLTE APPLIKATIONS ID"
  client_secret   = "ZUVOR ERSTELLTES GEHEIMNIS IN DER APP"
  tenant_id       = "TENANT ID"
}

Damit auch hier überprüft werden kann ob die Verbindung mit Azure funktioniert kann auch ein StorageAccount erstellt werden mit den Terraform Ressourcen.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.0.0"
    }
  }
}

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}

  subscription_id = "YOURSUBSCRIPTION"
  client_id       = "APP ID"
  client_secret   = "SECRET ID"
  tenant_id       = "YOUR TENANT"
}

resource "azurerm_resource_group" "rg" {
  name = "terrfaform-playground"
  location = "switzerlandnorth"
}

resource "azurerm_storage_account" "storage" {
  account_tier = "Standard"
  account_replication_type = "LRS"
  location = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  name = "schaedldstorage"  
}

Wir terraform dann in seiner Reihenfolge mit

terraform init                

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Using previously-installed hashicorp/azurerm v3.0.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
terraform plan -out sampleplan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "switzerlandnorth"
      + name     = "terrfaform-playground"
    }

  # azurerm_storage_account.storage will be created
  + resource "azurerm_storage_account" "storage" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "LRS"
      + account_tier                      = "Standard"
      + allow_nested_items_to_be_public   = true
      + enable_https_traffic_only         = true
      + id                                = (known after apply)
      + infrastructure_encryption_enabled = false
      + is_hns_enabled                    = false
      + large_file_share_enabled          = (known after apply)
      + location                          = "switzerlandnorth"
      + min_tls_version                   = "TLS1_2"
      + name                              = "schaedldstorage"
      + nfsv3_enabled                     = false
      + primary_access_key                = (sensitive value)
      + primary_blob_connection_string    = (sensitive value)
      + primary_blob_endpoint             = (known after apply)
      + primary_blob_host                 = (known after apply)
      + primary_connection_string         = (sensitive value)
      + primary_dfs_endpoint              = (known after apply)
      + primary_dfs_host                  = (known after apply)
      + primary_file_endpoint             = (known after apply)
      + primary_file_host                 = (known after apply)
      + primary_location                  = (known after apply)
      + primary_queue_endpoint            = (known after apply)
      + primary_queue_host                = (known after apply)
      + primary_table_endpoint            = (known after apply)
      + primary_table_host                = (known after apply)
      + primary_web_endpoint              = (known after apply)
      + primary_web_host                  = (known after apply)
      + queue_encryption_key_type         = "Service"
      + resource_group_name               = "terrfaform-playground"
      + secondary_access_key              = (sensitive value)
      + secondary_blob_connection_string  = (sensitive value)
      + secondary_blob_endpoint           = (known after apply)
      + secondary_blob_host               = (known after apply)
      + secondary_connection_string       = (sensitive value)
      + secondary_dfs_endpoint            = (known after apply)
      + secondary_dfs_host                = (known after apply)
      + secondary_file_endpoint           = (known after apply)
      + secondary_file_host               = (known after apply)
      + secondary_location                = (known after apply)
      + secondary_queue_endpoint          = (known after apply)
      + secondary_queue_host              = (known after apply)
      + secondary_table_endpoint          = (known after apply)
      + secondary_table_host              = (known after apply)
      + secondary_web_endpoint            = (known after apply)
      + secondary_web_host                = (known after apply)
      + shared_access_key_enabled         = true
      + table_encryption_key_type         = "Service"

      + blob_properties {
          + change_feed_enabled      = (known after apply)
          + default_service_version  = (known after apply)
          + last_access_time_enabled = (known after apply)
          + versioning_enabled       = (known after apply)

          + container_delete_retention_policy {
              + days = (known after apply)
            }

          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + delete_retention_policy {
              + days = (known after apply)
            }
        }

      + network_rules {
          + bypass                     = (known after apply)
          + default_action             = (known after apply)
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)

          + private_link_access {
              + endpoint_resource_id = (known after apply)
              + endpoint_tenant_id   = (known after apply)
            }
        }

      + queue_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + hour_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }

          + logging {
              + delete                = (known after apply)
              + read                  = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
              + write                 = (known after apply)
            }

          + minute_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }
        }

      + routing {
          + choice                      = (known after apply)
          + publish_internet_endpoints  = (known after apply)
          + publish_microsoft_endpoints = (known after apply)
        }

      + share_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + retention_policy {
              + days = (known after apply)
            }

          + smb {
              + authentication_types            = (known after apply)
              + channel_encryption_type         = (known after apply)
              + kerberos_ticket_encryption_type = (known after apply)
              + versions                        = (known after apply)
            }
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

Saved the plan to: sampleplan

To perform exactly these actions, run the following command to apply:
    terraform apply "sampleplan"
terraform apply simpleplan    
azurerm_resource_group.rg: Creating...
azurerm_resource_group.rg: Creation complete after 1s [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground]
azurerm_storage_account.storage: Creating...
azurerm_storage_account.storage: Still creating... [10s elapsed]
azurerm_storage_account.storage: Still creating... [20s elapsed]
azurerm_storage_account.storage: Creation complete after 21s [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground/providers/Microsoft.Storage/storageAccounts/schaedldstorage]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Nach der Kontrolle im Azure Portal sieht man das Ergebnis.

Azure: Ressource Gruppe.

Die Ressource Gruppe ist erstellt und wenn man diese auswählt, sieht man den darin erstellten StorageAccount.

Azure: Storageaccount.

as Abräumen der Ressource kann dann wie folgt geschehen:

terraform destroy
azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground]
azurerm_storage_account.storage: Refreshing state... [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground/providers/Microsoft.Storage/storageAccounts/schaedldstorage]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be destroyed
  - resource "azurerm_resource_group" "rg" {
      - id       = "/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground" -> null
      - location = "switzerlandnorth" -> null
      - name     = "terrfaform-playground" -> null
      - tags     = {} -> null
    }

  # azurerm_storage_account.storage will be destroyed
  - resource "azurerm_storage_account" "storage" {
      - access_tier                       = "Hot" -> null
      - account_kind                      = "StorageV2" -> null
      - account_replication_type          = "LRS" -> null
      - account_tier                      = "Standard" -> null
      - allow_nested_items_to_be_public   = true -> null
      - enable_https_traffic_only         = true -> null
      - id                                = "/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground/providers/Microsoft.Storage/storageAccounts/schaedldstorage" -> null
      - infrastructure_encryption_enabled = false -> null
      - is_hns_enabled                    = false -> null
      - location                          = "switzerlandnorth" -> null
      - min_tls_version                   = "TLS1_2" -> null
      - name                              = "schaedldstorage" -> null
      - nfsv3_enabled                     = false -> null
      - primary_access_key                = (sensitive value)
      - primary_blob_connection_string    = (sensitive value)
      - primary_blob_endpoint             = "https://schaedldstorage.blob.core.windows.net/" -> null
      - primary_blob_host                 = "schaedldstorage.blob.core.windows.net" -> null
      - primary_connection_string         = (sensitive value)
      - primary_dfs_endpoint              = "https://schaedldstorage.dfs.core.windows.net/" -> null
      - primary_dfs_host                  = "schaedldstorage.dfs.core.windows.net" -> null
      - primary_file_endpoint             = "https://schaedldstorage.file.core.windows.net/" -> null
      - primary_file_host                 = "schaedldstorage.file.core.windows.net" -> null
      - primary_location                  = "switzerlandnorth" -> null
      - primary_queue_endpoint            = "https://schaedldstorage.queue.core.windows.net/" -> null
      - primary_queue_host                = "schaedldstorage.queue.core.windows.net" -> null
      - primary_table_endpoint            = "https://schaedldstorage.table.core.windows.net/" -> null
      - primary_table_host                = "schaedldstorage.table.core.windows.net" -> null
      - primary_web_endpoint              = "https://schaedldstorage.z1.web.core.windows.net/" -> null
      - primary_web_host                  = "schaedldstorage.z1.web.core.windows.net" -> null
      - queue_encryption_key_type         = "Service" -> null
      - resource_group_name               = "terrfaform-playground" -> null
      - secondary_access_key              = (sensitive value)
      - secondary_connection_string       = (sensitive value)
      - shared_access_key_enabled         = true -> null
      - table_encryption_key_type         = "Service" -> null
      - tags                              = {} -> null

      - blob_properties {
          - change_feed_enabled      = false -> null
          - last_access_time_enabled = false -> null
          - versioning_enabled       = false -> null
        }

      - network_rules {
          - bypass                     = [
              - "AzureServices",
            ] -> null
          - default_action             = "Allow" -> null
          - ip_rules                   = [] -> null
          - virtual_network_subnet_ids = [] -> null
        }

      - queue_properties {

          - hour_metrics {
              - enabled               = true -> null
              - include_apis          = true -> null
              - retention_policy_days = 7 -> null
              - version               = "1.0" -> null
            }

          - logging {
              - delete                = false -> null
              - read                  = false -> null
              - retention_policy_days = 0 -> null
              - version               = "1.0" -> null
              - write                 = false -> null
            }

          - minute_metrics {
              - enabled               = false -> null
              - include_apis          = false -> null
              - retention_policy_days = 0 -> null
              - version               = "1.0" -> null
            }
        }

      - share_properties {

          - retention_policy {
              - days = 7 -> null
            }
        }
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_storage_account.storage: Destroying... [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground/providers/Microsoft.Storage/storageAccounts/schaedldstorage]
azurerm_storage_account.storage: Destruction complete after 2s
azurerm_resource_group.rg: Destroying... [id=/subscriptions/YOURSUBSCRIPTION/resourceGroups/terrfaform-playground]
azurerm_resource_group.rg: Still destroying... [id=/subscriptions/YOURSUBSCRIPTION-...4/resourceGroups/terrfaform-playground, 10s elapsed]
azurerm_resource_group.rg: Destruction complete after 16s

Destroy complete! Resources: 2 destroyed.

Nach dessen Ausführung ist dann auch im Azure-Portal nichts mehr zu sehen.

„Azure: Ressourcegruppe entfernt.

Fazit

Ein einfacher Weg Infrastruktur auch in Azure zu erstellen, ohne die dauernde Anmeldung und der Möglichkeit, Terraform automatisiert in einer CI/CD Pipeline laufen zu lassen.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s