Skip to content

GoogleContainerTools/distroless images fail for confidential containers in ACI #2574

@dwhjames

Description

@dwhjames

Bug Report: GoogleContainerTools/distroless images fail for confidential containers in ACI

Summary

When deploying gcr.io/distroless/static-debian12@sha256:2b0f5abab12e4d6a533b91a4796d10504a05d8c41a61d4969889efb66daafece to Azure Container Instances (ACI) with confidential computing enabled, the deployment fails with "deviceHash not found" errors. Other images (e.g., mcr.microsoft.com/aci/skr:2.12) work successfully with the same infrastructure.

We have conducted extensive investigation and are seeking feedback from the hcsshim maintainers on potential causes and debugging approaches.

Environment

  • Failing Images:
    • gcr.io/distroless/static-debian12@sha256:2b0f5abab12e4d6a533b91a4796d10504a05d8c41a61d4969889efb66daafece
    • gcr.io/distroless/static-debian12:latest
    • gcr.io/distroless/cc-debian12:latest
    • any images layered on top of these
  • Working Images:
    • mcr.microsoft.com/aci/skr:2.12
    • Custom images built from scratch with Bazel using rules_distroless and rules_oci
  • Policy Generation: az confcom acipolicygen (Azure CLI confcom extension)
  • Deployment Target: Azure Container Instances with confidential computing
  • Dev Environment: macOS Darwin 26, Podman; Linux Debian Bookworm, Docker

Error Details

Full Error Message

Message: pulling image "<…>.azurecr.io/<…>/static-debian12@sha256:2b0f5abab12e4d6a533b91a4796d10504a05d8c41a61d4969889efb66daafece";
Successfully pulled image "<…>.azurecr.io/<…>/static-debian12@sha256:2b0f5abab12e4d6a533b91a4796d10504a05d8c41a61d4969889efb66daafece";
Error: Failed to start container distroless, Error response: to create containerd task: failed to create shim task: failed to mount container storage: failed to add LCOW layer: failed to add SCSI layer: mount scsi controller 0 lun 3 at /run/mounts/scsi/m2: guest RPC failure: mounting scsi device controller 0 lun 3 onto /run/mounts/scsi/m2 denied by policy: {"decision":"deny","input":{"deviceHash":"2a85d4c2663990ccd9fa75431898a43e4b6add34d68bc25288908b2946b9446d","mountPathRegex":"/run/mounts/scsi/m[0-9]+","rule":"mount_device","target":"/run/mounts/scsi/m2"},"reason":{"errors":["deviceHash not found"]}};
...
mount scsi controller 0 lun 7 at /run/mounts/scsi/m6: guest RPC failure: mounting scsi device controller 0 lun 7 onto /run/mounts/scsi/m6 denied by policy: {"decision":"deny","input":{"deviceHash":"56e7199031a6018c465f0fe348458e8f0c74f37547537f1f6f1beaba7bf7450b","mountPathRegex":"/run/mounts/scsi/m[0-9]+","rule":"mount_device","target":"/run/mounts/scsi/m6"},"reason":{"errors":["deviceHash not found"]}};
The container group provisioning has failed.

Investigation Performed

1. Local Hash Computation

We used a local build of dmverity-vhd from https://github.com/microsoft/integrity-vhd to compute root hashes locally:

./dmverity-vhd-darwin-amd64 --docker roothash \
  -i gcr.io/distroless/static-debian12@sha256:2b0f5abab12e4d6a533b91a4796d10504a05d8c41a61d4969889efb66daafece

Output:

WARN Errored while trying to parse OCI format: not able to parse in OCI format
Layer 0 root hash: fb8047aef725bf71a43923c23456270c74e74c92593aad752ef42ba9a1b9ce93
Layer 1 root hash: 59b808c419a9474a91c7c3d938405ed73a6149732c8c90fd5f541a17cff40441
Layer 2 root hash: f80e4f9375d4111eba47abc51d1a4a6ef82d215b824bc4642bc31f64fe0360f9
Layer 3 root hash: 8b4842f06982817534a75bcf71865213b09dfa8313229c384e5201dadbd75e25
Layer 4 root hash: f6b039e7dc0b28706659ff50d71330f8f63a4d17c729ca7bb375597e195501cd
Layer 5 root hash: 5b61d127749f53a0fe4898a6ae181470715093cea393e88327a59c3a68852998
Layer 6 root hash: 2c6f540907e3fd5b6182cded7492b68f8ce9332f30e89436afab59271c8592d8
Layer 7 root hash: ac3801059d83cfb321d565fb31653ae6e1a8741bc29c54fe6b1229b097e469e5
Layer 8 root hash: 7b4fbef988c8f7e20a7e469cf1109e74018bebac8221a5e27b0fdaac3b6f1772
Layer 9 root hash: 981cc31fc6ca57bb14cb155b43d45568859fdaf3dfb72b22dda3cdfb2e3a3da4
Layer 10 root hash: 2a85d4c2663990ccd9fa75431898a43e4b6add34d68bc25288908b2946b9446d

Of the various Confidential Computing Enforcement (CCE) policies we generated, via the
az confcom acipolicygen tooling (on Linux), we did see agreement with using the
dmverity-vhd tool directly (macOS).

2. Image Characteristics Analysis

We analyzed the distroless image layers and found:

Tar Format:

  • All layers use standard POSIX tar format (GNU tar/ustar)
  • Layer tar files themselves have epoch 0 timestamps (Dec 31 1969)
  • Files within layers have fixed timestamps
  • Extraction is consistent across macOS/BSD tar and GNU tar

Content:

  • 11 layers total
  • Contains 5 symlinks in base layer (e.g., etc/os-release -> ../usr/lib/os-release)
  • All symlinks are under 59 bytes (fit in inode)
  • Regular files: ~1400+
  • Directories: ~130+
  • No hardlinks, block devices, or character devices

Build Properties:

  • Built with Bazel (hermetic builds)
  • Uses rules_distroless and rules_oci Bazel rules

3. Code Analysis

We reviewed the hcsshim codebase (v0.13.0-rc.2; as pinned by integrity-vhd and thus azext_confcom) and observed:

ext4 Filesystem Creation (ext4/internal/compactext4/compact.go):

  • Directory entries sorted by inode number (lines 986-999)
  • Sequential inode allocation (line 395)
  • Extended attributes sorted alphabetically (line 481)
  • Zero-initialized UUID in ext4 superblock (lines 1315-1343)
  • Timestamps from tar headers (not time.Now())
  • Includes fix from commit 16dc8eb for parent directory timestamps

dm-verity (ext4/dmverity/dmverity.go):

  • Fixed zero salt (line 30)
  • SHA256 hash algorithm
  • Sequential Merkle tree construction
  • Superblock UUID is randomly generated (lines 137, 157-163)

Policy Validation (pkg/securitypolicy/framework.rego):

  • deviceHash checked against data.policy.containers[].layers[] array (lines 15-18)
  • deviceHash extracted from verityInfo.RootDigest (internal/guest/runtime/hcsv2/uvm.go:1188)

4. Comparison Tests

We compared the failing image with working images:

Working: mcr.microsoft.com/aci/skr:2.12

  • Also contains symlinks (100+)
  • Also uses epoch 0 timestamps in layer tars
  • Deployment succeeds

Working: Custom Bazel Images

  • Same Bazel rules used by GoogleContainerTools/distroless
    • github.com/bazel-contrib/rules_distroless
    • github.com/bazel-contrib/rules_oci
  • Published to Azure Container Registry
  • Deployment succeeds

Failing: gcr.io/distroless/*

  • Multiple variants tested (static-debian12, cc-debian12)
  • Policy generation appears to complete
  • Deployment fails with "deviceHash not found"

Questions for Maintainers

  1. Image Compatibility: Are there known compatibility issues with:

    • Images from GoogleContainerTools/distroless?
    • Images with specific layer characteristics?
  2. Debugging Approach: What further debugging steps would you recommend?

We are happy to provide additional information, run tests, or assist with debugging. Thank you for your time and expertise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions