Skip to content

Trust corporate TLS inspection chain in Docker builds (Alpine Drupal Composer)

Stephen Mulvihill edited this page Nov 11, 2025 · 1 revision

Background

Docker builds on our network fail with TLS errors (e.g., curl error 60, apk WARNING: Permission denied, Composer timeouts) because outbound HTTPS is intercepted by our departmental proxy. Containers don’t trust that proxy’s issuing CA chain by default.

Goal

Document and implement a clean solution so apk, curl, git, and composer work over HTTPS without disabling verification or using HTTP fallbacks.

Scope

Export the TLS inspection intermediate + root CAs used on our network.

Add those CAs to the repo and into the image trust store.

Verify with apk update, git ls-remote, and composer install.

Remove any temporary workarounds (e.g., secure-http=false, sslVerify=false, HTTP repos).

Step-by-step

  1. Identify and export the proxy CA chain (from your workstation or a throwaway container)

Replace the hostname with any external https host we need (Alpine CDN shown)

echo | openssl s_client -showcerts -servername dl-cdn.alpinelinux.org \
  -connect dl-cdn.alpinelinux.org:443 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{i++;f=sprintf("cert%02d.pem",i)} f{print > f} /END CERTIFICATE/{f=""}'

# Inspect each to label them
for f in cert*.pem; do
  echo "== $f =="; openssl x509 -in "$f" -noout -subject -issuer; done

You should see:

  • cert01.pem → leaf site (do not install)
  • cert02.pem → department proxy intermediate (install)
  • cert03.pem → GoC intermediate (install)
  • cert04.pem → GoC root (install)

Save/rename files as:

  • cert02.pem → docker/certs/dept-mitm-intermediate.crt
  • cert03.pem → docker/certs/gov-intermediate.crt
  • cert04.pem → docker/certs/gov-root.crt

Ensure they’re Base-64 PEM and use LF line endings.

  1. Install the CAs in Alpine (canonical way)

Add this to the Dockerfile before any HTTPS activity:

# Add the full inspection chain (dept intermediate + gov intermediate + gov root)
COPY docker/certs/dept-mitm-intermediate.crt /usr/local/share/ca-certificates/dept-mitm-intermediate.crt
COPY docker/certs/gov-intermediate.crt /usr/local/share/ca-certificates/gov-intermediate.crt
COPY docker/certs/gov-root.crt /usr/local/share/ca-certificates/gov-root.crt

# Normalize, merge into system trust, and provide /etc/ssl/cert.pem symlink
RUN apk add --no-cache ca-certificates openssl && \
    awk '{sub(/\r$/,"");print}' /usr/local/share/ca-certificates/dept-mitm-intermediate.crt > /tmp/a.crt && mv /tmp/a.crt /usr/local/share/ca-certificates/dept-mitm-intermediate.crt && \
    awk '{sub(/\r$/,"");print}' /usr/local/share/ca-certificates/goc-intermediate.crt > /tmp/b.crt && mv /tmp/b.crt /usr/local/share/ca-certificates/goc-intermediate.crt && \
    awk '{sub(/\r$/,"");print}' /usr/local/share/ca-certificates/goc-root.crt > /tmp/c.crt && mv /tmp/c.crt /usr/local/share/ca-certificates/goc-root.crt && \
    update-ca-certificates -v && \
    ln -sf /etc/ssl/certs/ca-certificates.crt /etc/ssl/cert.pem

Do not overwrite /etc/ssl/certs/ca-certificates.crt; let update-ca-certificates merge your CAs.

  1. Verify over HTTPS
# Alpine repos
apk update

# Generic HTTPS
curl -I https://dl-cdn.alpinelinux.org

# Git (Drupal GitLab)
git ls-remote https://git.drupalcode.org/project/webform_migrate.git | head -n1

# Composer
composer diagnose
composer install --no-interaction