Configure registry: CI/CD
Route CI installs through the firewall with environment variables, so existing build commands don't change.
In CI, set the registry and certificate through environment variables. Your existing npm ci and pip install -r requirements.txt steps stay exactly as they are, and a blocked package fails the job.
Before you start: CI runners can reach sfw.example.com on 443, and you have the firewall's CA certificate (skip the CA steps if the firewall uses a certificate from a CA your runners already trust).
The four variables
| Variable | Value | For |
|---|---|---|
NPM_CONFIG_REGISTRY | https://sfw.example.com/npm/ | npm, pnpm, Yarn 1 |
NODE_EXTRA_CA_CERTS | path to sfw-ca.pem | npm and Node |
PIP_INDEX_URL | https://sfw.example.com/pypi/simple/ | pip |
PIP_CERT | path to a CA bundle that includes the firewall CA | pip |
Store the CA as a CI secret or file variable, write it to disk at the start of the job, and set the variables.
PIP_CERTreplaces pip's whole bundlePoint
PIP_CERTat the firewall CA alone and every other HTTPS fetch pip makes (git+https, an extra index) fails. Where you can runupdate-ca-certificates, add the firewall CA to the system store and pointPIP_CERTat the system bundle (/etc/ssl/certs/ca-certificates.crt).NODE_EXTRA_CA_CERTSadds to Node's list, so it can point at the firewall CA alone.
GitHub Actions
jobs:
build:
runs-on: ubuntu-latest
env:
NPM_CONFIG_REGISTRY: https://sfw.example.com/npm/
PIP_INDEX_URL: https://sfw.example.com/pypi/simple/
steps:
- uses: actions/checkout@v4
- name: Install firewall CA
run: |
printf "%s\n" "$SFW_CA_PEM" | sudo tee /usr/local/share/ca-certificates/sfw-ca.crt > /dev/null
sudo update-ca-certificates
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/sfw-ca.crt" >> "$GITHUB_ENV"
echo "PIP_CERT=/etc/ssl/certs/ca-certificates.crt" >> "$GITHUB_ENV"
env:
SFW_CA_PEM: ${{ secrets.SFW_CA_PEM }}
- run: npm ciThe CA path is set through $GITHUB_ENV because job-level env can't reference the runner context, and the secret goes through env rather than being interpolated into the script.
GitLab CI
variables:
NPM_CONFIG_REGISTRY: https://sfw.example.com/npm/
PIP_INDEX_URL: https://sfw.example.com/pypi/simple/
build:
script:
# SFW_CA_PEM is a File-type CI/CD variable (its value is a path)
- cp "$SFW_CA_PEM" /usr/local/share/ca-certificates/sfw-ca.crt && update-ca-certificates
- export NODE_EXTRA_CA_CERTS="$SFW_CA_PEM" PIP_CERT=/etc/ssl/certs/ca-certificates.crt
- npm ciContainer-based runners: bake it in once
If your builds run in your own image, put the CA and variables in the image and no pipeline changes at all:
COPY sfw-ca.pem /usr/local/share/ca-certificates/sfw-ca.crt
RUN update-ca-certificates
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/sfw-ca.crt \
PIP_CERT=/etc/ssl/certs/ca-certificates.crt \
NPM_CONFIG_REGISTRY=https://sfw.example.com/npm/ \
PIP_INDEX_URL=https://sfw.example.com/pypi/simple/Alpine and distroless bases need the ca-certificates package for update-ca-certificates to exist.
If runners can't resolve sfw.example.com through DNS, add it at runtime: docker run --add-host sfw.example.com:10.0.0.5 ....
Verify
Run one passing build, then add lodahs to a test branch's package.json and run again.
- The clean build passes
- The test build fails at install with
E403 ... Blocked by Security Policy - The firewall logs show requests from the runner's IP
Notes
- Lockfiles:
package-lock.jsonrecordsregistry.npmjs.orgURLs. Current npm versions swap that host for the configured registry automatically (replace-registry-host, defaultnpmjs), sonpm ciworks without regenerating the lockfile. - Caches: a warm dependency cache on the runner skips the firewall entirely for cached packages. Clear it once when you switch.
- Different from Socket scanning in CI: this blocks at install time. Pull request scanning with the Socket CLI or GitHub App is a separate integration.
Reference
Updated 8 days ago