Подписание конвейера CI/CD и MSIX с помощью Azure Key Vault

Подписание — одна из важнейших задач, которую необходимо выполнить при работе с пакетами MSIX. Если пакет MSIX не подписан доверенным сертификатом, пользователи не смогут установить приложение. В то же время подписание также является очень важной задачей с точки зрения безопасности. Сертификаты должны храниться в полной безопасности, чтобы злоумышленники не могли повторно использовать их для подписи своих приложений с помощью нашего удостоверения. Azure Key Vault — лучше всего подходит для выполнения этого требования.

В этой статье мы рассмотрим, как с помощью Azure Key Vault в конвейере CI/CD можно автоматически подписывать пакет MSIX в рамках этого процесса.

Важно!

Процесс, описанный в этой статье, основан на средстве с открытым исходным кодом Azure SignTool, которое работает как с Azure Pipelines, так и с GitHub Actions. При работе с Azure Pipelines можно также использовать расширения MSIX вместе с задачей Azure Key Vault.

Предварительные требования

  • Учетная запись Azure. Если у вас еще нет учетной записи, зарегистрируйте ее здесь.
  • Azure Key Vault. Дополнительные сведения см. в разделе Создание хранилища.
  • Действительный сертификат для подписывания пакета, импортированный в Azure Key Vault. Сертификат, который создается в Azure Key Vault по умолчанию, не подходит для этого. Дополнительные сведения см. в статье Создание сертификата для подписывания пакета.
  • Конвейер CI/CD, который создает пакет MSIX, размещенный в Azure Pipelines или GitHub Actions. Дополнительные сведения см. в статье Общие сведения о конвейере CI/CD и MSIX.

Регистрация приложения в Azure

Чтобы подписать пакет как часть конвейера CI/CD, мы будем использовать средство Azure SignTool. Это средство работает как служебная программа SignTool, включенная в пакет SDK для Windows 10, но вместо применения локального сертификата оно подключается к Azure Key Vault и использует один из доступных сертификатов. Однако, чтобы установить подключение, нам сначала нужно зарегистрировать приложение в Azure. Таким образом мы получим учетные данные, необходимые для проверки подлинности Azure SignTool в нашей службе Azure Key Vault.

Откройте портал Azure и выберите Azure Active Directory среди доступных служб. Щелкните Регистрация приложений и выберите Новая регистрация, чтобы начать процесс. Присвойте приложению имя (например, SignToolForContoso на изображении ниже) и оставьте настройки по умолчанию.

Register an application on Azure

Далее необходимо обработать приложение в качестве общедоступного клиента, так как в нашем случае URI перенаправления не требуется. Перейдите в раздел Проверка подлинности и в области Дополнительные параметры установите для параметра Treat application as a public client (Считать приложение общедоступным клиентом) значение Да.

Set advanced settings

Наконец, нам нужно создать секрет клиента. Это пароль, который нам понадобится для проверки подлинности в Azure SignTool. Перейдите в раздел Сертификаты и секреты и щелкните Создать секрет клиента. Присвойте ему имя, выберите срок действия и нажмите кнопку Добавить. Вы будете перенаправлены обратно на главную страницу, где будет указан секрет вместе с его значением. Обязательно скопируйте его и сохраните в безопасном месте. Вы не сможете получить его снова. Как только вы обновите страницу, секрет будет замаскирован и увидеть его будет невозможно. Единственным вариантом будет снова создать секрет.

И последняя информация, которую вам нужно сохранить вместе с секретом клиента, — идентификатор приложения. Вернитесь на домашнюю страницу приложения (нажав Обзор) и в верхнем разделе найдите значение Идентификатор приложения (клиент) :

Application Id

Включение доступа к Azure Key Vault

Следующим шагом является настройка приложения Azure, которое мы только что создали, для доступа к нашей службе Azure Key Vault. На портале Azure перейдите к экземпляру Azure Key Vault, содержащему сертификат, который вы хотите использовать для подписи своего пакета MSIX. Перейдите в раздел Политики доступа и нажмите Добавить политику доступа. В средстве можно выбрать один из доступных шаблонов для определения разрешений, которые мы хотим предоставить, но в нашем случае ни один из них не подходит. Таким образом, с помощью раскрывающихся списков нам нужно вручную установить приведенные ниже параметры.

  • В разделе Разрешения для ключа включите параметр Подписать.
  • В разделе Разрешения сертификатов включите параметр Получить.

Последний важный шаг — указать, какое приложение будет иметь доступ к этой политике. Щелкните Выбор субъекта и найдите приложение Azure, созданное на предыдущем шаге, по его имени. В этом примере оно называется SignToolForContoso.

Select principal

Найдя его, нажмите Выбрать. Так должна выглядеть политика.

Add access policy

По завершении процесса щелкните Добавить, чтобы создать политику.

Использование Azure SignTool для подписания пакета локально

Теперь, когда настройка Azure завершена, мы можем использовать Azure SignTool для подписания пакета. При работе с этим разделом мы воспользуемся средством локально, чтобы ознакомиться с ним. В следующих разделах мы будем использовать его как часть конвейера CI/CD.

Средство доступно как глобальное средство .NET. Убедитесь, что у вас установлена последняя версия пакета SDK для .NET, затем откройте командную строку и запустите следующую команду:

dotnet tool install --global AzureSignTool 

Теперь вы можете подписать свой пакет с помощью команды AzureSignTool, для которой требуются приведенные ниже параметры.

  • kvu — это URL-адрес Azure Key Vault. Вы можете найти его на главной странице службы на портале Azure в разделе "DNS-имя".
  • kvi — это идентификатор зарегистрированного вами приложения Azure, который вы сохранили ранее.
  • kvs — это созданный секрет клиента, который вы сохранили ранее.
  • kvc — понятное имя сертификата, который вы хотите использовать.
  • tr — URL-адрес сервера меток времени. Используя этот параметр, мы можем обеспечить работоспособность пакета, даже когда истечет срок действия сертификата.
  • v — это путь к пакету MSIX, который необходимо подписать.

Вот пример команды:

AzureSignTool sign -kvt "<tenantID>" -kvu "https://contosoexpenses-blog.vault.azure.net/" -kvi "64fae35e-cb84-4b9f-86eb-5170d169316d" -kvs "this-is-the-secret" -kvc "MyCertificate" -tr http://timestamp.digicert.com -v .\MyContosoApp.msix

Примечание

Чтобы узнать больше об AzureSignTool, выполните команду AzureSignTool sign --help

Использование Azure SignTool с Azure Pipelines

В этом разделе предполагается наличие конвейера CI/CD для приложения Windows, настроенного с помощью файла YAML в Azure Pipelines, как описано здесь.

Сначала вам нужно будет создать несколько переменных, чтобы сохранить информацию, необходимую Azure SignTool для подключения к Azure Key Vault. В Azure DevOps выберите свой конвейер и нажмите кнопку Изменить сверху. В редакторе YAML нажмите кнопку Переменные сверху, чтобы открыть панель. Вам нужно нажать кнопку "+", чтобы добавить такие переменные:

  • AzureKeyVaultName с понятным именем хранилища;
  • AzureKeyVaultUrl с URL-адресом хранилища;
  • AzureKeyVaultClientId с идентификатором приложения Azure;
  • AzureKeyVaultClientSecret с секретом клиента приложения Azure.

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

Add variable

Теперь вы можете настроить имеющийся конвейер YAML, добавив задачу .NET Core для установки Azure SignTool на агент. Вот фрагмент YAML, который нужно добавить:

- task: DotNetCoreCLI@2
  displayName: 'Install Azure SignTool'
  inputs:
    command: custom
    custom: tool
    arguments: 'install --global AzureSignTool'

Далее нам необходимо добавить задачу PowerShell для выполнения команды, которая подпишет пакет. Эту задачу необходимо выполнять только в конце процесса сборки, после создания пакета MSIX.

- powershell: '& AzureSignTool sign -kvu $(AzureKeyVaultUrl) -kvi $(AzureKeyVaultClientId) -kvs $(AzureKeyVaultClientSecret) -kvc $(AzureKeyVaultName) -tr http://timestamp.digicert.com -v "$(System.DefaultWorkingDirectory)\MyPipeline\MyContosoApp\MyContosoApp.msix"'
  displayName: 'Sign the package'

Эта команда аналогична той, которую мы использовали для подписания пакета локально. Вот единственные отличия:

  • вместо использования фиксированных значений для различных параметров мы используем переменные, которые мы создали с синтаксисом $(Variable-Name) ;
  • путь к пакету MSIX указывает на папку на агенте, в которой в конце сборки будет создан пакет MSIX.

Использование Azure SignTool с GitHub Actions

В этом разделе предполагается наличие конвейера CI/CD для приложения Windows, настроенного с помощью файла YAML в GitHub Actions, как описано здесь.

Как и в случае с Azure Pipeline, сначала нам необходимо безопасно сохранить учетные данные. GitHub использует секреты, которые можно добавить в настройках вашего репозитория. В репозитории GitHub, в котором размещено ваше приложение Windows, нажмите Параметры, а затем перейдите в раздел Секреты.

Как и в Azure Pipelines, вам необходимо щелкнуть Новый секрет, чтобы создать четыре секрета:

  • AzureKeyVaultName с понятным именем хранилища;
  • AzureKeyVaultUrl с URL-адресом хранилища;
  • AzureKeyVaultClientId с идентификатором приложения Azure;
  • AzureKeyVaultClientSecret с секретом клиента приложения Azure.

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

Теперь на вкладке Действия репозитория вы можете открыть имеющийся рабочий процесс и добавить задачи, необходимые для добавления подписи. При выполнении первой задачи на агент будет установлено средство Azure SignTool:

- name: Install AzureSignTool
  run: dotnet tool install --global AzureSignTool

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

 - name: Sign package
   run: |
        Get-ChildItem -recurse -Include **.msix | ForEach-Object {
        $msixPath = $_.FullName
        & AzureSignTool sign -kvu "${{ secrets.AzureKeyVaultUrl }}" -kvi "${{ secrets.AzureKeyVaultClientId }}" -kvs "${{ secrets.AzureKeyVaultClientSecret }}" -kvc ${{ secrets.AzureKeyVaultName }} -tr http://timestamp.digicert.com -v $msixPath
        }

Эта задача немного отличается от той, которую мы использовали в Azure Pipelines. Во-первых, GitHub использует другой синтаксис для доступа к секретам, а именно ${{ secrets.SECRET_NAME }}. Таким образом, различные параметры заполняются значениями, которые мы ранее создали в разделе "Секреты". Во-вторых, для поиска пакетов MSIX, которые требуется подписать, нужно использовать другой подход. Задача вместо того чтобы указывать на конкретный пакет MSIX, использует сценарий PowerShell, который выполняет итерацию по всем файлам, хранящимся в выходных данных сборки. Если файл имеет расширение MSIX, задача будет использовать команду AzureSignTool, чтобы подписать его.

Развертывание пакета

Независимо от выбранной вами платформы CI/CD, в конце потока вы получите пакет MSIX, подписанный вашим сертификатом, который хранится в Azure Key Vault. Теперь вы можете использовать любую другую доступную задачу для развертывания пакета с помощью предпочитаемого вами варианта распределения: Microsoft Store, веб-сайт, Microsoft Intune и т. д.