Skip to main content
Mobile device management (MDM) deployment lets an IT administrator configure many developer machines at once. You generate a self-contained script, push it through your MDM tool, and it configures each machine’s package managers to route installations through Package Firewall. Developers do nothing, and existing package-manager configuration is preserved. The scripts covers the following ecosystems. They are idempotent, so they are safe to re-run on every MDM check-in, and they have no runtime dependencies beyond the shell.
The scripts are available in the Endor Labs MDM scripts repository under the package-firewall/ directory.

Before you begin

Create an API key dedicated to the Package Firewall so that can authenticate to it. You can create it through one of the following methods:
  • Using the Endor Labs user interface, with the Package Firewall User role. See API keys to learn more.
  • Using endorctl, with the SYSTEM_ROLE_PACKAGE_FIREWALL role. Make sure to install and configure endorctl before you create the key.
To create the key using endorctl, run the following command and replace:
  • <namespace> with your namespace.
  • <API key name> with the name of the API key for the Package Firewall use case.
  • <YYYY-MM-DDTHH:MM:SSZ> with the API key expiration in ISO 8601 UTC format, for example 2026-12-31T23:59:59Z.
export NAMESPACE="<namespace>"
export KEY_NAME="<API key name>"

endorctl api create -r APIKey -n "$NAMESPACE" --data '{
  "meta": { "name": "'"$KEY_NAME"'" },
  "spec": {
    "permissions": { "roles": ["SYSTEM_ROLE_PACKAGE_FIREWALL"] },
    "expiration_time": "<YYYY-MM-DDTHH:MM:SSZ>"
  },
  "propagate": true
}'

Generate the MDM scripts

Clone the generator repository and run it with your namespace and Package Firewall credentials. Select your platform for the matching commands.
You can also generate the scripts in the browser using the MDM script generator. The generator fetches the real source files from the Endor Labs MDM scripts repository (https://github.com/endorlabs/mdm-scripts). The GitHub repository is the authoritative source for the scripts.
  1. Clone the generator repository: Clone the repository and change into the bash generator directory.
    git clone https://github.com/endorlabs/mdm-scripts
    cd mdm-scripts/package-firewall/bash
    
  2. Generate the scripts: Pass your credentials as environment variables. This keeps them out of your shell history.
    ENDOR_NAMESPACE=<namespace> \
    ENDOR_API_KEY_ID=<api-key-id> \
    ENDOR_API_SECRET=<api-secret> \
    ./generate.sh
    
    Alternatively, store the variables in a .env file, add .env to .gitignore, and source it.
    set -a; source .env; set +a
    ./generate.sh
    
The generator writes endor-js.sh, endor-python.sh,endor-go.sh, endor-all.sh, and endor-remove.sh to out/<namespace>/. Re-running generate.sh overwrites the same directory.
The generated scripts contain your API key and secret in plaintext, because the scripts need them to write credentials on each device. Treat the scripts, and the MDM policy that holds them, as secrets. Restrict access to the policy, add the out/ directory to .gitignore, and rotate your API key if a script is exposed.

Upload the scripts to your MDM tool

Each generated script is self-contained with no runtime dependencies, so you upload it directly to your MDM tool. On macOS and Linux the scripts use the .sh extension; on Windows they use .ps1.
Run the scripts as root. The script detects the logged-in console user and writes configuration files to the correct home directory.
  1. Add the script: Go to Library > Custom Scripts > Add Script.
  2. Provide the script: Paste the script content or upload the file.
  3. Set the run context: Set Run as to Root.
  4. Set the frequency: Set Execution Frequency to Run once per device, or to every check-in for ongoing enforcement.
  5. Assign the script: Assign the script to the relevant device blueprint.
  1. Add the script: Go to Settings > Scripts > New and paste the script content.
  2. Create a policy: Go to Policies > New Policy > Scripts and add your script.
  3. Set the frequency: Set the Execution Frequency as appropriate.
  4. Scope the policy: Scope the policy to the target devices.
Upload the script file and run it as root. The script detects the logged-in console user and writes configuration files to the correct home directory.

How credentials are stored

The scripts write your credentials to a single source on each device and reference them from the package-manager configuration files. The storage mechanism depends on your platform.
The scripts write all credentials to ~/.config/endor/env.sh and set the file permissions to 600.
export ENDOR_API_KEY_ID="..."
export ENDOR_API_SECRET="..."
export ENDOR_AUTH_B64="..."          # base64(key:secret) for npm, pnpm, yarn, and bun
export ENDOR_NPM_REGISTRY_URL="..."  # for npm and yarn 2+
export ENDOR_PYPI_URL="..."          # for uv
export ENDOR_GO_PROXY_URL="..."      # GOPROXY URL (also written literally to the go env file)
export POETRY_HTTP_BASIC_ENDOR_FIREWALL_USERNAME="..."
export POETRY_HTTP_BASIC_ENDOR_FIREWALL_PASSWORD="..."
Each shell profile (.zshrc, .bash_profile, and .bashrc) gets a one-line block that sources this file. The configuration files reference these variables instead of embedding credentials, except pip.conf and the go env file, which cannot expand variables.To rotate credentials, redeploy the MDM script to update env.sh on the target machines. No configuration file changes are needed.

What the scripts do

Each install script writes the credential store and an Endor-managed block to the package-manager configuration files. The file locations depend on your platform.
The endor-js.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following files.The endor-go.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following file.The endor-python.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following files.

How each package manager is configured

The scripts apply a few package-manager-specific behaviors that are the same on every platform.
  • JavaScript: The scripts write _auth (base64) instead of _authToken, which bun requires. Yarn classic reads authentication from .npmrc, so the .npmrc write covers it. The scripts do not write the project-level bunfig.toml.
  • Go: The scripts resolve the go env file path with go env GOENV, then write GOPROXY to it. If go is not installed, they fall back to the OS default path (~/Library/Application Support/go/env on macOS, ~/.config/go/env on Linux, or %APPDATA%\go\env on Windows). Credentials are literal because go env files cannot expand environment variables. The GOPROXY value ends in ,direct, so Go downloads a module directly from its source when the firewall does not serve it. The go env file applies to every go command regardless of shell, and it has lower precedence than the GOPROXY process variable, so project-level overrides still work.
  • Python (pip): The scripts use a named [endor-firewall] section, so they preserve any existing [global] settings. Credentials are literal because pip cannot expand environment variables.
  • Python (uv): uv ignores pip.conf, so the scripts write the user-level uv.toml, which references the ENDOR_PYPI_URL variable.
  • Python (poetry): poetry reads credentials from the POETRY_HTTP_BASIC_ENDOR_FIREWALL_* environment variables, so no separate write step is needed. Add the source to your pyproject.toml:
Poetry reads the registry URL from pyproject.toml and the credentials from environment variables. Add the Package Firewall as a source in each project. The source includes the URL only, never the credentials.
[[tool.poetry.source]]
name = "endor-firewall"
url = "https://factory.endorlabs.com/v1/namespaces/<namespace>/firewall/pypi/simple/"
priority = "primary"

Preserve existing configuration

The scripts use a sentinel block pattern. Each script writes only a clearly delimited section to a configuration file and leaves everything else untouched, so existing settings survive every deployment. The following example shows an .npmrc file that already contains administrator settings. The script adds only the Endor-managed block between the BEGIN and END markers.
# Existing configuration — never touched
legacy-peer-deps=true

# ===== BEGIN ENDOR PACKAGE FIREWALL (managed — do not edit) =====
registry=https://factory.endorlabs.com/v1/namespaces/<namespace>/firewall/npm/
always-auth=true
//factory.endorlabs.com/v1/namespaces/<namespace>/firewall/npm/:_auth=${ENDOR_AUTH_B64}
# ===== END ENDOR PACKAGE FIREWALL =====
The following table describes how the scripts handle each configuration scenario.

Remove the configuration

To offboard a machine, deploy the remove script. It strips the Endor block from every managed file and removes the credentials the install scripts added.
Deploy endor-remove.sh. It removes the Endor block from each configuration file and removes the credentials from ~/.config/endor/env.sh.

Security notes

The scripts store credentials on each device. Review the following before you deploy.

Generate your MDM script in the browser

Select your platform, ecosystem, and MDM tool, then enter your namespace and API key. The script is generated entirely in your browser: your credentials are never sent to Endor Labs or GitHub, only baked into the script you download.
The generated script contains your API key and secret in plaintext, because they are needed to write credentials on each device. Treat the script, and the MDM policy that holds it, as secrets. Restrict who can view the policy, add generated scripts to .gitignore, and rotate your API key if a script is exposed.