image Привет, Хаброжители!

PowerShell — это язык для написания скриптов, инструмент, позволяющий программно управлять всем центром обработки данных. С его помощью можно создавать высокоэффективные и надежные системы автоматизации, пригодные для многократного использования и значительно повышающие производительность специалистов. Из этой книги вы узнаете, как проектировать, разрабатывать, организовывать и развертывать скрипты для автоматизации задач любого масштаба, от локальных серверов до корпоративных облачных платформ.

Вы узнаете, как создавать скрипты PowerShell для автоматизации локальных и облачных систем. Найдете советы по определению задач, которые стоит автоматизировать, по организации структуры скриптов и управлению ими, а также множество примеров кода с подробными пояснениями. Научитесь адаптировать уже готовые скрипты к новым условиям применения и упрощать работу специалистов не-технического профиля при помощи простых и понятных интерфейсов SharePoint.
Для кого эта книга
Эта книга предназначена для всех, кто знаком с PowerShell и хочет создавать системы автоматизации для применения в реальных условиях. Изложенные на этих страницах концепции пригодятся всем: от новичков до экспертов, но все-таки, чтобы польза от книги была максимальной, нужно иметь хотя бы некоторое представление о PowerShell: знать, как устанавливать модули, писать скрипты (.ps1), использовать основные конструкции, такие как условные операторы, сплаттинг (splatting) и циклы.
Структура книги
Книга состоит из 14 глав и разделена на три части. Каждая часть посвящена одной из ключевых концепций автоматизации.

Первая часть — это разговор о том, с чего начинается автоматизация:
  • В главе 1 мы посмотрим на PowerShell с точки зрения автоматизации, проверим и подготовим к работе нужные инструменты.
  • В главе 2 поговорим про организацию скриптов и модулей с возможностью их повторного использования.
Вторая часть — это сердце книги. В ней мы обсудим множество важных для автоматизации вопросов:
  • В главе 3 мы научимся запускать скрипты по графику и обсудим, какие особенности нужно учесть при написании кода для подобных операций.
  • В главе 4 будем работать с секретными данными, в том числе использовать хранилища паролей.
  • В главе 5 рассмотрим разные способы удаленного запуска PowerShell и как их применять в реальных условиях.
  • В главе 6 рассмотрим логику создания адаптивных скриптов, а также используем внешние данные для управления работой скрипта.
  • В главе 7 написанный нами скрипт будет взаимодействовать с бэкендом базы данных — удобная замена Excel- и CSV-файлов для хранения информации.
  • В главе 8 для выполнения скриптов и управления ими мы задействуем Azure и объединим многие из рассмотренных ранее концепций в единую платформу.
  • В главе 9 поговорим о взаимодействии PowerShell с другими инструментами. Например, о том, как создавать документы Word из PowerShell, осуществлять коммуникацию с веб API и даже о том, как вызывать скрипты, написанные на Python, и обмениваться данными между скриптами.
  • В главе 10 познакомимся с лучшими практиками автоматизации PowerShell.
Третья часть посвящена совместному использованию и обслуживанию скриптов:
  • В главе 11 мы используем SharePoint в качестве пользовательского интерфейса для скриптов PowerShell и поговорим о разработке скриптов для работы на устройствах конечных пользователей.
  • В главе 12 научимся применять GitHub для контроля за исходным кодом и предоставления доступа к скриптам другим разработчикам.
  • В главе 13 узнаем, как при помощи Pester проводить модульное и комплексное тестирование скриптов на соответствие сценариям, для которых они были созданы.
  • В главе 14 вернемся к написанному ранее скрипту и внесем в него изменения. Поговорим о том, что нужно учесть заранее, а также об автоматическом тестировании скриптов средствами GitHub.

УЧЕТНЫЕ ДАННЫЕ И БЕЗОПАСНЫЕ СТРОКИ В POWERSHELL


В прошлом, когда скрипты PowerShell работали только локально, а все серверы были подключены к одному домену Active Directory, проблем с аутентификацией не возникало. Достаточно было настроить планировщик заданий и запускать скрипт от лица определенного пользователя. Сегодня, в условиях гибридных кросс-платформенных систем, одному скрипту часто приходится подключаться к ресурсам из разных сред. В большинстве случаев при этом нужно передавать пароли, API-ключи и другие учетные данные. И чтобы не хранить их в виде текста в файлах и памяти, в PowerShell предусмотрены объекты SecureString и PSCredential.

Работу с ними мы подробно разберем в разделе 4.3, на примере проверки состояния баз данных. Сейчас же поговорим о том, что именно представляют собой эти объекты и почему они более безопасны.

Безопасные строки


При изменении стандартной строки PowerShell сначала создает в памяти ее копию. Поэтому даже при удалении переменной или присвоении ей значения null старые копии строки могут остаться в памяти. Экземпляры объекта SecureString работают по-другому: они хранятся в зашифрованном виде, а новых копий не создается. Шифрование защищает от риска получить строку путем анализа дампов памяти. Отсутствие копий гарантирует, что строка будет полностью уничтожена при удалении переменной или завершении процесса.

ПРИМЕЧАНИЕ Прежде чем перейти к разговору о безопасных строках, важно сказать, что их можно использовать только на Windows. В основе объекта SecureString — API .NET Framework API, а не .NET Core. Применять их на Linux и MaxOS технически возможно, но строки в памяти шифроваться не будут.

Создать экземпляр объекта SecureString можно двумя способами: при помощи командлетов ConvertTo-SecureString или Read-Host. Во втором случае в качестве параметра нужно указать AsSecureString. При этом поступит запрос на ввод значения, а введенная пользователем строка будет сохранена как безопасная:

$SecureString = Read-Host -AsSecureString
$SecureString
System.Security.SecureString

Командлет ConvertTo-SecureString с параметром AsPlainText преобразует стандартную строку в безопасную. Однако нужно помнить, что эта строка уже хранится в памяти, а значит, такой подход не столь безопасен, как Read-Host. Если включить в скрипт текстовую строку, она может попасть в журнал событий или остаться в истории PowerShell. Поэтому в подтверждение того, что разработчик понимает все риски, командлет требует использования параметра Force:

$String = "password01"
$SecureString = ConvertTo-SecureString $String -AsPlainText -Force
$SecureString
System.Security.SecureString

Возникает вопрос, для чего тогда нужен командлет ConvertTo-SecureString. Есть несколько сценариев, когда его применение оправданно. Чаще всего он полезен, когда скрипт нужно переносить на другие машины. По умолчанию алгоритм шифрования SecureString использует данные о пользователе и устройстве. Попытка экспортировать безопасную строку на одном компьютере, а затем импортировать ее на другой ни к чему не приведет. Однако можно заменить ключ по умолчанию пользовательским ключом, а затем с его помощью расшифровывать строки на других машинах. Конечно, такие ключи требуют защиты, ведь их утечка позволит прочесть все объекты SecureString.

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

Объект учетных данных


Для хранения учетных данных в PowerShell предусмотрен объект PSCredential. Он включает стандартную строку для имени пользователя и безопасную строку для пароля. Как и в случае SecureString, создать экземпляр PSCredential можно двумя способами.

Первый из них — командлет Get-Credential, который предложит пользователю ввести учетные данные:

$Credential = Get-Credential

Второй способ — создать экземпляр PSCredential вручную, объединив обычную строку с именем и объект SecureString с паролем. При этом незащищенные копии этих строк останутся в памяти. Впрочем, как мы увидим в разделе 4.4, если использовать встроенное хранилище Jenkins, у таких копий есть применение:

$Username = 'Contoso\BGates'
$Password = 'P@ssword'
$SecureString = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential $Username,
➥ $SecureString

Объекты PSCredential можно использовать только в системах и командах, которые их поддерживают, в том числе передавать командлетам PowerShell в качестве параметров. При работе с системами, где такая поддержка отсутствует, можно преобразовать PSCredential в объект .NET NetworkCredential. Например, такой подход применим при подключении к базам данных и веб-приложениям, а также при базовой, дайджест-, NTLM- и Kerberos-аутентификации:

$Username = 'Contoso\BGates'
$Password = ConvertTo-SecureString 'Password' -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential $Username,
➥ $Password
$NetCred = $Credential.GetNetworkCredential()
$NetCred
UserName    Domain
--------    ------
BGates      Contoso

ПРИМЕЧАНИЕ Объект NetworkCredential содержит текстовый пароль. Однако при закрытии сеанса PowerShell пароль удаляется из памяти.

ХРАНЕНИЕ УЧЕТНЫХ ДАННЫХ И БЕЗОПАСНЫХ СТРОК В POWERSHELL


Как проще всего вызвать спор на любом форуме PowerShell? Спросить пользователей, как хранить пароли для скриптов. Вам тут же предложат десяток различных способов, и каждый из них немедленно будет раскритикован. Эта дискуссия стала еще оживленнее после выхода PowerShell Core, когда оказалось, что SecureString применяются только в Windows.

К счастью, усердный труд разработчиков PowerShell привел к созданию модуля SecretManagement, который позволяет хранить учетные и другие секретные данные в разных хранилищах паролей. Мы установим этот модуль и будем его применять как в примере с проверкой состояния баз данных, так и в других скриптах при необходимости.

Модуль SecretManagement


Модуль SecretManagement представляет собой механизм для доступа к разным хранилищам, в том числе к Azure Key Vault, KeePass, LastPass и многим другим. Модуль взаимодействует с ними при помощи специальных команд. Поэтому можно в любой момент перейти на другое хранилище без необходимости обновлять скрипты. Кроме того, можно работать с несколькими хранилищами одновременно. Принцип работы модуля SecretManagement показан на рис. 4.3.

Кроме того, специально для модуля SecretManagement разработчики PowerShell и Microsoft создали хранилище паролей — модуль SecretStore. Работать с ним не обязательно: при наличии модуля-расширения можно использовать любое другое хранилище. Полный список хранилищ, поддерживаемых модулем SecretManagement, приведен в каталоге PowerShell.

image

Рис. 4.3. Модуль SecretManagement и работа с хранилищами

ПРИМЕЧАНИЕ На данный момент в версии 1.0.0 в основу модуля SecretManagement положены объекты SecureString. Поэтому его рекомендуется применять только на Windows. Он будет работать на Linux и macOS, но менее безопасно из-за отсутствия шифрования строк.

Модуль SecretManagement — это прослойка между скриптом и хранилищем, которая не требует особой настройки. Достаточно просто установить этот модуль. Однако необходимо настроить хранилище паролей и зарегистрировать его в SecretManagement.

Настройка хранилища SecretStore


Хранилище SecretStore — отличный способ познакомиться с модулем SecretManagement. У него есть большой недостаток: хранилище всегда привязано к пользователю и компьютеру, а значит, его нельзя переместить на другую систему либо использовать совместно с другими. Однако создать такое хранилище можно за считаные минуты. Чтобы увидеть, как это просто, настроим модули SecretStore и SecretManagement. В дальнейшем мы будем использовать их при проверке состояния баз данных.

Установка модулей


Прежде всего установим эти два модуля. Оба они доступны в каталоге PowerShell, поэтому можно использовать команду PowerShellGet:

Install-Module Microsoft.PowerShell.SecretStore
Install-Module Microsoft.PowerShell.SecretManagement

Настройка хранилища SecretStore


После установки модулей нужно создать хранилище SecretStore. Для этого предназначен командлет Get-SecretStoreConfiguration. При первой настройке SecretStore понадобится ввести пароль для доступа к хранилищу:

Get-SecretStoreConfiguration
Creating a new Microsoft.PowerShell.SecretStore vault. A password is required
➥ by the current store configuration.
Enter password:
********
Enter password again for verification:
********
      Scope Authentication PasswordTimeout Interaction
      ----- -------------- --------------- -----------
CurrentUser       Password             900      Prompt

Здесь нужно поговорить о пароле и связанных с ним трудностях. Пароль делает хранилище более защищенным. Однако из-за потребности вводить его скрипт не может выполняться автоматически. И здесь на помощь приходит тот факт, что хранилище связано с устройством и пользователем.

Поскольку наш скрипт должен работать без участия пользователя, пароль следует отключить. При этом также полезно добавить параметр Interaction со значением none. В этом случае, если впоследствии ввод пароля станет вдруг вновь обязательным, будет выдано исключение и скрипт прекратит работу вместо зависания и ожидания ответа от пользователя.

Итак, отключим ввод пароля и избавимся от необходимости взаимодействовать с пользователем при помощи командлета Set-SecretStoreConfiguration:

Set-SecretStoreConfiguration -Authentication None -Interaction None
Confirm
Are you sure you want to perform this action?
Performing the operation "Changes local store configuration" on target "Secre
➥tStore module local store".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (defaul
➥t is "Y"): y
A password is no longer required for the local store configuration.
To complete the change please provide the current password.
Enter password:
********

После отключения пароля учетная запись и компьютер с хранилищем становятся зоной уязвимости. Поэтому нужно принять меры дополнительной защиты, в том числе придумать сложный пароль и наблюдать за активностью учетной записи и компьютера.

Регистрация хранилища


Предыдущие шаги касались настройки хранилища SecretStore. Но для того чтобы SecretManagement знал, где искать секретные данные, это хранилище нужно зарегистрировать. Передадим его имя, а также название модуля-расширения в качестве параметров командлета Register-SecretVault. Имя хранилища в дальнейшем будет указываться в скрипте.

Создадим для нашего примера хранилище с именем SQLHealthCheck:

Register-SecretVault -ModuleName Microsoft.PowerShell.SecretStore -Name SQLHe
➥althCheck

Модуль SecretStore может работать с несколькими хранилищами в одном профиле. Эта возможность полезна для организации паролей и управления ими. Для доступа к некоторым хранилищам потребуется дополнительный параметр VaultParameters, но так как модуль привязан к устройству и пользователю, дополнительные настройки не требуются.

Настройка хранилища по умолчанию

Модуль SecretManagement позволяет назначить хранилище по умолчанию и получать доступ к данным без указания имени. Такая настройка очень удобна для личного применения, но не рекомендуется при автоматизации. Во избежание сбоев, вызванных изменением хранилища по умолчанию, следует явно указывать имя хранилища.

Настройка хранилища KeePass


Как уже говорилось, модуль SecretManagement может работать с хранилищами разных типов. Их более десяти. Рассмотрим настройку хранилища KeePass — бесплатного менеджера паролей с открытым кодом. В отличие от таких решений, как, например, LastPass и Azure Key Vault, оно работает полностью автономно.

В отличие от SecretStore, в хранилище KeePass данные помещаются в файл БД, который легко перенести на другой компьютер и даже поместить в сетевую папку для совместного использования. Как и в SecretStore, здесь можно отключить ввод пароля, что удобно для систем автоматизации. Для повышения уровня защиты в KeePass также можно использовать пользовательские ключи.

Устанавливать KeePass на компьютер, чтобы использовать расширение, не обязательно. Модуль расширения содержит все необходимое для доступа к файлу базы данных. Однако для создания файла базы данных потребуется установка KeePass.

Создание хранилища KeePass


Как и в случае с SecretStore, настраивая базу данных KeePass для работы через SecretManagement, необходимо подумать о доступе к хранилищу. Для автоматической работы скриптов следует отключить мастер-пароль. При этом также рекомендуется использовать файл ключа.

Файлы ключей обеспечивают дополнительную защиту хранилища KeePass. Их можно использовать для доступа вместо паролей. Поскольку файл с данными не привязан к конкретной машине, он может попасть в руки злоумышленников, но принесет мало пользы: для его чтения нужен файл ключа. Но если доступ к данным можно получить только по файлу ключа, необходимо принять меры предосторожности. Оба файла должны находиться в надежных местах, недоступных для неавторизованных пользователей. И главное — не хранить их друг с другом.

Итак, установим KeePass, создадим файл БД SmtpKeePass.kdbx и файл ключа SmtpKeePass.keyx для доступа к нему. В процессе работы с мастером New Database (Новая база данных) необходимо снять флажок Master Password (Мастер-пароль) и нажать кнопку Show Expert Options (Показать расширенные функции), чтобы создать файл ключа. Более подробно эти процессы описаны на сайте keepass.info.

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


Теперь, когда система KeePass и хранилище готовы к работе, нужно установить модуль KeePass, который расширяет возможности SecretManagement и дает доступ к KeePass из PowerShell:

Install-Module SecretManagement.KeePass

Регистрация хранилища KeePass


Последний этап — регистрация нового хранилища в модуле SecretManagement. Снова используем командлет Register-SecretVault, но в этот раз с другими параметрами: для каждой системы они свои. В случае с KeePass нужно указать пути к файлу БД и файлу ключа, а также запретить запрос мастер-пароля.

Запустим командлет Register-SecretVault, чтобы зарегистрировать только что созданный файл БД SmtpKeePass. В параметре Path передаем полный путь к файлу SmtpKee-Pass.kdbx, в параметре KeyPath — полный путь к файлу ключа SmtpKeePass.keyx, а в параметре UseMasterPassword — значение false:

$ModuleName = 'SecretManagement.KeePass'
Register-SecretVault -Name 'SmtpKeePass' -ModuleName $ModuleName -VaultParame
➥ ters @{
   Path = " \\ITShare\Automation\SmtpKeePass.kdbx"
   UseMasterPassword = $false
   KeyPath= "C:\Users\svcacct\SmtpKeePass.keyx"
}

Теперь, когда оба хранилища созданы и зарегистрированы, для доступа к ним и получения данных можно использовать команды для модуля SecretManagement и любых других связанных с ним хранилищ.

Выбор подходящего хранилища


Выбор хранилища зависит от требований проекта. Например, SecretStore всегда привязано к одному пользователю и компьютеру, что повышает уровень безопасности, но затрудняет переносимость скриптов. В KeePass таких ограничений нет, поэтому хранилище легко перенести на другой компьютер. Однако файл данных более уязвим и может быть скомпрометирован при недостаточной защите.

Одно из преимуществ модуля SecretManagement — возможность работы с разными хранилищами на стороне сервера. Поэтому можно использовать несколько хранилищ одновременно, как показано на рис. 4.4.

image

Рис. 4.4. Применение модуля SecretManagement в скрипте для проверки состояния баз данных

В нашем примере KeePass послужит хранилищем учетных данных, необходимых для отправки сообщений, а SecretStore — данных, необходимых для входа на SQL-сервер. Причина такого решения в том, что отправка сообщений может понадобиться и в других средствах автоматизации.

Если для каждого скрипта, требующего отправки сообщений, создавать новую учетную запись, со временем их может стать слишком много и ими не получится эффективно управлять. К тому же возникнут трудности с обновлением: любые изменения на SendGrid потребуют изменений во всех местах, где хранится пароль. Эти проблемы легко решить с помощью сетевого хранилища: если учетные данные будут находиться только в одном месте, изменить их не составит труда. Более того, все отправляющие сообщения скрипты обновятся одновременно. В то же время наличие отдельного хранилища с информацией об SQL-подключении обеспечивает дополнительный уровень безопасности: если какое-то хранилище будет взломано, на остальные части процесса автоматизации это не повлияет.

Добавление данных в хранилище


Когда все хранилища будут настроены и зарегистрированы, можно поместить в них необходимые данные. Для этого служит командлет Set-Secret со следующими параметрами:
  • Name — Имя секретных данных (секретов). Оно понадобится для их получения.
  • Vault — Имя хранилища данных. Если оно не указано, используется имя по умолчанию.
  • Secret — Объект, содержащий секреты. Поддерживаются объекты следующих типов:
    • byte[]
    • String
    • SecureString
    • PSCredential
    • Hashtable
Секреты нужно передавать только в параметре Secret. Важно упомянуть, что, если в хранилище уже есть данные с указанным именем, они будут перезаписаны. Чтобы этого не случилось, при вызове Set-Secret нужно добавить переключатель NoClobber.

Параметры, необходимые для скрипта из примера, приведены в табл. 4.1.

Таблица 4.1. Секреты, необходимые для работы скрипта проверки состояния баз данных

image

Перечисленные значения используются по умолчанию в настраиваемом скрипте из репозитория на GitHub.

Необходимо загрузить секреты в оба хранилища — SecretStore и KeePass. Начнем с SecretStore: создадим объект PSCredential с именем и паролем для подключения к SQL-серверу и объект SecureString с именем этого сервера. Затем поместим в KeePass API-ключ для работы с SendGrid.

Именование связанных секретов

При наличии нескольких связанных друг с другом секретов (как, например, в нашем скрипте) их имена должны иметь общий префикс. Это не только сделает код более понятным, но и позволит упростить параметры: мы сможем передавать только префикс, к которому затем добавлять нужные суффиксы.

Например, чтобы получить данные для доступа к SQL-серверу (см. табл. 4.1), достаточно передать слово TestSQL, а затем добавить к нему слово Credential:

$SqlName = 'TestSQL'
$SqlCred = "$($SqlName)Credential"

То же самое можно сделать с учетными данными для доступа к SendGrid: добавить Key в конец имени.

Создадим записи в хранилище SecretStore:

$SQLServer = "$($env:COMPUTERNAME)\SQLEXPRESS"
Set-Secret -Name TestSQL -Secret $SQLServer -Vault SQLHealthCheck
$Credential = Get-Credential
Set-Secret -Name TestSQLCredential -Secret $Credential -Vault SQLHealthCheck

Создадим записи в хранилище KeePass:

$SmtpFrom = Read-Host -AsSecureString
Set-Secret -Name SendGrid -Secret $SmtpFrom -Vault SmtpKeePass
$Credential = Get-Credential
Set-Secret -Name SendGridKey -Secret $Credential -Vault SmtpKeePass

Теперь, когда все секреты находятся в хранилищах, можно написать код для их получения.

РАБОТА С УЧЕТНЫМИ ДАННЫМИ И БЕЗОПАСНЫМИ СТРОКАМИ


Как можно заметить, использование модуля SecretManagement для получения секретных данных — простой и удобный процесс. Однако существуют и другие варианты хранения и предоставления секретных данных. Многие популярные платформы автоматизации и платформы CD/CI имеют способы безопасной и надежной передачи учетных данных и других значений скриптам. В нашем примере мы будем использовать сначала модуль SecretManagement, а затем Jenkins с его встроенным хранилищем.

Модуль SecretManagement


После настройки и регистрации хранилищ в модуле SecretManagement можно использовать их для получения секретов в скриптах. При этом нужно помнить, что конфигурации задаются в профиле пользователя, поэтому при настройке хранилища нужно войти в систему как пользователь, который будет иметь к нему доступ. Затем нужно убедиться, что скрипт запускается от имени этого пользователя. Мы говорили об этом в главе 3.

Чтобы получить секреты, достаточно воспользоваться командлетом Get-Secret. Он возвращает первую запись, которая соответствует указанному имени. Вот почему важно проверить, что все секреты имеют уникальные имена, а также использовать параметр Vault. В его отсутствие модуль SecretManagement выполнит поиск по всем хранилищам, начиная с того, которое используется по умолчанию.

По умолчанию строковые секреты возвращаются в виде объектов SecureString. Однако если необходимо, их можно получить в виде обычного текста. Для этого используется переключатель AsPlainText.

Как мы увидим в нашем примере, в скрипте можно использовать любое сочетание хранилищ и секретов. В скрипте из примера нам нужно получить данные для подключения к SQL-серверу из одного хранилища, а данные для подключения к SendGrid — из другого. Кроме того, имя SQL-сервера и адрес электронной почты должны быть получены в виде обычного текста (используем переключатель AsPlainText). Протестируем подключение к SQL-серверу и SendGrid по отдельности.

Начнем с SQL-сервера (листинг 4.1). Получим нужные для подключения данные из хранилища SecretStore, а затем выполним простой запрос к серверу при помощи командлета Invoke-DbaDiagnosticQuery. Если свойство Results возвращенного командлетом объекта содержит данные, можно считать, что запрос выполнен. Если данные в свойстве Results отсутствуют, нужно изучить сообщение вывода: оно будет содержать описание проблем с разрешениями, если они возникнут. В таком случае можно попробовать изменить права доступа к серверу и повторить запрос.

image

Теперь протестируем код для отправки электронных сообщений через SendGrid. Как показано в листинге 4.2, для этого используется командлет Send-EmailMessage. При этом необходимые для доступа API-ключ и адрес электронной почты мы получим из хранилища KeePass. Если отправленное сообщение дошло до указанного адреса, можно перейти к объединению обеих частей кода в единый скрипт.

image

Убедившись, что отправка диагностического запроса к SQL-серверу и электронных сообщений работает, можно объединить два фрагмента в единый скрипт. Для этого сначала нужно получить имена хранилищ и секретных данных в параметрах, чтобы скрипт можно было использовать для работы с разными экземплярами SQL. Поскольку имена связанных секретов имеют одинаковые префиксы, достаточно запросить префикс и добавить к нему нужные суффиксы. Таким образом, вместо двух параметров (секрета экземпляра SQL и секрета с учетными данными) нам понадобится только один: для префикса. Скрипт добавит к нему слово Credential. Аналогичный подход используем для API-ключа SendGrid: добавляем к префиксу слово Key. Наконец, нам понадобится параметр для адреса электронной почты, на который в случае неудачной проверки будет отправлено сообщение.

Далее скрипт получает данные для подключения к SQL-серверу из хранилища, а затем запрашивает свойства базы данных при помощи командлета Invoke-DbaDiagnosticQuery. Среди этих свойств — нужные нам сведения о модели восстановления баз данных. Скрипт проверяет, что используется модель восстановления SIMPLE. Если это не так, скрипт формирует текст для электронного сообщения и отправляет его, получив из хранилища параметры, необходимые для доступа к SendGrid. Текст сообщения представляет собой HTML-таблицу с указанием сведений о базах данных, не прошедших проверку. Полный код скрипта приведен на следующем листинге.

image

image

Работа с учетными данными Jenkins


До появления модуля SecretManagement лучшим способом хранения учетных данных были сторонние платформы с собственными хранилищами. Одной из таких платформ является Jenkins. Поэтому в скриптах, выполняемых при помощи Jenkins, можно использовать как модуль SecretManagement, так и встроенное в эту платформу хранилище.

Одно из преимуществ Jenkins состоит в том, что при ее использовании не придется беспокоиться об установке хранилищ и модулей расширения на каждом сервере Jenkins. Все они смогут получать учетные данные из одного глобального хранилища. Кроме того, платформа имеет графический интерфейс, а также поддерживает функции регистрации доступа к различным объектам.

По умолчанию используется одно хранилище с именем Jenkins. Однако можно настроить несколько хранилищ и даже доступ к ним на основе ролей. Но в нашем примере мы ограничимся хранилищем по умолчанию.

Обновим созданный ранее скрипт для проверки состояния баз данных так, чтобы использовать учетные данные и переменные Jenkins вместо хранилищ SecretManagement.

Чтобы создать учетные данные в Jenkins, нужно перейти в меню Manage Jenkins > Manage Credentials (Управление Jenkins > Управление учетными данными), а затем щелкнуть на нужном хранилище. В данном случае оно будет называться Jenkins. Перейдя в хранилище, нужно нажать Global Credentials (Глобальные учетные данные) и создать объекты с учетными данными, указанные в табл. 4.2.

Таблица 4.2. Секреты, необходимые для проверки состояния баз данных при помощи Jenkins

image

* Перечисленные значения используются по умолчанию в настраиваемом скрипте из репозитория на GitHub.

Настроив все необходимые секреты, можно использовать их в скриптах. Однако перед этим нужно выполнить несколько подготовительных действий. Jenkins использует собственные методы хранения секретов, а потому поддерживает объекты SecureString и PSCredential напрямую. Поэтому во время выполнения значения секретов загружаются в переменные среды как обычные небезопасные строки. В Jenkins предусмотрены специальные средства, позволяющие предотвратить попадание этих переменных в логи, а также их хранение в памяти. Поэтому, чтобы преобразовать секреты в объекты SecureString или PSCredential, необходимо конвертировать их из стандартных строк при помощи командлета ConvertTo-SecureString.

В нашем скрипте нужно будет заново создать учетные данные для подключения к SQL-серверу и API-ключ для SendGrid. Адрес электронной почты и экземпляр SQL преобразовывать не нужно, так как они и должны быть небезопасными строками.

Сначала создадим в Jenkins новый проект Freestyle. Затем в разделе Binding (Привязка) свяжем с ним переменные для имени пользователя и пароля, после чего настроим их согласно табл. 4.3.

Привяжем также переменные для секретного текста и настроим их согласно табл. 4.4.

Таблица 4.3. Связь учетных данных, необходимых для проверки состояния баз данных, с Jenkins

image

Таблица 4.4. Связь секретных текстов, необходимых для проверки состояния баз данных, с Jenkins
image

Наконец, обновим сценарий для проверки состояния баз данных, заменив обращения к хранилищам SecretManagement на переменные среды Jenkins. Код скрипта приведен в следующем листинге. Не забудем, что нужно заново создать учетные данные.

image

image

Чтобы сделать скрипт динамическим и запускать его на разных SQL-серверах, достаточно заменить привязки нужных учетных данных параметрами. Это позволит вводить учетные данные при выполнении скрипта.

ПОНИМАНИЕ РИСКОВ


На протяжении всей главы мы видели, что при создании автоматических скриптов всегда существуют уязвимости. Однако, зная, в чем они заключаются, можно уменьшить связанные с ними риски. К сожалению, многие компании настолько боятся этих уязвимостей, что фактически блокируют развитие автоматизации. Поэтому вам нужно уметь объяснить, в чем именно заключаются риски и какие действия предприняты для их снижения.

В нашем примере мы снизили риски, используя несколько способов. Во-первых, мы создали специальную учетную запись для доступа к SQL-серверу с минимально необходимыми правами, а также отдельный API-ключ для подключения к SendGrid. Мы отказались от хранения секретных данных в скриптах, применив вместо этого модуль SecretManagement и хранилище учетных данных Jenkins.

Однако даже значительно сократив количество уязвимостей, мы не смогли избавиться от всех рисков. И мы должны знать и учитывать эти риски. Например, злоумышленник может скопировать хранилище KeePass, а затем открыть его на своем компьютере. Но если использовать файл ключа и хранить его в отдельном защищенном месте, хранилище открыть не удастся. Также необходимо убедиться, что доступ к файлу ключа есть только у отдельных, уполномоченных пользователей.

Кроме того, применяя SendGrid вместо SMTP-релея, можно еще повысить уровень безопасности. Например, можно разрешить доступ только с определенных IP-адресов, просматривать логи и рассылать оповещения об аномальной активности. Благодаря этому, даже если злоумышленник скопирует KeePass и получит файл ключа, он не успеет ничего сделать.

Еще одна возможная уязвимость, которая требует внимания, заключается в том, что Jenkins передает в PowerShell секретные данные в виде небезопасных строк. Однако в Jenkins встроена защита, которая предотвращает их запись в любой выходной поток, а сеанс PowerShell завершается с полной очисткой памяти сразу после выполнения скрипта. Поэтому получить эти данные можно только одним способом: сделать дамп памяти во время работы скрипта. И если у злоумышленника есть такая возможность, утечка пароля — не самая значительная проблема.

Во всех перечисленных случаях нам удалось снизить риски, сопровождающие применение автоматических скриптов автоматизации. Конечно, даже физическое отключение от сети и вооруженный охранник рядом с компьютером не гарантируют полную защиту системы — и ни один специалист по безопасности не должен рассчитывать на это. Однако мы должны предпринимать все возможное, чтобы минимизировать риски. По своему опыту я могу сказать, что залог получения разрешений, необходимых для внедрения систем автоматизации, — честный и открытый диалог с командой по безопасности.

ИТОГИ
  • Организация доступа на основе ролей, предоставление минимальных полномочий, отказ от STO как единственного средства защиты, а также другие базовые принципы позволяют обеспечить безопасность скриптов автоматизации.
  • Объекты PowerShell SecureString и PSCredential можно использовать для защиты чувствительных данных во время выполнения и хранения скрипта.
  • Модуль SecretManagement может работать с несколькими хранилищами паролей одновременно, что позволяет организовать безопасное хранение и доступ к чувствительным данным.
  • Многие платформы имеют встроенные хранилища, которые могут заменить модуль SecretManagement.
  • Понимание имеющихся рисков помогает снизить их до приемлемого уровня.
Об авторе
Мэтью Доуст — управляющий консультант и ведущий архитектор в группе управляемой автоматизации компании Quisitive (ранее Catapult Systems). Последние десять лет он активно работает с PowerShell, помогая малому и крупному бизнесу в автоматизации насущных производственных задач. Кроме того, Мэтью принимает активное участие в жизни сообщества PowerShell: ведет блоги, работает над авторскими модулями, выступает на онлайн-форумах. Он также является автором рассылки PowerShell Weekly — еженедельного обзора новостей о PowerShell.

Более подробно с книгой можно ознакомиться на сайте издательства:

» Оглавление
» Отрывок

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — PowerShell

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


  1. Yuriy_krd
    13.08.2024 14:51
    +1

    "Питер", вы продаете книгу из будущего ?) у вас на сайте год издания - 2025 :)


    1. IMnEpaTOP
      13.08.2024 14:51

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


  1. rendov
    13.08.2024 14:51

    Обожаю эти старинные иллюстрации, на обложках вашего издательства. До сих пор улыбаюсь, когда взгляд цепляет эту книгу на полке:

    Linux: Системное программирование
    Новая летающая машина Эйреса
    Новая летающая машина Эйреса


  1. ilkman
    13.08.2024 14:51

    Скачать где ссылка млять. Заипался листать, не увидел. Трекер?


    1. sovid
      13.08.2024 14:51

      Чувак иди проспись


  1. SirSpite
    13.08.2024 14:51

    Заказал в бумаге, судя по статье про секреты - заманчиво, вероятно можно что-то интересное почерпнуть, да и оригинал вроде только в прошлом году вышел - свежак.

    Отдельное спасибо за промокод - неплохая скидка получилась