Historically, I’ve used an Entra ID Service Principal and Client Secret to authenticate Packer builds in my automation workflows, whether in Azure DevOps or GitHub Actions. While functional, this approach had significant downsides: it required embedding a secret in the pipeline environment, leading to ongoing maintenance to renew the secret and posing a security risk if the secret was ever leaked. As I continue expanding the GitHub AT-AT with useful templates, I wanted to refine this approach, merging two projects: setting up a public Minecraft SMP (Survival Multi-Player) server and adding a new Infrastructure Lifecycle Management template to GitHub AT-AT. This template will enable developers building Virtual Machine-based applications to integrate Packer image builds into their DevOps workflows, a concept I cover extensively in my book Mastering Terraform. Now, I’m codifying this setup directly within GitHub AT-AT.

Using Federated Identity Credential with Packer

A Federated Identity Credential eliminates the need for client secrets, instead leveraging GitHub’s identity to authenticate to Azure. To configure Packer for this authentication model, we need to introduce two new input variables:

variable "arm_oidc_request_token" {
  type = string
}
variable "arm_oidc_request_url" {
  type = string
}

Then, within the azure-arm builder configuration, these variables must be referenced accordingly:

source "azure-arm" "vm" {

  client_id          = var.arm_client_id
  subscription_id    = var.arm_subscription_id
  tenant_id          = var.arm_tenant_id
  oidc_request_token = var.arm_oidc_request_token
  oidc_request_url   = var.arm_oidc_request_url

  // foo

}

Configuring GitHub Actions

To enable authentication via GitHub’s federated identity, we need to modify the GitHub Actions workflow by granting necessary permissions at the top of the workflow file:

permissions:
  id-token: write
  contents: read

Next, we authenticate to Azure using the Federated Identity Credential within our GitHub Actions workflow:

- name: 'Az CLI login'
  uses: azure/login@v1
  with:
    client-id: $
    tenant-id: $
    subscription-id: $

This step utilizes GitHub’s authentication context to specify the Entra ID Tenant, Azure Subscription, and the identity being used. If the operation succeeds, it produces two key values: the GitHub Identity Request Token and the GitHub Identity Request URL, which Packer needs for authentication.

Exporting Environment Variables for Packer

To make these authentication values available to Packer, we define two special environment variables:

export PKR_VAR_arm_oidc_request_token=$ACTIONS_ID_TOKEN_REQUEST_TOKEN
export PKR_VAR_arm_oidc_request_url=$ACTIONS_ID_TOKEN_REQUEST_URL

Finally, we execute Packer:

packer init ./
packer build -var-file=variables.pkrvars.hcl ./

Challenges and Observations

One issue I encountered is that these environment variables do not seem accessible outside of the Bash script within the GitHub Actions step. I attempted to pipe them into the env collection of the GitHub Actions step, but this was unsuccessful. While manually exporting them as PKR_VAR_ environment variables is effective, it feels less elegant. I’d be curious to hear if anyone else has found a cleaner approach.

By implementing this workflow, I’ve removed the need for storing secrets in GitHub Actions, enhancing security and reducing maintenance overhead. This setup not only simplifies Packer authentication but also strengthens the security posture of automation pipelines. If you’re integrating Packer into your DevOps workflows, moving to Federated Identity Credential authentication is a step in the right direction.