Автор статьи — Сергей Груздов (egel@egel.su), ведущий инженер, Dataline

Windows Azure Pack предоставляет подписчикам возможность использовать собственные ISO- и VHD(X)-файлы, расположенные в выделенной только для подписчика папке библиотеки. На данный момент единственным способом закачки файлов в эту папку является организация FTP с корневой папкой, указывающей на папку библиотеки, выделенной подписчикам. В данной статье я продемонстрирую, как с помощью ранбуков (runbook) Service Manager Automation (SMA) создавать и удалять папки подписчиков при заведении или удалении пользователя, и как с помощью расширения Microsoft FTP собственными провайдерами авторизации и домашних каталогов авторизовывать пользователей непосредственно через Azure Pack, исключая необходимость дублировать учетные записи в Active Directory.


Подготовка Azure Pack


Предварительно необходимо добавить активы SMA:
  1. VMMConnection – переменная типа «Соединение», в которой указывается FQDN сервера VMM и учетные данные. Учетная запись должна входить в группу локальных администраторов на сервере библиотеки, сервере VMM и в VMM входить в группу «Администраторы»
  2. VMMLibPath – переменная с общей папкой корневого каталога библиотеки подписчиков


Ранбуки SMA


Обработка события создания подписчика


Подготовим ранбук для создания каталога подписчика и привязки его к учетной записи в VMM. Текст ранбука ниже. В качестве бонуса – код, оповещающий пользователя после заведения его на админском портале (или любым другим способом) о необходимости смены пароля. Это избавляет от надобности генерации паролей и пересылкой их открытым текстом пользователю.
Notify-Created-User
workflow Notify-Created-User
{
    param
    (
        [Parameter(Mandatory=$true)]
        [object] $params
    )    
    
    $VmmConnection = Get-AutomationConnection -Name 'VmmConnection'
    $VmmServerName = $VmmConnection.ComputerName

    $SecurePassword = ConvertTo-SecureString -AsPlainText -String $VmmConnection.Password -Force
    $VmmCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $VmmConnection.Username, $SecurePassword
    $eMail = $params.Name.SubString(0, $params.Name.IndexOf("_"))
    
    $vmmLib = Get-AutomationVariable -Name 'VMMLibPath'
    
    $libServer = $vmmLib.SubString(2)
    $libServer = $libServer.SubString(0, $libServer.IndexOf("\"))
    
    $tenantPath = "{0}\{1}" -f $vmmLib, $eMail
    
    Write-Output "Invoke create folder on $libServer"
    inlinescript
    {
        try 
        { 
            if (!(Test-Path $Using:tenantPath))
            {
                Write-Output "Creating folder $($Using:tenantPath)"
                New-Item -Type Directory -Path $Using:tenantPath -ErrorAction Stop | Out-Null 
            }
            else
            {
                Write-Output "Folder $($Using:tenantPath) already exist"
            }
        }  
        catch
        { 
            Write-Output $_ 
        }
    } –PSComputer $libServer –PSCredential $VmmCredential
    
    inlinescript
    {
        $tenantSite = "https://my.azureline.ru" # здесь необходимо указать URL Tenant Site
        $authSite = "https://auth.azureline.ru" # здесь необходимо указать URL Tenant Auth Site
        $mail = $Using:eMail
        $roles = Get-SCUserRole -VMMServer $Using:VmmServerName | ?{$_.Name.Contains($mail)}

        # Для каждой подписки создается UserRole в SCVMM. Во избежание дубликатов писем, посылаем оповещение только если роль одна (при создании первой подписки)

        if (!($roles -is [System.Array]))
        {
            try
            {
                [reflection.assembly]::loadwithpartialname("System.Net.Http") | Out-Null
                $forget = New-Object System.Net.Http.HttpClient
                
                $getMess = $forget.GetAsync($tenantSite).Result
                $getMess.EnsureSuccessStatusCode() | Out-Null
                $authPage = $getMess.Content.ReadAsStringAsync().Result
                $forgRegex = [regex]'form id="__AjaxAntiForgeryForm".*?__RequestVerificationToken.*?value="(?<Token>.*?)"'
                $m = $forgRegex.Match($authPage);
                if ($m.Success)
                {
                    $forget.DefaultRequestHeaders.Add("x-ms-client-antiforgery-id", $m.Groups["Token"].Value);
                    $data = New-Object System.Net.Http.StringContent("{`"emailAddress`":`"$($Using:eMail)`"}", [System.Text.Encoding]::UTF8, "application/json")
                    $mess = $forget.PostAsync("$authSite/Account/SendMeResetPasswordLink", $data).Result
                    $mess.EnsureSuccessStatusCode() | Out-Null
                
                    Write-Output "Successfuly sent reset password link to $($Using:eMail)"
                }
            }
            catch
            {
                Write-Output $_
            }
            
            Write-Output "Set library share for $($roles.Name). Share path $($Using:tenantPath)"
            Set-SCUserRole -UserRole $roles -UserRoleDataPath $Using:tenantPath -VMMServer $Using:VmmServerName | Out-Null
        }
        else
        {
            Write-Output "Nothing to do"
        }       
    } –PSComputer $VmmServerName –PSCredential $VmmCredential
}



Очистка каталога FTP


Для очистки каталога FTP от каталогов удаленных подписчиков придется сделать ранбук, выполняющийся по расписанию, так как обработка некоторых событий VMM (нам необходимо для объекта «VMM UserRole» событие «Delete») в данное время в SMA не реализована.
CleanUp-Ftp-Folder
workflow CleanUp-Ftp-Folder
{
    $VmmConnection = Get-AutomationConnection -Name 'VmmConnection'
    $VmmServerName = $VmmConnection.ComputerName
    $SecurePassword = ConvertTo-SecureString -AsPlainText -String $VmmConnection.Password -Force
    $VmmCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $VmmConnection.Username, $SecurePassword
    
    $vmmLib = Get-AutomationVariable -Name 'VMMLibPath'
    
    $libServer = $vmmLib.SubString(2)
    $libServer = $libServer.SubString(0, $libServer.IndexOf("\"))
    
    $dataPaths = inlinescript
    {
        $dataPaths = Get-SCUserRole -VMMServer $Using:VmmServerName | %{ $_.UserRoleDataPath }
        
        $dataPaths
    } -PSComputer $VmmServerName –PSCredential $VmmCredential

    inlinescript
    {
        $ftpFolders = Get-ChildItem -Directory -Path $Using:vmmLib | %{ $($_.FullName + '\') }
        
        if ($Using:dataPaths -ne $null)
        {
            $diffList = $ftpFolders | ?{ $Using:dataPaths -notcontains $_ }
        }
        
        if ($diffList)
        {
            foreach ($diff in $diffList)
            {
                if ([String]::IsNullOrEmpty($diff))
                {
                    continue
                }
                Write-Output "Deleting $diff"
                Remove-Item -Recurse -Force -Confirm:$false -Path $diff
            }
        }
        else
        {
            Write-Output "Nothing to delete"
        }
    } –PSComputer $libServer –PSCredential $VmmCredential
}



Данные ранбуки необходимо импортировать, опубликовать, ранбуку «Notify-Created-User» присвоить тэг SPF и привязать к событию «Создать» объекта «SPF-клиент»:



Для ранбука «Cleanup-ftp-folder» необходимо создать расписание, чтобы он выполнялся раз в день:




Подготовка FTP


Необходимо, чтобы службы Framework 2.0/3.5 были предварительно установлены

С помощью диспетчера сервера добавляем роль FTP с поддержкой расширения:




Создаем FTP-сервер:



В качестве пути в мастере указываем физический путь к корню библиотеки подписчиков. Если FTP сервер разворачивается не на сервере библиотеки наилучшим выходом будет создание символической связи с общим ресурсом, например:
mklink /D C:\TenantsData \\vmmlibserver\TenantsData




На следующей странице мастера указываем дополнительные параметры (использование SSL, номер порта и т.д.):



На завершающей странице указываем, что все пользователи имеют право на чтение и запись, но не указываем поддерживаемые типы аутентификации:



На этом первоначальная настройка закончена. Остальные параметры будут указаны после установки модуля расширения.


Установка модуля расширения и настройка FTP


Скачайте приложенный к статье архив «Module.zip» и распакуйте (например, в «C:\Module»). Запустите интерпретатор cmd с правами администратора. Выполните следующие команды (если Ваш FTP называется по другому, укажите его имя в качестве параметра):



Получите следующий вывод:



После этого необходимо исправить файл «CustomFTPHomeDirectoryProvider.dll.config», указав там значения ключей «auth» и «root». Ключ «auth» содержит URL сайта TenantAuth, ключ «root» указывает физический путь к библиотеке подписчиков. Пример:

<configuration>
  <appSettings>
    <add key="auth" value="https://auth.azureline.ru" />
    <add key="root" value="C:\ProgramData\TenantsLibrary" />
  </appSettings>
</configuration>

После этого файл «CustomFTPHomeDirectoryProvider.dll.config» необходимо скопировать по физическому пути «C:\Windows\Microsoft.NET\assembly\GAC_MSIL\CustomFTPHomeDirectoryProvider\v4.0_1.0.0.0__a8ad38bd3b2a69ea».


Проверка настроек


Открываем консоль IIS Management, выбираем FTP-сайт, открываем настройку «FTP Authentication». Должен быть включен единственный провайдер аутентификации «CustomAuth»:



Открываем настройку «FTP User Isolation», убеждаемся, что включено «Custom»:



Данная настройка указывает уровень изоляции пользователя. При помощи кастомного провайдера подписчик «запирается» в собственном каталоге.
Теперь тестируем. Я использовал FTP-клиент входящий в FAR. Подключаемся:



Закачиваем файл:



После обновления библиотеки видим загруженный файл:



На портале Azure Pack этот образ теперь можно подключить:



Таким образом, практически без дополнительных усилий, как то, контроль дополнительных учетных записей в AD для доступа к FTP, получилась удобная для подписчика точка загрузки ISO- и VHD(X)-файлов.

Материалы (архивы с готовым модулем, исходниками и ранбуками) можно скачать по этой ссылке. На этом все, до новых встреч!

Комментарии (0)