Firma de MSIX y canalización de CI/CD con Azure Key VaultMSIX and CI/CD Pipeline signing with Azure Key Vault

La firma es una de las tareas críticas que se deben realizar cuando se trabaja con paquetes MSIX.Signing is one of the critical tasks to perform when you're working with MSIX packages. Si un paquete MSIX no está firmado con un certificado de confianza, los usuarios no podrán instalar la aplicación.If a MSIX package isn't signed with a trusted certificate, users won't be able to install the application. Al mismo tiempo, la firma también es una de las tareas más críticas en términos de seguridad.At the same time, signing is one of the most critical tasks also when it comes to security. Los certificados se deben almacenar de forma segura para evitar que actores malintencionados puedan volver a usarlos para firmar sus aplicaciones con nuestra identidad.Certificates must be safely stored, to avoid that malicious actors could reuse them to sign their applications with our identity. Azure Key Vault es la mejor opción para admitir este requisito.Azure Key Vault is the best option to support this requirement.

En este artículo, veremos cómo puede usar Azure Key Vault en una canalización de CI/CD para que podamos firmar automáticamente nuestro paquete MSIX como parte del proceso.In this article we're going to see how you can leverage Azure Key Vault in a CI/CD pipeline, so that we can automatically sign our MSIX package as part of the process.

Importante

El proceso que se describe en este artículo se basa en una herramienta de código abierto denominada Azure SignTool, que funciona tanto con Azure Pipelines como con Acciones de GitHub.The process described in this article is based on an open source tool called Azure SignTool, which works both with Azure Pipelines and GitHub Actions. Si usa Azure Pipelines, también puede usar las extensiones MSIX en combinación con la tarea de Azure Key Vault.If you're using Azure Pipelines, you can leverage also the MSIX Extensions in combination with the Azure Key Vault task.

Requisitos previosPrerequisites

  • Una cuenta de Azure.An Azure account. Si aún no tiene una cuenta de Azure, comience aquí.If you do not already have an Azure account, start here.
  • Una instancia de Azure Key Vault.An Azure Key Vault. Para más información, consulte Creación de un almacén.For more info, see Create a Key Vault.
  • Un certificado de firma de paquetes válido importado en Azure Key Vault.A valid package signing certificate imported into Azure Key Vault. El certificado predeterminado generado por Azure Key Vault no funcionará para la firma de código.The default certificate generated by Azure Key Vault will not work for code signing. Para obtener más información sobre cómo crear un certificado de firma de paquetes, vea Crear un certificado para la firma de paquetes.For details on how to create a package signing certificate, see Create a certificate for package signing.
  • Una canalización de CI/CD que genera un paquete de MSIX hospedado en Azure Pipelines o en Acciones de GitHub.A CI/CD pipeline which generates a MSIX package, hosted on Azure Pipelines or GitHub Actions. Para obtener más información, consulte Configuración de la canalización de CI/CD con el archivo YAML.For more info, see Configure CI/CD pipeline with YAML file.

Registro de una aplicación en AzureRegister an application on Azure

Para firmar el paquete como parte de la canalización de CI/CD, usaremos una herramienta denominada Azure SignTool.To sign the package as part of the CI/CD pipeline, we're going to use a tool called Azure SignTool. Funciona como la utilidad SignTool estándar incluida en el SDK de Windows 10, pero, en lugar de usar un certificado local, se conecta a Azure Key Vault para usar uno de los certificados disponibles.It works like the standard SignTool utility included in the Windows 10 SDK but, instead of using a local certificate, it connects to Azure Key Vault to use one of the available certificates. Sin embargo, para establecer la conexión, primero tenemos que registrar una aplicación en Azure, lo que nos proporcionará las credenciales necesarias para permitir que Azure SignTool se autentique en nuestro servicio de Azure Key Vault.To establish the connection, however, we first need to register an application on Azure, which will give us the credentials we need to enable Azure SignTool to authenticate against our Azure Key Vault service.

Abra Azure Portal y elija Azure Active Directory entre los servicios disponibles.Open the Azure Portal and choose Azure Active Directory among the available services. Haga clic en Registros de aplicaciones y elija Nuevo registro para iniciar el proceso.Click on App Registrations and choose New registration to start the process. Asigne un nombre a la aplicación (por ejemplo, es SignToolForContoso en la siguiente imagen) y, a continuación, deje la configuración predeterminada.Give a name to the application (for example, it's SignToolForContoso in the image below) and then leave the default settings.

Registro de una aplicación en Azure

El siguiente paso consiste en tratar la aplicación como un cliente público, ya que estamos en un escenario en el que no se necesita un URI de redireccionamiento.The next step is to treat the application as a public client, since we are in a scenario where a redirect URI is not needed. Vaya a la sección Autenticación y, en Configuración avanzada, defina la opción Trate la aplicación como cliente público en .Move to the Authentication section and, under Advanced settings, change the switch Treat application as a public client to Yes.

Configuración avanzada

El último paso consiste en crear un secreto de cliente, que es la contraseña que necesitaremos para la autenticación desde Azure SignTool.The last step is to create a client secret, which is the password we'll need to authenticate from the Azure SignTool. Vaya a la sección Certificados y secretos y, a continuación, haga clic en Nuevo secreto de cliente.Move to the Certificates & secrets section, then click on New client secret. Asígnele un nombre, elija una expiración y, a continuación, presione el botón Agregar.Give it a name, choose an expiration and then press the Add button. Se le redirigirá de nuevo a la página principal, donde el secreto se mostrará junto con su valor.You will be redirected back to the main page, where the secret will be listed together with its value. Asegúrese de copiarlo y almacenarlo en un lugar seguro.Make sure to copy it and to store it somewhere safe. No podrá recuperarlo de nuevo.You won't be able to retrieve it again. Al actualizar la página, se aplicará una máscara al secreto y no habrá forma de revelarlo.As soon as you refresh the page, the secret will be masked and there won't be any way to reveal it. Su única opción será generar uno nuevo.Your only option will be to generate a new secret.

Hay un último dato que necesitará guardar junto con el secreto de cliente: el identificador de la aplicación.There's one last information you need to save together with the client secret: the application identifier. Vuelva a la página principal de la aplicación (al hacer clic en Información general) y, en la sección superior, busque el valor de Id. de la aplicación (cliente) :Go back to the home of the application (by clicking on Overview) and, in the upper section, look for the value Application (client) ID:

Id. de aplicación

Habilitación del acceso a Azure Key VaultEnable access to Azure Key Vault

El siguiente paso consiste en configurar la aplicación de Azure que acabamos de crear para acceder a nuestro servicio de Azure Key Vault.The next step is to configure the Azure application we have just created to access to our Azure Key Vault service. Desde Azure Portal, vaya a la instancia de Azure Key Vault que contiene el certificado que quiere usar para firmar el paquete de MSIX.From the Azure portal, move to the Azure Key Vault instance which holds the certificate you want to use to sign your MSIX package. Vaya a la sección Directivas de acceso y haga clic en Agregar directiva de acceso.Go to the Access policies section and click on Add Access Policy. La herramienta permite elegir una de las plantillas disponibles para definir los permisos que queremos conceder pero, en nuestro escenario, ninguna de estas opciones es la adecuada.The tool supports choosing one of the available templates to define the permissions we want to grant but, in our scenario, no one of them is the right fit. Por lo tanto, es necesario establecer manualmente, mediante las listas desplegables, las siguientes opciones:As such, we'll need to manually set, using the dropdowns, the following options:

  • En Permisos clave, habilite la opción Firmar.Under Key permissions, enable the Sign option.
  • En Permisos de certificado, habilite la opción Obtener.Under Certificate permissions, enable the Get option.

El último paso importante consiste en especificar qué aplicación tendrá acceso a esta directiva.The last important step is to specify which application is going to access to this policy. Haga clic en Seleccionar la entidad de seguridad y busque la aplicación de Azure que ha creado en el paso anterior mediante su nombre.Click on Select principal and search for the Azure application you have created in the previous step by using its name. En el ejemplo, se llama SignToolForContoso.In the example, it's called SignToolForContoso.

Selección de la entidad de seguridad

Cuando la haya encontrado, presione Seleccionar.Once you have found it, press Select. La directiva debe tener un aspecto similar al siguiente.This is how the policy should look like.

Agregar directiva de acceso

Una vez completado el proceso, haga clic en Agregar para crear la directiva.When you have completed the process, click Add to create the policy.

Uso de Azure SignTool para firmar el paquete localmenteUse Azure SignTool to sign the package locally

Ahora que se ha completado la configuración de Azure, podemos usar Azure SignTool para firmar el paquete.Now that the Azure configuration is completed, we can use Azure SignTool to sign the package. En esta sección, usaremos la herramienta de forma local para familiarizarnos con ella.In this section, we'll use the tool locally to familiarize with it. En las secciones siguientes, la usaremos como parte de una canalización de CI/CD.In the next sections, we're going to use it as part of a CI/CD pipeline.

La herramienta está disponible como herramienta global de .NET.The tool is available as a .NET global tool. Asegúrese de tener instalado el SDK de .NET más reciente. A continuación, abra un símbolo del sistema y ejecute el siguiente comando:Make sure to have the latest .NET SDK installed, then open a command prompt and launch the following command:

dotnet tool install --global AzureSignTool 

Ahora puede firmar el paquete con el comando AzureSignTool, que requiere los siguientes parámetros:Now you can sign your package using the AzureSignTool command, which requires the following parameters:

  • kvu es la dirección URL de Azure Key Vault.kvu is the URL of your Azure Key Vault. Puede buscarla en la página principal del servicio de Azure Portal, en Nombre DNS.You can find it in the main page of the service in the Azure portal, under DNS Name.
  • kvi es el identificador de la aplicación de Azure que ha registrado y anotado previamente.kvi is the application id of the Azure app you have registered and that you have previously noted.
  • kvs es el secreto de cliente que ha generado y anotado previamente.kvs is the client secret you have previously generated and that you have previously noted.
  • kvc es el nombre descriptivo del certificado que quiere utilizar.kvc is the friendly name of the certificate you want to use.
  • tr es la dirección URL de un servidor de marca de tiempo.tr is the URL of a timestamp server. Al utilizar esta opción, podemos permitir que el paquete siga funcionando una vez que expire el certificado.By using this option, we can enable our package to work also when the certificate will expire.
  • v es la ruta de acceso del paquete de MSIX que queremos firmar.v is the path of the MSIX package we want to sign.

Este es un comando de ejemplo:This is a sample command:

AzureSignTool sign -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

Uso de Azure SignTool con Azure PipelinesUsing Azure SignTool with Azure Pipelines

En esta sección se supone que ya tiene una canalización de CI/CD para una aplicación Windows configurada con un archivo YAML en Azure Pipelines, como se explica aquí.This section assumes you already have a CI/CD pipeline for a Windows application configured with a YAML file on Azure Pipelines, as explained here.

En primer lugar, tendrá que crear algunas variables para almacenar la información que Azure SignTool requiere para conectarse a Azure Key Vault.At first, you will need to create a few variables to store the information required by Azure SignTool to connect to Azure Key Vault. En Azure DevOps, seleccione la canalización y presione el botón Editar en la parte superior.In Azure DevOps select your pipeline and press the Edit button at the top. Desde el editor de YAML, haga clic en el botón Variables de la parte superior para abrir el panel.Once you are in the YAML editor, click on the Variables button at the top to open the panel. A continuación, haga clic en el botón + para agregar las siguientes variables:You're going to click on the + button to add the following variables:

  • AzureKeyVaultName, con el nombre descriptivo del almacén.AzureKeyVaultName, with the friendly name of your vault.
  • AzureKeyVaultUrl, con la dirección URL del almacén.AzureKeyVaultUrl, with the URL of your vault.
  • AzureKeyVaultClientId, con el identificador de la aplicación de Azure.AzureKeyVaultClientId, with the application id of your Azure application.
  • AzureKeyVaultClientSecret, con el secreto de cliente de la aplicación de Azure.AzureKeyVaultClientSecret, with the client secret of your Azure application.

Al crear cada variable, asegúrese de habilitar la opción Mantener este valor como secreto.When you create each variable, make sure to enable the Keep this value secret option. Esto garantizará que otras personas que tienen acceso a la canalización no podrán ver sus valores.It will make sure that other people who have access to the pipeline won't be able to see their values.

Agregar variable

Ahora puede personalizar la canalización de YAML existente mediante la adición de una tarea de .NET Core para instalar Azure SignTool en el agente.Now you can customize your existing YAML pipeline by adding a .NET Core task to install Azure SignTool on the agent. Este es el código YAML que se va a agregar:This is the YAML to add:

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

El siguiente paso consiste en agregar una tarea de PowerShell para ejecutar el comando que firmará el paquete.The next step is to add a PowerShell task to execute the command that will sign the package. Debe realizar esta tarea solo al final del proceso de compilación, una vez creado el paquete MSIX.You must perform this task only at the end of the build process, once the MSIX package has been created.

- 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'

El comando es similar al que hemos usado para firmar el paquete localmente.The command is similar to the one we have used to sign the package locally. Las únicas diferencias son:The only differences are:

  • En lugar de usar valores fijos para los distintos parámetros, usamos las variables que hemos creado con la sintaxis $(Nombre-Variable) .Instead of using fixed values for the various parameters, we're using the variables we have created with the syntax $(Variable-Name)
  • La ruta de acceso del paquete MSIX apunta a la carpeta del agente en que se crea el paquete MSIX al final de la compilación.The path of the MSIX package points to the folder on the agent where the MSIX package is created at the end of the build.

Uso de Azure SignTool con Acciones de GitHubUsing Azure SignTool with GitHub Actions

En esta sección se supone que ya tiene una canalización de CI/CD para una aplicación para Windows configurada con un archivo YAML en Acciones de GitHub, como se explica aquí.This section assumes you already have a CI/CD pipeline for a Windows application configured with a YAML file on GitHub Actions, as explained here.

Como primer paso, tal y como lo hicimos en Azure Pipelines, es necesario almacenar las credenciales de forma segura.As first step, like we did on Azure Pipeline, we need to safely store the credentials. GitHub usa secretos y se pueden agregar en la configuración del repositorio.GitHub uses secrets and they can be added in the settings of your repository. Una vez que esté en el repositorio de GitHub que hospeda la aplicación para Windows, haga clic en Configuración y, a continuación, pase a Secretos.Once you're on the GitHub repository which hosts your Windows application, click on Settings then move to Secrets.

De forma similar a lo que hizo con Azure Pipelines, haga clic en Nuevo secreto para crear cuatro secretos:Similarly to what you did with Azure Pipelines, you're going to click on New secret to create four secrets:

  • AzureKeyVaultName, con el nombre descriptivo del almacén.AzureKeyVaultName, with the friendly name of your vault.
  • AzureKeyVaultUrl, con la dirección URL del almacén.AzureKeyVaultUrl, with the URL of your vault.
  • AzureKeyVaultClientId, con el identificador de la aplicación de Azure.AzureKeyVaultClientId, with the application id of your Azure application.
  • AzureKeyVaultClientSecret, con el secreto de cliente de la aplicación de Azure.AzureKeyVaultClientSecret, with the client secret of your Azure application.

La diferencia con Azure Pipelines es que los secretos están ocultos implícitamente, por lo que no tendrá que habilitar ninguna opción para protegerlos.The difference with Azure Pipeline is that secrets are implicitly hidden, so you won't have to enable any option to protect them.

Ahora, desde la pestaña Acciones del repositorio, puede abrir el flujo de trabajo existente y agregar las tareas que necesita para la firma.Now, through the Actions tab of your repository, you can open your existing workflow and add the tasks you need to perform the signing. La primera instalará la herramienta AzureSign en el agente:The first one will install AzureSign Tool on the agent:

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

La segunda firmará el paquete y, como tal, debe ejecutarse una vez completada la compilación de Visual Studio y generado el paquete MSIX.The second one will sign the package and, as such, it must be executed after the Visual Studio build has been completed and the MSIX package has been generated.

 - 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
        }

Hay algunas diferencias entre esta tarea y la que usamos en Azure Pipelines.There are a few differences in this task compared to the one we used in Azure Pipelines. La primera es que GitHub usa una sintaxis diferente para acceder a los secretos, que es ${{ secrets.NOMBRE_SECRETO }}.The first one is that GitHub uses a different syntax to access to the secrets, which is ${{ secrets.SECRET_NAME }}. Como tal, los distintos parámetros se rellenan con los valores que hemos creado anteriormente en la sección Secretos.As such, the various parameters are filled with the values we have previously created in the Secrets section. La otra es que necesita usar un enfoque diferente para buscar los paquetes MSIX que se deben firmar.The other one is that you need to use a different approach to find the MSIX packages to sign. La tarea, en lugar de apuntar a un paquete MSIX concreto, usa un script de PowerShell que recorre en iteración todos los archivos almacenados en la salida de la compilación.The task, instead of pointing to a specific MSIX package, uses a PowerShell script which iterates through all the files stored in the build output. Si el archivo tiene la extensión MSIX, usará el comando AzureSignTool para firmarlo.If the file has the MSIX extension, then it will use the AzureSignTool command to sign it.

Implementar el paqueteDeploy the package

Independientemente de la plataforma de CI/CD que elija, al final del flujo tendrá un paquete MSIX firmado con el certificado almacenado en Azure Key Vault.Regardless of the CI/CD platform of your choice, at the end of the flow you will have a MSIX package signed with your certificate stored on Azure Key Vault. Ahora puede usar cualquier otra tarea disponible para implementar el paquete con su opción de distribución preferida: Microsoft Store, un sitio web, Microsoft Intune, etc.Now you can use any other available task to deploy the package using your preferred choice of distribution: the Microsoft Store, a website, Microsoft Intune, etc.