Можно ли загрузить блоб Azure с помощью токена идентификации виртуальной машины через PowerShell без использования ключей доступа - PullRequest
0 голосов
/ 14 января 2020

Я настраиваю виртуальную машину для выполнения начальной загрузки при создании. Частью этого является загрузка большого двоичного объекта из учетной записи хранения azure в виртуальную машину. Все они находятся в одной подписке, группе ресурсов и т. Д. c.

Я могу сделать это следующим образом:

function Get-BlobUsingVMIdentity 
{
    param(
        [Parameter(Mandatory = $true)] $containerName,
        [Parameter(Mandatory = $true)] $blobName,
        [Parameter(Mandatory = $true)] $outputFolder
    )

    write-host "Defining package information"
        mkdir $outputFolder -force

    write-host "Getting Instance meta data"
        $instanceInfo = Invoke-WebRequest -UseBasicParsing -Uri 'http://169.254.169.254/metadata/instance/?api-version=2018-02-01' `
            -Headers @{Metadata="true"} `
            | select -expand content `
            | convertfrom-json `
            | select -expand compute

        $storageAccountName = "$($instanceInfo.resourceGroupName.replace('-rg',''))sa" # This is custom since we know our naming schema
        $resourceGroupName = $($instanceInfo.resourceGroupName)
        $subscriptionId = $($instanceInfo.subscriptionId)

    write-host "Got storageAccountName [$storageAccountName], resourceGroupName [$resourceGroupName], subscriptionId [$subscriptionId]"

    write-host "Getting VM Instance Access Token"
        $response = Invoke-WebRequest  -UseBasicParsing -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' `
            -Headers @{Metadata = "true" }

        $content = $response.Content | ConvertFrom-Json
        $access_token = $content.access_token

    write-host "Getting SAS Token From Storage Account"
        $params = @{canonicalizedResource = "/blob/$($storageAccountName)/$($containerName)"; signedResource = "c"; signedPermission = "rcw"; signedProtocol = "https"; signedExpiry = "2031-09-23T00:00:00Z" }
        $jsonParams = $params | ConvertTo-Json

        $sasResponse = Invoke-WebRequest -UseBasicParsing -Uri "https://management.azure.com/subscriptions/$($subscriptionId)/resourceGroups/$($resourceGroupName)/providers/Microsoft.Storage/storageAccounts/$($storageAccountName)/listServiceSas/?api-version=2017-06-01" `
            -Method POST `
            -Body $jsonParams `
            -Headers @{Authorization="Bearer $access_token"}

        $sasContent = $sasResponse.Content | ConvertFrom-Json
        $sasCred = $sasContent.serviceSasToken

    write-host "Manually download blob"
        $params = @{signedResource = "c"; signedPermission = "rcw"; signedProtocol = "https"; signedExpiry = "2031-09-23T00:00:00Z" }
        $jsonParams = $params | ConvertTo-Json

        $sasResponse = Invoke-WebRequest -UseBasicParsing -Uri "https://$($storageAccountName).blob.core.windows.net/$($containerName)/$($blobName)?api-version=2017-06-01" `
            -Method POST `
            -Body $jsonParams `
            -Headers @{Authorization="Bearer $access_token"}

        $sasContent = $sasResponse.Content | ConvertFrom-Json
        $sasCred = $sasContent.serviceSasToken

    write-host "Setting up storage context"
        $ctx = New-AzStorageContext -StorageAccountName $storageAccountName -SasToken $sasCred

    write-host "Downloading package"
        Get-AzStorageBlobContent `
            -Blob $blobName `
            -Container $containerName `
            -Destination $outputFolder `
            -Context $ctx `
            -Force
}

Это работает отлично, за исключением того, что я должен предоставить полный / доступ на запись к идентификатору, чтобы он мог использовать ключ доступа.

Существует ли подобный подход, который разрешил бы доступ только для чтения к BLOB-объекту? Мои цели: 1. Никакие учетные данные нигде не хранятся. 2. Загрузите BLOB-объект в виртуальную машину из azure хранилища 3. Нет статически определенных переменных (например: subscriptionid) 4. Доступ только для чтения к учетной записи BLOB / хранилища.

Цени любую помощь!

Ответы [ 2 ]

1 голос
/ 15 января 2020

Насколько я понимаю, вы хотите использовать Azure VM MSI для доступа к Azure хранилищу. Если это так, выполните следующие действия:

  1. Включите назначенный системой управляемый идентификатор на виртуальной машине
Connect-AzAccount
$vm = Get-AzVM -ResourceGroupName myResourceGroup -Name myVM
Update-AzVM -ResourceGroupName myResourceGroup -VM $vm -AssignIdentity:$SystemAssigned
Предоставьте вашей виртуальной машине доступ к Azure контейнеру хранения
Connect-AzAccount
$spID = (Get-AzVM -ResourceGroupName myRG -Name myVM).identity.principalid
New-AzRoleAssignment -ObjectId $spID -RoleDefinitionName "Storage Blob Data Reader" -Scope "/subscriptions/<mySubscriptionID>/resourceGroups/<myResourceGroup>/providers/Microsoft.Storage/storageAccounts/<myStorageAcct>/blobServices/default/containers/<container-name>"
access blob
# get AD access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' `
                              -Headers @{Metadata="true"}
$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token

# call Azure blob rest api
$url="https://<myaccount>.blob.core.windows.net/<mycontainer>/<myblob>"
$RequestHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$RequestHeader.Add("Authorization", "Bearer $access_token")
$RequestHeader.Add("x-ms-version", "2019-02-02")

$result = Invoke-WebRequest -Uri $url -Headers $RequestHeader
$result.content 

Update

Согласно моему тесту, когда мы получаем токен для доступа к Azure blob, нам нужно изменить resouce как https://storage.azure.com/

# get AD access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/' `
                              -Headers @{Metadata="true"}
$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token

# call Azure blob rest api
$url="https://<myaccount>.blob.core.windows.net/<mycontainer>/<myblob>"
$RequestHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$RequestHeader.Add("Authorization", "Bearer $access_token")
$RequestHeader.Add("x-ms-version", "2019-02-02")

$result = Invoke-WebRequest -Uri $url -Headers $RequestHeader
$result.content 

enter image description here

0 голосов
/ 15 января 2020

Обновление

Найден гораздо более простой способ сделать это! Ключ должен был использовать:

Connect-AzAccount -identity

Это автоматически регистрирует личность и позволяет вам взаимодействовать через модуль AZ вместо попытки взломать вызовы API вместе.

Для этого вам нужно только назначить [Storage Data Blob Data Reader].

Рабочий пример выглядит следующим образом:

function Get-BlobUsingVMIdentity
{
    param(
        [Parameter(Mandatory = $true)] $containerName,
        [Parameter(Mandatory = $true)] $blobName,
        [Parameter(Mandatory = $true)] $outputFolder
    )

    write-host "Get instance info"
        $instanceInfo = Invoke-WebRequest -UseBasicParsing -Uri 'http://169.254.169.254/metadata/instance/?api-version=2018-02-01' `
                -Headers @{Metadata="true"} `
                | select -expand content `
                | convertfrom-json `
                | select -expand compute

        $storageAccountName = "$($instanceInfo.resourceGroupName.replace('-rg',''))sa" # This is custom since we know our naming schema

    write-host "Clear existing identies to keep cache fresh"
        Clear-AzContext -force

    write-host "Authenticate using identity"
        $account = Connect-AzAccount -identity
        if(-not $account.Context.Subscription.Id)
        {
            write-error "Failed to authenticate with identity. Ensure VM has identity enabled and is assigned the correct IAM roles"
            return
        }

    write-host "Get storage context"
        $ctx = New-AZStorageContext  -StorageAccountName $storageAccountName

    write-host "Getting blob"
        Get-AzStorageBlobContent `
            -Blob $blobName `
            -Container $containerName `
            -Destination $outputFolder `
            -Context $ctx `
            -Force
}


Get-BlobUsingVMIdentity `
        -containerName "deploy" `
        -blobName "deploy.zip" `
        -outputFolder "c:\deploy\"

...