Skip to content

feat(nutanix): support API key auth and custom HTTP headers#358

Open
andrew-sumner wants to merge 6 commits intonutanix-cloud-native:mainfrom
andrew-sumner:issue/api-key-and-custom-headers
Open

feat(nutanix): support API key auth and custom HTTP headers#358
andrew-sumner wants to merge 6 commits intonutanix-cloud-native:mainfrom
andrew-sumner:issue/api-key-and-custom-headers

Conversation

@andrew-sumner
Copy link
Copy Markdown

@andrew-sumner andrew-sumner commented May 1, 2026

What this PR does / why we need it:

Adds two new builder configuration fields to authenticate with Prism Central:

  • nutanix_api_key — when set, requests use the X-ntnx-api-key header in place of HTTP Basic auth. Falls back to the NUTANIX_API_KEY environment variable.
  • nutanix_custom_headers — extra HTTP headers attached to every Prism Central request (REST API, VNC console websocket, and Objects Lite S3 uploads), intended for environments fronted by a reverse proxy that requires additional auth headers (e.g. Cloudflare Access service tokens). Headers can also be supplied via NUTANIX_HEADER_* environment variables; the prefix is stripped, underscores become dashes, and each segment is title-cased (NUTANIX_HEADER_CF_ACCESS_CLIENT_ID -> Cf-Access-Client-Id). Config values take precedence over env vars.

Authentication validation now accepts either nutanix_api_key or the existing nutanix_username + nutanix_password pair. If both are provided, nutanix_api_key wins and a warning is emitted. The legacy service-account form documented today (nutanix_username = "X-ntnx-api-key", nutanix_password = <key>) keeps working for backwards compatibility; the docs now steer users to the new field.

Brings the plugin to parity with the equivalent changes in the sibling Nutanix projects:

Header propagation across all paths

The plugin communicates with Prism Central over three distinct transports. All three now honour nutanix_api_key and nutanix_custom_headers:

Path Purpose How headers are applied
REST API (v4 + v3) VM create, image metadata, task polling applyCustomHeaders on each SDK ApiClient via AddDefaultHeader
VNC console websocket boot_command keystroke injection step_vnc_connect.go copies CustomHeaders + APIKey onto the WSS upgrade http.Header
Objects Lite S3 source_image_path / cd_content image upload CreateImageFile builds the AWS HTTP client with a headerInjectingTransport that carries CustomHeaders

Objects Lite caveat: Objects Lite always validates the AWS V4 signature against Prism Central's user table. nutanix_username/nutanix_password are required for uploads even when nutanix_api_key handles all other API calls. Users can avoid the Objects Lite path entirely by using source_image_name or source_image_uri instead of source_image_path.

Windows guest customization: windows_install_type

New config option windows_install_type controls the Nutanix V4 API InstallType field for Windows Sysprep guest customization (user_data with os_type = "Windows"):

  • PREPARED (default) — for sysprepped template/clone deployments. AHV delivers the unattend as Unattend.xml and may auto-restart the VM to apply customization.
  • FRESH — for ISO-based fresh installs. AHV delivers the unattend as Autounattend.xml (discoverable by Windows PE) and does not auto-restart the VM after shutdown.

Without this option, PREPARED was always used, which caused Nutanix to auto-restart VMs after sysprep /shutdown — preventing Packer from capturing the disk.

Shutdown command resilience (defensive)

step_shutdown_vm.go now tolerates communicator disconnects during shutdown_command execution and PowerOff() errors when the VM is already off. Previously, if the shutdown command triggered a VM power-off (e.g. sysprep /shutdown), the communicator drop was treated as a fatal error, halting the build before reaching the power-state polling loop. Now the error is logged as a warning and the polling loop proceeds normally.

This is a defensive improvement — with the recommended scheduled-task approach for sysprep, the shutdown command returns cleanly before sysprep starts and this code path is not triggered. But it prevents build failures if the timing is different or a different shutdown command is used.

Documentation updates

  • nutanix_custom_headers description lists all three propagation paths
  • user_data documented for both Linux (cloud-init) and Windows (Sysprep unattend.xml)
  • windows_install_type documented with FRESH/PREPARED options

Adds two new builder fields:

- nutanix_api_key — uses the X-ntnx-api-key header in place of Basic
  auth. Falls back to the NUTANIX_API_KEY environment variable.
- nutanix_custom_headers — extra HTTP headers attached to every Prism
  Central request (e.g. for Cloudflare Access service tokens). Headers
  can also be supplied via NUTANIX_HEADER_* env vars; config values
  take precedence.

Authentication accepts either nutanix_api_key or the existing
nutanix_username/nutanix_password pair; if both are set, the API key
wins and a warning is emitted. The legacy service-account form
(nutanix_username = "X-ntnx-api-key", nutanix_password = key) keeps
working for backwards compatibility.

Brings the plugin to parity with the equivalent changes in the
terraform-provider-nutanix and nutanix.ansible projects.
dt-andrews added 5 commits May 3, 2026 13:58
…Lite S3

Extends nutanix_api_key and nutanix_custom_headers support to the two
remaining paths that were not covered by the initial PR:

VNC console websocket (boot_command):
  step_vnc_connect.go now copies CustomHeaders into the WSS upgrade
  request and prefers the explicit APIKey field over the legacy
  Username == "X-ntnx-api-key" form. Without this, any service-token
  gateway in front of Prism Central (e.g. Cloudflare Access) rejects
  the websocket handshake and boot_command keystrokes never land.

Objects Lite S3 upload (source_image_path / cd_content):
  CreateImageFile is reimplemented to build the AWS HTTP client through
  a headerInjectingTransport that carries nutanix_custom_headers, then
  calls v4Client.Images.Create separately. The upstream
  prism-go-client ImagesService.Upload uses an unconfigured HTTP client
  that silently drops any service-token headers. Note: Objects Lite
  still validates AWS V4 signatures against Prism Central's user table,
  so nutanix_username/nutanix_password are required for upload even when
  nutanix_api_key handles all other API calls.

Documentation:
  - nutanix_custom_headers description updated to list all three paths
    (REST API, VNC websocket, Objects Lite S3)
  - user_data documented for both Linux (cloud-init) and Windows
    (Sysprep unattend.xml) — the code already handled both but the docs
    only mentioned Linux
  - Added caveat about Objects Lite requiring username/password
When the shutdown command triggers a VM power-off (e.g. sysprep
/generalize /oobe /shutdown), the communicator drops before it can
read the exit status. Previously this was treated as a fatal error,
halting the build. Now log a warning and fall through to the power-
state polling loop, which detects the VM is off and proceeds to
image capture.
Without this, the Sysprep guest customization defaults to PREPARED,
which tells Nutanix to auto-restart the VM after shutdown to apply
the customization on first boot. For Packer ISO builds, the unattend
is for a fresh install — the VM should stay off after sysprep so
Packer can capture the disk.
When sysprep runs as a provisioner with /shutdown, the VM may be off
before StepShutdown calls PowerOff(). Log a warning and fall through
to the polling loop instead of halting.
Exposes the Nutanix V4 API InstallType field as a Packer config option
(windows_install_type). Defaults to PREPARED (existing behaviour for
template/clone deployments). Set to FRESH for ISO-based builds where
the unattend is for a fresh install — prevents Nutanix from auto-
restarting the VM after sysprep shutdown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants