Повторное использование логина и пароля в Powershell с Get-Credential и их шифрование


07 сентября 2020


Сохранение учетных данных и пароля с Get-Credential в файл с Powershell и их шифрование

При работе в Powershell вы часто используете другие учетные данные. Один из способов ввести учетные данные - это использовать команду Get-Credential, которая показывает диалоговое окно:

Ввод логина и пароля с Get-Credential в Powershell

Далее мы можем использовать эту переменную $cred в командах, как на примере ниже. Команда будет запущена от имени пользователя, который был указан в диалоговом окне выше:

Invoke-Command -ComputerName "localhost" `
-ScriptBlock {Get-ComputerInfo} `
-Credential $cred

Альтернативный способ использования - это совместить два действия описанные выше в одно:

Invoke-Command -ComputerName "localhost" `
-ScriptBlock {Get-ComputerInfo} `
-Credential $(Get-Credential)

Минусы описанных вариантов в том, что нам требуется вводить нужный логин и пароль каждый раз, когда мы запускаем Powershell (открываем/закрываем сессию). В этой статье будут рассмотрены несколько вариантов хранения учетных данных и их загрузка.

 

В чем особенность хранения учетных данных в Powershell?

Powershell не совсем очевидно хранит и обрабатывает введенный логин и пароль. После ввода логина и пароля создается объект PSCredential, в котором хранится логин (в обычном виде) и пароль в защищенном виде(называется SecureString). Этот объект хранится в оперативной памяти компьютера и что бы PSCredential (а точнее SecureString) мог быть выгружен - он должен быть зашифрован. Такое шифрование, в основном выполняется автоматически командами конвертации и экспорта. Например мы сможем выгрузить данные c Export-CliXML сразу, а с Export-CSV этого не получится.

Кроме этого, процесс создания SecureString и последующее шифрование уникальны для каждого компьютера и пользователя. Поэтому мы не сможем просто перенести этот файл на другой компьютер и использовать. Такой процесс работы с данными называется  Windows Data Protection API.

В статье будут рассмотрены большинство способов работы и переноса учетных данных.

 

Импорт и экспорт в XML

После ввода учетных данных мы получаем обычный объект, который будет выглядеть так:

Объект PSCredential в Powershell

Экспорт в XML мы можем выполнить с помощью следующей команды, которая выполнит шифрование пароля и сохранит данные в корне диска 'C':

$cred = Get-Credential
$cred | Export-CliXML -Path 'C:\mycredentials.xml'

Экспорт учетных данных Get-Credential и Export-CliXml в Powershell

На примере ниже можно увидеть, что логин пользователя не зашифрован, в отличие от пароля:

Файл с учетными данными в Powershell

Теперь мы можем загружать этот файл и использовать другие учетные данные без повторного ввода:

$cred = Import-CliXML -Path 'C:\mycredentials.xml'

Импорт учетной записи в Powershell с Import-CliXML

Мы можем конвертировать пароль из SecureString обратно в строку:

$cred = Import-CliXML -Path 'C:\mycredentials.xml'
$cred.GetNetworkCredential().Password

Преобразование PSCredential в пароль с Powershell

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

 

Импорт и экспорт пароля из обычного файла

В Powershell есть команда ConvertTo-SecureString, которая может преобразовывать обычные строки в объект SecureString. Результатом команды будет такой же объект, который был у команды Get-Credential , свойства 'Password':

'somepassword' | ConvertTo-SecureString -AsPlainText -Force

Получение из пароля объект SecureString в Powershell

Для того что бы безопасно сохранять эти данные в файл мы можем зашифровать их с помощью команды ConvertFrom-SecureString:

$sec_string = 'somepassword' | ConvertTo-SecureString -AsPlainText -Force
$sec_string | ConvertFrom-SecureString | Set-Content -Path 'C:\secure.txt'

Сохранение пароля в файл в Powershell

Результат команды выше будет та же строка, что была у пароля при выполнении команды Export-CliXML:

Мы можем открыть этот, и преобразовать зашифрованный пароль в объект SecureString:

$sec_string = Get-Content -Path 'C:\secure.txt' | ConvertTo-SecureString
# Получаем чистый пароль
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((($sec_string))))

Преобразование SecureString в пароль с Powershell

Создание объекта PSCredential

Любой ключ -Credential в командах ожидает получить объект PSCredential, а не просто пароль. Мы можем создать такой объект следующим способом:

# Логин
$login = 'admin@domain.local'
# Объявления пароля с последующем конвертированием в защищенную строку
$password = 'password123' | ConvertTo-SecureString -AsPlainText -Force
# Преобразование логина и пароля в специальный объект
$cred = New-Object system.Management.Automation.PSCredential($login,$password)

Создание учетных данных PSCredential из SecureString в Powershell

Т.е. с этим способом мы можем создать учетные данные в нужном формате, но для этого мы должны будем хранить файл с паролем в чистом виде.

 

Шифрование пароля используя симметричный ключ

Мы можем шифровать файл с паролем используя симметричное шифрование (AES). После шифрования вы сможете опубликовать пароль в открытой папке и выдавать права или предоставлять сам ключ шифрования.

С помощью следующей команды мы создадим симметричный ключ для последующего шифрования пароля:

$key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
$key | Out-File C:\powershell.key

Создание ключа шифрования AES в Powershell

Далее я создам SecureString (объект в оперативной памяти) что бы потом его зашифровать ключом созданным выше:

# Преобразуем пароль в Secure.String
$password = "Somepassword123!" | ConvertTo-SecureString -AsPlainText -Force
# Открываем файл с ключом AES
$key = Get-Content -Path "C:\powershell.key"
# Шифруем пароль
$secure_password = ConvertFrom-SecureString -Key $key -SecureString $password
# Сохраняем пароль в файл
Set-Content -Path 'C:\password.txt' -Value $secure_password

Теперь у нас есть 2 файла, с помощью которого мы можем организовывать доступ к паролю. Это файл:

  • powershell.key - ключ AES с помощью которого можно зашифровать файл и расшифровать;
  • password.txt - зашифрованная строка типа SecureString (пароль), который может быть расшифрован ключом выше.

Вы сможете перенести эти файлы на другой компьютер и выполнить следующую операцию для расшифровки:

# Открываем файл с зашифрованным паролем
$secure_password = Get-Content -Path "C:\password.txt"
# Расшифровываем объект в SecureString
$password = ConvertTo-SecureString -Key C:\Passwords\aes.key -String $secure_password
# Создаем объект PSCredential
$credential = New-Object System.Management.Automation.PsCredential("administrator@domain.local",$password)
# Можем убедиться, что пароль был расшифрован корректно
$credential.GetNetworkCredential().Password

 

Использование Credential Manager (Диспетчер учетных данных)

Многие знают, что пароли от сетевых дисков (и многие другие) хранятся в специальном месте под названием Credential Manager. В панели управления он выглядит так:

Диспетчер учетных данных в Windows

Мы можем получить доступ к этим объектам использовав модуль CredentialManager. Этот модуль не относится к стандартным и устанавливается отдельно:

Install-Module CredentialManager

У вас могут появится два уведомления говорящие об установке репозитория NuGet и о том, что он является не доверенным.

У нас станут доступны 4 команды:

  • Get-StoredCredential - получает учетные данные из хранилища;
  • Get-StrongPassword - генерирует случайный пароль;
  • New-StoredCredential - создает учетные данные;
  • Remove-StoredCredential - удаляет учетные данные.

Модуль диспетчера учетных данных в Windows Powershell

Далее мы сможем получить все учетные данные указав нужный тип в атрибуте Type или  Target (источник) которому эти данные принадлежат:

Get-StoredCredential -Target 'localhost'

Получение данных из диспетчера учетных данных Windows Powershell

Мы получаем объект типа PSCredential, который мы можем использовать в командах. Создавать новые учетные данные и добавлять их в хранилище CredentialManager мы тоже можем:

New-StoredCredential -Target 'localhost' -Type Generic -UserName 'admin@domain.local' -Password '123' -Persist 'LocalMachine'

Создание учетных данных в диспетчере Windows Powershell

Кроме логина и пароля мы указываем:

  • Target - кому принадлежит учетная запись. Проще говоря имя компьютера;
  • Type - тип учетной записи;
  • Persist - тип хранения. Может быть session (временной), localmachine (сохраненной) и enterprise(как я понимаю это тип перемещаемый, например с MS Passport).

Первые два пункта особого значения не имеют. Они предназначены для программ, которые получают пароли по определенным идентификаторам. В ваших скриптах вы выбираете идентификаторы для себя.

Так же у меня была ошибка 'New-StoredCredential : CredWrite failed with the error code 1312'. Эта ошибка проявляет себя только в удаленных сессиях PSSession. Если вы работаете локально - то она не проявляется. Причина ошибки и ее решение - пока не ясно (нет ответа на github).

Ошибка CredWrite failed with the error code 1312

 

Как загружать переменную с учетными данными при открытии Powershell

В Powershell есть возможность загружать переменные (и другие данные) при открытии самой консоли. Например мы сможем единожды объявить переменные '$credential_local', '$credential_domain', '$credential_forest' и каждый раз открывать консоль Powershell они сами будут импортироваться. 

Первое что нужно сделать - проверить существования файла 'Microsoft.PowerShell_profile.ps1', который является профилем Powershell. Путь до этого файла лежит следующей переменной (если работаете в сессии PSsession - ничего не вернется):

$profile

Профиль Powershell

Если этого файла нет - его нужно создать (c PS 6+ он должен создаваться автоматически):

New-item –type file –force $profile

Создание профиля Powershell для загрузки переменныхВ этот файл мы помещаем один из скриптов написанных выше:

# Логин
$login = 'admin@domain.local'
# Объявления пароля с последующем конвертированием в защищенную строку
$password = 'password123' | ConvertTo-SecureString -AsPlainText -Force
# Преобразование логина и пароля в специальный объект
$credential_domain = New-Object system.Management.Automation.PSCredential($login,$password)

Теперь, открывая консоль, вы всегда сможете вызвать эту переменную:

Загрузка профиля Powershell с переменными

...

Теги: #powershell


Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.