Skip to content

fix(butane,ignition): disable systemcrypto on CGO_ENABLED=0 static cross-builds - #18550

Open
Nan Liu (liunan-ms) wants to merge 1 commit into
4.0from
liunan/golang-nosystemcrypto-dev
Open

fix(butane,ignition): disable systemcrypto on CGO_ENABLED=0 static cross-builds#18550
Nan Liu (liunan-ms) wants to merge 1 commit into
4.0from
liunan/golang-nosystemcrypto-dev

Conversation

@liunan-ms

@liunan-ms Nan Liu (liunan-ms) commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Azure Linux 4.0's golang is the Microsoft build of Go, whose systemcrypto (OpenSSL) backend is baseline-enabled for Linux. butane and ignition build their native binary fine, then cross-compile static -redistributable Linux binaries with CGO_ENABLED=0. In that config the OpenSSL backend file is excluded (no cgo, and the ms_nocgo_opensslcrypto experiment isn't set) and the pure-Go nobackend fallback is excluded (systemcrypto stays enabled), so crypto/internal/backend/fips140 references systemFIPSMode/backendEnabled with no file defining them → build fails.

Fix: set MS_GO_NOSYSTEMCRYPTO=1 on those cgo-free static cross-builds so the pure-Go crypto implementation is selected, keeping the redistributable binaries self-contained (no runtime OpenSSL dependency).

Changes

Component Change
butane, ignition New dedicated *.comp.toml + per-file overlays/0001-disable-systemcrypto-static-cross-builds.overlay.toml; removed inline entries from components.toml
Overlay type spec-search-replace in %build, prepending MS_GO_NOSYSTEMCRYPTO=1 to the four GOOS=linux CGO_ENABLED=0 cross-build lines only
Metadata category = "azl-compatibility", upstream-status = "inapplicable"

Why MS_GO_NOSYSTEMCRYPTO=1 and not GOEXPERIMENT=nosystemcrypto: it is the documented, forward-compatible knob (supported Go 1.25.2 → 1.27+), whereas GOEXPERIMENT=nosystemcrypto is removed and rejected with an error in Go 1.27. Ref: MS Go FIPS README — build option to use Go crypto.

Untouched on purpose: the darwin/windows cross-builds (non-Linux, systemcrypto baseline N/A) and ignition's native GOEXPERIMENT=strictfipsruntime binary (the on-system, FIPS-strict initramfs binary). Only the portable redistributable validators become pure-Go/non-FIPS.

Validation

Locally built and validated against the Microsoft build of Go 1.26.5 (the toolchain that reproduces the failure; the local repo golang RPM Provides: msft-golang), via azldev comp build -p <name> --local-repo <ms-go-repo>:

Package Build Emitted redistributable RPM
butane ✅ exit 0 butane-redistributable-0.26.0-*.azl4.noarch.rpm
ignition ✅ exit 0 ignition-validate-redistributable-2.26.0-*.azl4.noarch.rpm

arm64 static binary inspection (extracted from the redistributable RPMs):

  • butane-aarch64-unknown-linux-gnu-staticELF 64-bit LSB executable, ARM aarch64, statically linked, go1.26.5
  • ignition-validate-aarch64-unknown-linux-gnu-staticELF 64-bit LSB executable, ARM aarch64, statically linked, go1.26.5

The previously-failing CGO_ENABLED=0 aarch64 static builds now compile and link cleanly as self-contained pure-Go binaries (no libcrypto.so.3/OpenSSL runtime dependency).

Runnable smoke test (mock chroot)

Installed the emitted -redistributable RPMs in azldev adv mock shell, staged the x86_64 static payloads (chmod 0755, since they ship as 0644 data files under /usr/share/), and executed them. Binaries built with MS_GO_NOSYSTEMCRYPTO=1.

# rpm -q ...
butane-redistributable-0.26.0-7.azl4.noarch
ignition-validate-redistributable-2.26.0-6.azl4.noarch

# ldd butane  →  proves true self-containment (no OpenSSL / no libc runtime dep)
        not a dynamic executable

# butane --version
Butane 0.26.0

# butane transpile (variant: fcos / version: 1.5.0 + an inline file)  →  valid Ignition emitted
{
  "ignition": { "version": "3.4.0" },
  "storage": { "files": [ { "path": "/etc/hello",
      "contents": { "compression": "", "source": "data:,hi" } } ] }
}

# ignition-validate --version
Ignition 2.26.0

# ignition-validate <the config butane produced>
VALIDATE-OK

# ignition-validate <invalid: {"ignition":{"version":"9.9.9"}}>
couldn't parse config: unsupported config version
correctly-rejected (exit 1)

Result: both x86_64-unknown-linux-gnu-static binaries run standalone, are truly static (not a dynamic executable — no libcrypto.so.3/OpenSSL dependency), and perform their real work — Butane transpiles a config and Ignition-validate both accepts a good config and rejects a bad one. Crucially, startup does not panic, confirming the pure-Go crypto path selected by MS_GO_NOSYSTEMCRYPTO=1 initializes correctly with no crypto backend present.

…oss-builds

Azure Linux 4.0's golang is the Microsoft build of Go, whose systemcrypto
(OpenSSL) backend is baseline-enabled for Linux targets. Both packages build
their native binary fine, then cross-compile static -redistributable Linux
binaries with CGO_ENABLED=0. In that configuration the OpenSSL backend file is
excluded (no cgo) while the nobackend fallback is also excluded (systemcrypto
stays enabled), so crypto/internal/backend/fips140 references
systemFIPSMode/backendEnabled with no file defining them and the build fails.

Set MS_GO_NOSYSTEMCRYPTO=1 on those cgo-free static cross-builds so the pure-Go
crypto implementation is used, keeping the redistributable binaries
self-contained (no runtime OpenSSL). MS_GO_NOSYSTEMCRYPTO=1 is the documented,
forward-compatible knob (Go 1.25.2 through 1.27+); GOEXPERIMENT=nosystemcrypto
is removed and rejected in Go 1.27. ignition's GOEXPERIMENT= (empty) did not
clear the platform baseline; butane supplied no override at all. The
darwin/windows cross-builds and ignition's native strictfipsruntime binary are
untouched.

Overlays are per-file documents under each component's overlays/ directory; both
components move from inline entries in components.toml to dedicated comp.toml
files so the overlays are discovered.
Copilot AI balanced review requested due to automatic review settings August 21, 2026 21:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Disables Microsoft Go systemcrypto for static, cgo-free Butane and Ignition cross-builds.

Changes:

  • Adds targeted component overlays.
  • Moves customized components into dedicated definitions.
  • Refreshes locks and rendered specs.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
base/comps/components.toml Removes inline component entries.
base/comps/butane/butane.comp.toml Adds dedicated Butane definition.
base/comps/butane/overlays/0001-disable-systemcrypto-static-cross-builds.overlay.toml Defines Butane workaround.
base/comps/ignition/ignition.comp.toml Adds dedicated Ignition definition.
base/comps/ignition/overlays/0001-disable-systemcrypto-static-cross-builds.overlay.toml Defines Ignition workaround.
locks/butane.lock Refreshes Butane fingerprint.
locks/ignition.lock Refreshes Ignition fingerprint.
specs/b/butane/butane.spec Applies workaround and release bump.
specs/i/ignition/ignition.spec Applies workaround and release bump.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@liunan-ms

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
2 pipeline(s) were filtered out due to trigger conditions.

@liunan-ms
Nan Liu (liunan-ms) marked this pull request as ready for review August 21, 2026 22:33
@liunan-ms
Nan Liu (liunan-ms) requested a review from a team as a code owner August 21, 2026 22:33
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