feat(nutanix): support API key auth and custom HTTP headers#358
feat(nutanix): support API key auth and custom HTTP headers#358andrew-sumner wants to merge 4 commits into
Conversation
0bdd433 to
b81c9ce
Compare
b81c9ce to
2fbfa70
Compare
| // Objects Lite validates the AWS V4 signature against Prism Central's user | ||
| // table, so nutanix_username/nutanix_password are required even when the rest | ||
| // of the build authenticates with nutanix_api_key. | ||
| func (d *NutanixDriver) uploadImageObject(ctx context.Context, key, filePath string) error { |
There was a problem hiding this comment.
https://github.com/nutanix-cloud-native/prism-go-client/blob/main/converged/v4/images.go#L170
it will be better if we use existing api of prism go client
There was a problem hiding this comment.
Thanks for the suggestion! We actually started with ImagesService.Upload but had to reimplement the S3 upload path because the upstream awsConfig() builds the AWS HTTP client internally with no way to inject custom headers or a custom transport.
This PR adds nutanix_custom_headers support — needed when Prism Central sits behind a service-token gateway like Cloudflare Access. Our uploadImageObject wraps the AWS HTTP client with a headerInjectingTransport so those headers reach the Objects Lite S3 endpoint. The upstream Upload → uploadToObjects → awsConfig chain would silently drop them.
Specifically, awsConfig() only conditionally creates a custom http.Client for TLS skip-verify — there's no mechanism to pass in additional headers or wrap the transport.
Happy to contribute custom header / transport support upstream to prism-go-client as a follow-up so we can switch back to ImagesService.Upload — would that work?
|
Update: Opened the upstream PR — nutanix-cloud-native/prism-go-client#354. It adds a Once that lands and a release is cut, the |
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.
…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
Remove NUTANIX_API_KEY env var fallback and NUTANIX_HEADER_* env var scanning from plugin code. Users should use PKR_VAR_nutanix_api_key and PKR_VAR_nutanix_custom_headers (or HCL env() function) instead, which aligns with Packer best practices and existing plugin behaviour. Updated docs with usage examples showing PKR_VAR_ approach.
- Clone request in headerInjectingTransport.RoundTrip() to comply with the http.RoundTripper contract (callers must not modify the request) - Align example file field formatting for consistency - Remove unused strings import from config.go
2fbfa70 to
e0dbe09
Compare
TestPrepareRejectsInvalidWindowsInstallType previously relied on the default nutanix_username/nutanix_password set by minimalValidConfig. Pass them explicitly so the test is self-contained and does not depend on helper defaults — also avoids a behavioural conflict when this PR is rebased against the API-key PR (nutanix-cloud-native#358), whose minimalValidConfig omits default credentials so its auth-combination tests can work.
Closes #357
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 theX-ntnx-api-keyheader in place of HTTP Basic auth. Falls back to theNUTANIX_API_KEYenvironment 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 viaNUTANIX_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_keyor the existingnutanix_username+nutanix_passwordpair. If both are provided,nutanix_api_keywins 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_keyandnutanix_custom_headers:applyCustomHeaderson each SDK ApiClient viaAddDefaultHeaderboot_commandkeystroke injectionstep_vnc_connect.gocopiesCustomHeaders+APIKeyonto the WSS upgradehttp.Headersource_image_path/cd_contentimage uploadCreateImageFilebuilds the AWS HTTP client with aheaderInjectingTransportthat carriesCustomHeadersV3 API exclusion: The legacy V3 client is not wired with
nutanix_api_keyornutanix_custom_headers— the V3 API is deprecated and will be removed in a future release. The only remaining V3 call is project lookup; this will not work through a proxy that requires custom headers.Objects Lite caveat: Objects Lite always validates the AWS V4 signature against Prism Central's user table.
nutanix_username/nutanix_passwordare required for uploads even whennutanix_api_keyhandles all other API calls. Users can avoid the Objects Lite path entirely by usingsource_image_nameorsource_image_uriinstead ofsource_image_path.Windows guest customization:
windows_install_typeNew config option
windows_install_typecontrols the Nutanix V4 APIInstallTypefield for Windows Sysprep guest customization (user_datawithos_type = "Windows"):PREPARED(default) — for sysprepped template/clone deployments. AHV delivers the unattend asUnattend.xmland may auto-restart the VM to apply customization.FRESH— for ISO-based fresh installs. AHV delivers the unattend asAutounattend.xml(discoverable by Windows PE) and does not auto-restart the VM after shutdown.Without this option,
PREPAREDwas 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.gonow tolerates communicator disconnects duringshutdown_commandexecution andPowerOff()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_headersdescription lists all three propagation pathsuser_datadocumented for both Linux (cloud-init) and Windows (Sysprep unattend.xml)windows_install_typedocumented with FRESH/PREPARED options