При автоматизации различных процессов посредством PowerShell мне очень часто приходится производить авторизацию в какой-нибудь системе. При этом, для каждой системы используются свои наборы логинов и паролей. Когда количество скриптов, выполняющих работу было не велико, не возникало и особых проблем. Несколько паролей я шифровал такой командой:
$PlainPassword | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString |
и хранил в реестре. Зашифрованный таким образом пароль был доступен для расшифровки только той же учетной записи из под которой он был зашифрован. Но большую часть паролей приходилось хранить также в реестре в открытом виде, так как эти пароли иногда нужны не только скриптам PowerShell, но и мне лично.
С ростом числа скриптов и автоматизируемых процессов встал вопрос, как хранить пароли, чтобы это было безопасно, удобно и бесплатно. Мой коллега нашел менеджер паролей, который называется KeePass и позволяет удобно работать с паролями как вручную, так и из PowerShell. Он удовлетворяет всем требованиям, которые мы предъявляем к менеджеру паролей.
Ну и самое главное. Как же посредством PowerShell получить доступ к паролям? Чтобы открыть базу KeePass я также использую пароль, поэтому надо сохранить этот пароль в кусте реестра HKCU моей учетной записи (зашифрованный таким образом пароль сможет расшифровать только моя учетная запись):
Function Set-PasswordEncrypted() { <# .SYNOPSIS Эта функция шифрует пароль и сохраняет в реестр для последующего получения функцией Get-PasswordFromKeePass. .DESCRIPTION Эта функция сохранит пароль, зашифрованный таким образом, что пароль сможет расшифровать только текущая учетная запись, в кусте реестра HKCU текущей учетной записи. Пароль в последующем может быть использован функцией Get-PasswordFromKeePass. .PARAMETER Name Имя пароля, необходимо для последующего извлечения этого пароля из реестра. .PARAMETER PlainPassword Пароль в виде нешифрованного текста. .EXAMPLE Set-PasswordEncrypted -Name 'saqwel' -PlainPassword 'P@ssw0rd' #> param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] [string]$Name, [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] [string]$PlainPassword ) $SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString $RegPath = "HKCU:\Software\Passwords" if(!(Test-Path -Path $RegPath)) { New-Item -Path $RegPath -Confirm:$false -Force -ErrorAction Stop | Out-Null } New-ItemProperty -Path $RegPath -Name $Name -Value $SecurePassword -Force -ErrorAction Stop | Out-Null } |
Ниже функция, которая возвращает логин и соответствующий ему пароль из KeePass. Подроности его работы в комментариях к коду.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | Function Get-PasswordFromKeePass() { <# .SYNOPSIS Эта функция возвращает логин и пароль запрашиваемой записи из базы данных KeePass. .DESCRIPTION Эта функция помогает получить любой пароль из базы данных KeePass, зная имя записи и родительской группы, в которой хранятся логин и пароль. Пояснение. В KeePass можно создавать группы (или папки), которые и надо наполнять данными. Эти группы называются ParentGroup. Для получения пароля надо знать не только имя записи, в которой хранится требуемый пароль, но и имя родительской группы, где хранится запись. Мы разбили все пароли по принадлежности к операционке. Для использования этой функции необходимо зашифровать пароль и поместить в реестр командлетом Set-PasswordEncrypted. .PARAMETER UserName Имя записи, в которой хранится логин и пароль. Имя записи может совпадать или не совпадать с логином. .PARAMETER ParentGroupName Группа в базе данных KeePass, в которой находится запись, хранящая пароль. .EXAMPLE Get-PasswordFromKeePass -UserName 'MegaAdmin' -ParentGroupName 'Windows' .EXAMPLE Get-PasswordFromKeePass -UserName 'MegaRoot' -ParentGroupName 'Linux' #> param( [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] [string]$UserName, [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] [string]$ParentGroupName ) # Пароль от KeePass хранится в кусте реестра $RegPath = "HKCU:\Software\KeePass" # Параметр, который хранит зашифрованный пароль - KeePassPassword $Encrypted = (Get-ItemProperty -Path $RegPath).KeePassPassword # Перед расшифровшкой пароля надо его конвертировать $SecureString = $Encrypted | ConvertTo-SecureString # Получить пароль готовый для открытия базы паролей KeePass $KeePass = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)) # Загрузить класс из KeePass.exe: [Reflection.Assembly]::LoadFile('C:\Keepass\KeePass.exe') | Out-Null # Получить параметры, необходимые для подключения к базе KeePass $KcpUserAccount = New-Object -TypeName KeePassLib.Keys.KcpUserAccount $KcpPassword = New-Object -TypeName KeePassLib.Keys.KcpPassword($KeePass) $CompositeKey = New-Object -TypeName KeePassLib.Keys.CompositeKey $CompositeKey.AddUserKey( $KcpPassword ) # Требуется файл .KDBX для открытия базы данных KeePass $IOConnectionInfo = New-Object KeePassLib.Serialization.IOConnectionInfo $IOConnectionInfo.Path = 'C:\Keepass\gpikkit.kdbx' # Открыть базу данных, наконец-то $PwDatabase = New-Object -TypeName KeePassLib.PwDatabase $PwDatabase.Open($IOConnectionInfo, $CompositeKey, $Null) # Получить требуемый пароль $PwCollection = $PwDatabase.RootGroup.GetEntries($True) | Where{ $_.ParentGroup.Name -eq $ParentGroupName -and $_.Strings.ReadSafe("Title") -eq $UserName } $PwDatabase.Close() # Вернуть только один пароль и логин пользователя If($PwCollection.Uuid.Count -eq 1) { $Object = @{ Password = $PwCollection.Strings.ReadSafe("Password") UserName = $PwCollection.Strings.ReadSafe("UserName") } } else { $Object = $False } return $Object } |