Глава 9. Практичный промежуток

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

Определение задачи

Прежде всего, мы предполагаем то вы работаете в любой операционной системе, исполняющей PowerShell 7.1 или выше. Данный пример, как мы предполагаем, может очень достойно работать и в более ранних версиях Windows PowerShell, но мы не проверяли этого.

В мире DevOps существует конкретный язык программирования, который всплывает почти всегда - помимо PowerShell, естественно. Это достаточно противоречивый язык среди ИТ- профессионалов и инженеров DevOps - люди либо обожают его, либо ненавидят. Вы догадались? Если вы предвидели YAML, вы угадали! YAML расшифровывается как "YAML ain’t markup language" (YAML не является языком разметки, то, что мы именуем рекурсивной аббревиатурой, когда сама аббревиатура содержит аббревиатуру), и хотя здесь говорится что это не так, во многих отношениях он похож на простой язык разметки - иначе говоря, это всего лишь файл с определённой структурой, точно так же как CSV и JSON обладают определённой структурой. Поскольку в мире DevOps мы наблюдаем большое число YAML, важно обладать инструментами для взаимодействия с YAML.

Поиск команды

Самый первый шаг в решении любой задачи состоит в том чтобы сообразить какая именно команда сделает это для вас. Ваши результаты могут отличаться от наших, в зависимости от того что у вас установлено, однако важен сам проходимый нами процесс. Поскольку мы знаем что вы желаете сопровождать какие- то виртуальные машины, мы начинаем с YAML в качестве ключевого слова:


PS C:\Scripts\ > Get-Help *YAML*
PS C:\Scripts\ >
		

Хм... Это не кажется полезным. Нет ничего. Ладно, давайте испробуем другой подход - на этот раз мы сосредоточимся на командах вместо файлов подсказок:


PS C:\Scripts\ > get-command -noun *YAML*
PS C:\Scripts\ >
		

Хорошо, нет никаких команд, чьи названия содержат YAML. Огорчение! Итак, нам придётся искать что может быть в Интернете в Галерее PowerShell:


PS C:\Scripts\ > find-module *YAML* | format-table -auto
Version Name            Repository Description
------- ----            ---------- -----------
0.4.0   powershell-yaml PSGallery  Powershell module for serializing...
1.0.3   FXPSYaml        PSGallery  PowerShell module used to...
0.2.0   Gainz-Yaml      PSGallery  Gainz: Yaml...
0.1.0   Gz-Yaml         PSGallery  # Gz-Yaml...
		

Многообещающе! Итак, давайте установим этот первый модуль:


PS C:\Scripts\ > install-module powershell-yaml 
You are installing the module(s) from an untrusted repository. If you
trust this repository, change its InstallationPolicy value by
running the Set-PSRepository cmdlet.
Are you sure you want to install software from
'https://go.microsoft.com/fwlink/?LinkID=397631&clcid=0x409'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend
[?] Help(default is "N"): y
		

Теперь, в этом месте вам следует быть осторожным. Хотя Microsoft и пользуется Галереей PowerShell, они не проверяют публикуемый другими код. Поэтому мы сделаем перерыв в своём процессе, просмотрим только что установленный код, и убедимся что он нам подходит, прежде чем продолжать. Также помогает и то, что автором данного модуля выступает коллега по MVP, Бо Прокс, а мы ему доверяем. Теперь давайте посмотрим на полученные нами команды:


PS C:\Scripts\ > get-command -module powershell-yaml | format-table -auto
CommandType Name              Version Source
----------- ----              ------- ------
Function    ConvertFrom-Yaml 0.4.0   powershell-yaml
Function    ConvertTo-Yaml   0.4.0   powershell-yaml
		

Отлично, это кажется простым. ConvertTo и ConvertFrom - выглядит как то что нам и требовалось.

Изучение использования команд

Если повезёт, его автор включил в свой модуль подсказку. Если когда- нибудь вы напишите модуль, всегда помните, что когда прочие парни будут его применять, скорее всего вам потребуется - нет, вам следует - включать в него подсказку, чтобы потребители вашего модуля знали как его применять. Если бы вы этого не сделали, это было бы похоже на отправку мебели IKEA без инструкции - не делайте этого! Имеется ещё одна книга под названием Learn PowerShell Toolmaking in a Month of Lunches (Manning, 2012), в которой два её автора, Дон Джонс и Джеффри Хикс, рассказывают, как писать модули и как размещать в них подсказку - а добавление подсказки, это именно то, что необходимо делать. Посмотрим, правильно ли поступил наш автор:


PS C:\Scripts\ > help ConvertFrom-Yaml
NAME
    ConvertFrom-Yaml
 
SYNTAX
    ConvertFrom-Yaml [[-Yaml] <string>] [-AllDocuments] [-Ordered] 
  ➥ [-UseMergingParser] [<CommonParameters>]
 
 
PARAMETERS
    -AllDocuments     Add-Privilege
		

Чёрт! Подсказки нет. Ну что же, в данном случае это не так уж плохо, потому как PowerShell помогает даже когда автор не написал никакой подсказки. PowerShell по- прежнему предоставляет вам синтаксис, параметры, вывод и псевдонимы - всего этого достаточно для обычной команды. Итак, нам требуется образец файла YAML... Ну что же, стоит воспользоваться интернет примером из репозитория GitHub PowerShell: https://raw.githubusercontent.com/PowerShell/PowerShell/master/.vsts-ci/templates/credscan.yml.

Это YAML файл Azure Pipelines, который команда PowerShell применяет для запуска CredScan - инструмента, применяемого для сканирования. когда в код были добавлены секреты или полномочия. Команда PowerShell обладает им настроенным для запуска всякий раз, когда некто отправляет запрос на извлечение (pull - синоним изменения кода) в репозиторий GitHub PowerShell с тем, чтобы его можно было бы немедленно перехватывать. Запуск задач во время запроса Pull - это обычная практика, носящая название непрерывной интеграции (CI, continuous integration).

Двинемся далее и выгрузим этот файл, и давайте считаем это файл из PowerShell:


PS C:\Scripts\ > Get-Content -Raw /Users/travis/Downloads/credscan.yml
parameters:
  pool: 'Hosted VS2017'
  jobName: 'credscan'
  displayName: Secret Scan
 
jobs:
- job: ${{ parameters.jobName }}
  pool:
    name: ${{ parameters.pool }}
 
  displayName: ${{ parameters.displayName }}
 
  steps:
  - task: securedevelopmentteam.vss-secure-development-tools.build-task
  ➥ -credscan.CredScan@2
    displayName: 'Scan for Secrets'
    inputs:
      suppressionsFile: tools/credScan/suppress.json
      debugMode: false
 
  - task: securedevelopmentteam.vss-secure-development-tools.build-task
  ➥ -publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2
    displayName: 'Publish Secret Scan Logs to Build Artifacts'
    continueOnError: true
 
  - task: securedevelopmentteam.vss-secure-development-tools.build-task
  ➥ -postanalysis.PostAnalysis@1
    displayName: 'Check for Failures'
    inputs:
      CredScan: true
      ToolLogsNotFoundAction: Error
		

Хорошо, отлично, итак, мы разобрались как считывать файл YAML. Далее давайте преобразуем его в нечто, с чем слегка легче работать:


PS C:\Scripts\ > Get-Content -Raw /Users/travis/Downloads/credscan.yml | 
 ➥ ConvertFrom-Yaml
 
Name                           Value
----                           -----
parameters                     {pool, jobName, displayName}
jobs                           {${{ parameters.displayName }}} 
		

Ну да. Это было несложно. Посмотрим что у нас за объект:


PS C:\Scripts\ > Get-Content -Raw /Users/travis/Downloads/credscan.yml | 
 ➥ ConvertFrom-Yaml | gm
 
   TypeName: System.Collections.Hashtable
Name              MemberType            Definition
----              ----------            ----------
Add               Method                void Add(System.Object key...
Clear             Method                void Clear(), void IDictionary.Clear()
Clone             Method                System.Object Clone(), ...
Contains          Method                bool Contains(System.Object key)...
ContainsKey       Method                bool ContainsKey(System.Object key)
ContainsValue     Method                bool ContainsValue(System.Object...
CopyTo            Method                void CopyTo(array array, int...
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionary...
GetHashCode       Method                int GetHashCode()
GetObjectData     Method                void GetObjectData(System.Runtim... GetType
       Method                type GetType()
OnDeserialization Method                void OnDeserialization(System.Object...Remove
       Method                void Remove(System.Object key), voi... ToString
       Method                string ToString()
Item              ParameterizedProperty System.Object Item(System.Object 
                ➥ key...
Count             Property              int Count {get;}
IsFixedSize       Property              bool IsFixedSize {get;}
IsReadOnly        Property              bool IsReadOnly {get;}
IsSynchronized    Property              bool IsSynchronized {get;}
Keys              Property              System.Collections.ICollection K...
SyncRoot          Property              System.Object SyncRoot {get;}
Values            Property              System.Collections.ICollection Value...
		

Ладно, итак, это некая хэш- таблица. Хэш- таблицы это просто наполненный мешок. Вы будете часто сталкиваться с ними на протяжении всего путешествия по PowerShell. Это великолепно, поскольку их запросто можно превращать в иные форматы. Давайте попробуем взять то что мы получили в YAML и превратить это в иную очень важную структуру данных в DevOps - YAML. Давайте посмотрим как нам придётся работать:


PS C:\Scripts\ > Get-Help *json*
 
Name             Category Module                       Synopsis
----             -------- ------                       --------
ConvertFrom-Json Cmdlet   Microsoft.PowerShell.Utility...
ConvertTo-Json   Cmdlet   Microsoft.PowerShell.Utility...
Test-Json        Cmdlet   Microsoft.PowerShell.Utility...
		

Победа - командлет ConvertTo-Json. Давайте воспользуемся конвейером для преобразования YAML в JSON. Нам понадобится воспользоваться параметром Depth для ConvertTo-Json (вы можете о нём прочесть в соответствующей подсказке), который позволит нам определить насколько глубоко этот командлет должен опускаться при попытке создания необходимой структуры JSON. Для того чем мы занимаемся, 100 будет вполне достаточно. Отлично, давайте соберём всё воедино:


PS C:\Scripts\ > Get-Content -Raw /Users/travis/Downloads/credscan.yml | 
 ➥ ConvertFrom-Yaml | ConvertTo-Json -Depth 100
 
{
  "parameters": {
    "pool": "Hosted VS2017",
    "jobName": "credscan",
    "displayName": "Secret Scan"
  },
  "jobs": [
    {
      "job": "${{ parameters.jobName }}",
      "pool": {
        "name": "${{ parameters.pool }}"
      },
      "steps": [
        {
          "task": "securedevelopmentteam.vss-secure-development-tools.build
        ➥ -task-credscan.CredSca          "inputs": {
            "debugMode": false,
            "suppressionsFile": "tools/credScan/suppress.json"
          },
          "displayName": "Scan for Secrets"
        },
        {
nalysislogs.PublishSecurityAnalysisLogs@2",
          "continueOnError": true,
          "displayName": "Publish Secret Scan Logs to Build Artifacts"
        },
        {
          "task": "securedevelopmentteam.vss-secure-development-tools.build
         ➥ -task-postanalysis.PostAnalysis@1",
          "inputs": {
            "CredScan": true,
            "ToolLogsNotFoundAction": "Error"
          },
          "displayName": "Check for Failures"
        }
      ],
      "displayName": "${{ parameters.displayName }}"
    }
  ]
}
		

Это работает! Теперь у нас имеется некий JSON на основе файла YAML. Это полезное упражнение, поскольку в природе имеется большое число различных инструментов DevOps, которые получают YAML или JSON (AutoRest, Kubernetes, чтобы назвать хотя бы пару). Как результат, вы можете предпочитать YAML, но совместно работающему с вами коллеге больше нравится JSON. Теперь у вас имеется простой способ совместной работы друг с другом выполняя таким образом преобразование.

Теперь мы вольны признать что это не сложная задача. о сама эта задача не является основной целью данной главы. Основная цель в том, что она нам дала. Что мы сделали?

  1. Мы начали с поиска локальных файлов подсказок для всех тех, которые содержат некое конкретное слово. Когда наш искомый термин не совпал ни с каким названием команды, PowerShell осуществил поиск по содержимому всех файлов подсказок. Это имеет смысл, поскольку даже когда YAML упоминается, мы бы его обнаружили.

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

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

  4. Даже хотя автор нашего модуля и не предоставляет подсказку, PowerShell способствует нам в наличии возможности разобраться с тем как запускает команду для преобразования в и из YAML. Это помогает нам обнаружить как структурированы данные команды и какой вид значений ожидать от этой команды.

  5. Воспользовавшись собранными нами на этот момент сведениями, мы получили возможность реализовать желаемые нами изменения.

Советы для самостоятельного обучения

И снова, реальной темой данной книги является то как самостоятельно обучаться - и именно это и иллюстрирует данная глава. Вот несколько советов:

  • не бойтесь подсказок и обязательно знакомьтесь с примерами. Мы повторяем это снова и снова и, кажется, нам никто не верит. Мы всё ещё наблюдаем прямо перед собой новичков, скрытно следующих в Google для поиска примеров. Что такого страшного в файлах подсказок? Если вы желаете прочесть чей- то блог, почему бы для начала не испробовать примеры из файлов подсказок?

  • Будьте внимательны. Любая незначительная информация на экране потенциально важна - не упускайте мысленно то, что вы не ищете прямо сейчас. Это просто сделать, но не стоит. Вместо этого просматривайте каждый момент и пытайтесь понять для чего он требуется и какие сведения вы можете из него извлечь.

  • Не бойтесь неудач. Надеюсь, у вас имеется некая виртуальная машина, на которой вы можете поиграться - а потому пользуйтесь ею. Новички постоянно задают вопросы типа: "Эй, а если я сделаю то- то и то- то, что случится?", на что мы начали отвечать: "Понятия не имею - попробуйте". Эксперименты это польза. Самое плохое что может приключиться с виртуальной машиной - вам придётся выполнить откат до моментального снимка, не так ли? Так что вертите это, над чем бы вы не работали.

  • Если что- то не работает, не бейтесь головой о стену - испробуйте нечто иное.

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

Лабораторные занятия

[Замечание]Замечание

Для данного лабораторного занятия вы можете применять любую предпочитаемую вами ОС (если пожелаете, попробуйте несколько) и убедитесь что вы пользуетесь PowerShell v7 или выше.

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

Данное упражнение будет посвящено управлению секретами. Инженеры DevOps должны быть накоротке с этим понятием. Идея проста: имеется куча конфиденциальной информации (пароли, строки соединения и т.п.), которые нам надлежит применять в своих командах, но нам следует хранить эти секреты в безопасном месте. Мы также можем пожелать поделиться такими секретами с прочими членами своей команды - а электронная почта недостаточно безопасна, пацаны!

Команда PowerShell недавно работала над модулем с названием Secrets Management именно для этого. Это универсальный модуль для взаимодействия с любым хранилищем, который поддерживает это. Некоторые из них будут локальными хранилищами секретов, например, macOS Keychain, а другие - облачными службами, такими как Azure Key Vault и HashiCorp Vault. Ваша цель - перехватить такой модуль, сохранить секрет в хранилище секретов, а затем выполнить его выборку. Если вы применяете хранилище секретов на базе облачного хранилища, в качестве окончательной проверки попробуйте получить этот секрет с другого компьютера.

Ответы лабораторных занятий

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