Langzeitbackups machen

Die meisten Anbieter haben inzwischen Lösungen für Cloud-Drives (OneDrive von Microsoft, Google Drive, Apple iCloud). Doch ab und zu schläft man besser, wenn man noch ein zusätzliches Backup hat.

Tape Storage

Amazon Glacier

Amazon Glacier ist kinderleicht zu bedienen und extrem kostengünstig. Das Anfordern des Inventars kann schon einige Stunden in Anspruch nehmen, aber ein Backup braucht man ja nicht jeden Tag. Wir reden hier von ca. 60cent pro Monat für 80GB. Man lädt die Inventar Metadaten lokal und synced dann. Storage Class ändern ist nicht erforderlich.

Fast Glacier

Fast Glacier hat bis jetzt auch mit der Gratis-Version einwandfrei funktioniert. Durch einen blöden Zufall hab ich mich heuer aber aus AWS ausgesperrt und müsste eine notarielle Beglaubigung unterzeichnen (50 EUR), damit ich wieder Zugriff erlange. Daher der Wechsel auf Azure - was ich ohnehin schon immer machen wollte, da ich inzwischen Azure in der Arbeit genutzt habe.

Azure Blob Storage

Der Storage Explorer ist gratis und funktioniert auch hervorragend. Allerdings wollte ich meine lokalen Ordner mit dem Container synchronisieren - das geht aber nur mit azcopy.

Storage Explorer

Folgende Links sind wichtig:

Fazit: Man muss im Hot Access-Tier synchronisieren.

Bevor man loslegen kann, muss man natürlich erst mal den Container anlegen.

main.bicep

targetScope = 'subscription'

resource backupRessourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = {
  name: 'rg-xxxx-001'
  location: 'germanywestcentral'
}

module storageAccount 'storage.bicep' = {
  name: 'storageModule'
  scope: backupRessourceGroup
  params: {
    storageName: '<storage-account>'
    location: backupRessourceGroup.location
  }
}

Microsoft empfiehlt, die Values nicht hardzucoden.

storage.bicep

@description('Azure region of the deployment')
param location string = resourceGroup().location

@description('Name of the storage account')
param storageName string
@description('Azure region of the deployment')
param location string = resourceGroup().location

@description('Name of the storage account')
param storageName string

resource backupStorageContainerAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  name: storageName
  location: location
  tags: {}
  properties: {
    dnsEndpointType: 'Standard'
    allowedCopyScope: 'AAD'
    defaultToOAuthAuthentication: true
    publicNetworkAccess: 'Enabled'
    allowCrossTenantReplication: false
    isSftpEnabled: false
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    allowSharedKeyAccess: false
    isHnsEnabled: true
    networkAcls: {
      ipv6Rules: []
      bypass: 'AzureServices'
      virtualNetworkRules: []
      ipRules: []
      defaultAction: 'Allow'
    }
    supportsHttpsTrafficOnly: true
    encryption: {
      requireInfrastructureEncryption: false
      services: {
        file: {
          keyType: 'Account'
          enabled: true
        }
        blob: {
          keyType: 'Account'
          enabled: true
        }
      }
      keySource: 'Microsoft.Storage'
    }
    accessTier: 'Hot'
  }
}

resource backupStorageContainerAccount_default 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
  parent: backupStorageContainerAccount
  name: 'default'
  properties: {
    cors: {
      corsRules: []
    }
    deleteRetentionPolicy: {
      allowPermanentDelete: false
      enabled: false
    }
  }
  sku: {
    name: 'Standard_LRS'
    tier: 'Standard'
  }
}

resource storageBlobDataContributorRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  scope: subscription()
  name: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  scope: backupStorageContainerAccount
  name: guid(resourceGroup().id, '<AD user object id>', storageBlobDataContributorRoleDefinition.id)
  properties: {
    roleDefinitionId: storageBlobDataContributorRoleDefinition.id
    principalId: '<AD user object id>'
    principalType: 'User'
  }
}

resource storageAccounts_backup2fhw_name_default_onedrive 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
  parent: backupStorageContainerAccount_default
  name: '<containername>'
  properties: {
    defaultEncryptionScope: '$account-encryption-key'
    denyEncryptionScopeOverride: false
    publicAccess: 'None'
  }
}

Für RBAC braucht der User die Storage Blob Data Contributor Rolle. Wichtig ist auch, dass man den hierarchischen Namespace aktiviert um Ordner zu “simulieren”.

Um zu deployen, macht man folgendes:

@echo off

az login

call az account set --subscription "<subscription>"

call az deployment sub create --name backupDeployment --location germanywestcentral --template-file main.bicep

pause

Anschließend kann man den Ordner kopieren:

@echo off

set AZCOPY_AUTO_LOGIN_TYPE=AZCLI

call azcopy sync "\\192.XXX.XXX.XXX\<folder>" "https://<storage-account>.blob.core.windows.net/<container>" --recursive

pause

Wichtig ist, dass man die Dateien dann von Hot nach Archive schiebt. Mit PowerShell schaut das wie folge aus:

$storageAccountName = "<storage-account>"
$storageContainer =  "<container>"
$MaxReturn = 10000

Write-Host "Starting script"

Connect-AzAccount

$ctx = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount
$Token = $Null

do  
{  
    $listOfBlobs = Get-AzStorageBlob -Container $storageContainer -Context $ctx -MaxCount $MaxReturn -ContinuationToken $Token
  
    foreach($blob in $listOfBlobs) {          
        if($blob.BlobProperties.AccessTier -ne "Archive" -and $blob.BlobProperties.Metadata["hdi_isfolder"] -ne "true")
        { 
          $blob.ICloudBlob.SetStandardBlobTier("Archive")
          Write-Host "the blob" $blob.name "is being set to Archive"          
        }
    }  
    $Token = $blob[$blob.Count -1].ContinuationToken;  
    
    write-host "Processed items. Continuation token = " $Token.NextMarker
} while ($Null -ne $Token)

Write-Host "Complete processing of all blobs"

Nicht vergessen, vorher das AZ Modul zu installieren:

Install-Module -Name Az -Repository PSGallery -Force

Siehe auch Doku:

The Set Blob Tier suboperation of the Blob Batch operation is not yet supported in accounts that have a hierarchical namespace.

Google

Google hat ähnliche Storage Klassen.

Das ändern der Storage-Klasse geht hier für den ganzen Bucket (=Container):

gsutil defstorageclass set ARCHIVE gs://your-bucket-name

Aber noch nie verwendet.

Zu beachten

  • Bei google ist die Mindestzeit im Archiv 1 Jahr - bei Microsoft ein halbes Jahr.
  • google braucht nur wenige msec zum Wiederherstellen, Microsoft und Amazon mehrere Stunden

Fazit

Durch Cloud-Services war es noch nie so einfach Software zu machen. Von OCR bis Spracherkennung bis eben super Storage-Services. Habe ich bedenken bzgl. Sicherheit? Nein. Mein Nachbar hat mich mal zur Hilfe geholt - der hat ein Uralt-Zyxel NAS, für das es schon ewig lange keine Updates mehr gibt. Er konnte den Share nicht mehr in Windows einbinden, weil es selbst die Minimalanforderungen an Sicherheit nicht mehr erfüllt. Und neue Computer haben keine Laufwerke mehr - d.h. ein M-Disc fähiges Laufwerk zu kaufen macht auch keinen Sinn mehr.