Chezmoi externals behind a coorporate proxy

Posted in linux on June 17, 2025 by Adrian Wyssmann ‐ 4 min read

As you know I use https://wyssmann.com/blog/2022/08/chezmoi-a-very-cool-tool-to-manage-your-dotfiles/ to manage my dotfiles. One problem I face is using it in corparate environment with proxy that uses kerberos authentication. Just adding the external urls to .chezmoiexternal.toml will not work ase there is no native kerberos support.

Luckily there is curl which supports Kerberos authentication with –negotiate. In order to ensure that curl works by default with --netgotiate I add the following content into ~/.curlrc

--proxy-negotiate
-u :

The I create a script, that would run at the beginning e.g. run_before_get_packages.sh.tmpl:

#!/usr/bin/env bash
{{ if eq .chezmoi.os "linux" }}
TARGET_BIN_DIR="{{ .chezmoi.homeDir }}/Downloads/packages"

mkdir -p "$TARGET_BIN_DIR"

chezmoi_version=2.62.6
chezmoi_file=chezmoi_${chezmoi_version}
if [ ! -f $TARGET_BIN_DIR/${chezmoi_file} ]; then
  curl https://github.com/twpayne/chezmoi/releases/download/v${chezmoi_version}/chezmoi-linux-amd64 -L -o $TARGET_BIN_DIR/${chezmoi_file}
  cp $TARGET_BIN_DIR/${chezmoi_file} $TARGET_BIN_DIR/chezmoi
fi

atuin_version=18.6.1
atuin_file=atuin_${atuin_version}.tar.gz
if [ ! -f $TARGET_BIN_DIR/${atuin_file} ]; then
  curl https://github.com/atuinsh/atuin/releases/download/v${atuin_version}/atuin-x86_64-unknown-linux-musl.tar.gz -L -o $TARGET_BIN_DIR/${atuin_file}
  cp $TARGET_BIN_DIR/${atuin_file} $TARGET_BIN_DIR/atuin.tar.gz
fi

trivy_version=0.62.1
trivy_file=trivy_${trivy_version}.tar.gz
if [ ! -f $TARGET_BIN_DIR/${trivy_file} ]; then
  curl https://github.com/aquasecurity/trivy/releases/download/v${trivy_version}/trivy_${trivy_version}_Linux-64bit.tar.gz -L -o $TARGET_BIN_DIR/${trivy_file}
  cp $TARGET_BIN_DIR/${trivy_file} $TARGET_BIN_DIR/trivy.tar.gz
fi

skaffold_version=latest
skaffold_file=skaffold_${skaffold_version}
if [ ! -f $TARGET_BIN_DIR/${skaffold_file} ]; then
  curl https://storage.googleapis.com/skaffold/releases/${skaffold_version}/skaffold-linux-amd64 -L -o $TARGET_BIN_DIR/${skaffold_file}
  cp $TARGET_BIN_DIR/${skaffold_file} $TARGET_BIN_DIR/skaffold
fi

sonar_version=7.1.0.4889
sonar_file=sonar_${sonar_version}.zip
if [ ! -f $TARGET_BIN_DIR/${sonar_file} ]; then
  curl https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${sonar_version}-linux-x64.zip -L -o $TARGET_BIN_DIR/${sonar_file}
  cp $TARGET_BIN_DIR/${sonar_file} $TARGET_BIN_DIR/sonar.zip
fi

tflint_version=0.58.0
tflint_file=tflint_${tflint_version}.zip
if [ ! -f $TARGET_BIN_DIR/${tflint_file} ]; then
  curl https://github.com/terraform-linters/tflint/releases/download/v${tflint_version}/tflint_linux_amd64.zip -L -o $TARGET_BIN_DIR/${tflint_file}
  cp $TARGET_BIN_DIR/${tflint_file} $TARGET_BIN_DIR/tflint.zip
fi

tfupdate_version=0.9.1
tfupdate_file=tfupdate_${tfupdate_version}.tar.gz
if [ ! -f $TARGET_BIN_DIR/${tfupdate_file} ]; then
  curl https://github.com/minamijoyo/tfupdate/releases/download/v${tfupdate_version}/tfupdate_${tfupdate_version}_linux_amd64.tar.gz -L -o $TARGET_BIN_DIR/${tfupdate_file}
  cp $TARGET_BIN_DIR/${tfupdate_file} $TARGET_BIN_DIR/tfupdate.tar.gz
fi

tfdocs_version=0.20.0
tfdocs_file=tfdocs_${tfdocs_version}.tar.gz
if [ ! -f $TARGET_BIN_DIR/${tfdocs_file} ]; then
  curl https://github.com/terraform-docs/terraform-docs/releases/download/v${tfdocs_version}/terraform-docs-v${tfdocs_version}-linux-amd64.tar.gz -L -o $TARGET_BIN_DIR/${tfdocs_file}
  cp $TARGET_BIN_DIR/${tfdocs_file} $TARGET_BIN_DIR/tfdocs.tar.gz
fi

posh_version=26.8.0
posh_file=posh_${posh_version}
if [ ! -f $TARGET_BIN_DIR/${posh_file} ]; then
  curl https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v${posh_version}/posh-linux-amd64 -L -o $TARGET_BIN_DIR/${posh_file}
  cp $TARGET_BIN_DIR/${posh_file} $TARGET_BIN_DIR/oh-my-posh
fi
{{- end }}

This script will download the packages into {{ .chezmoi.homeDir }}/Downloads/packages. I currently only download it once - for new versions I have to update the version only here. I also ensure I don’t download it twice. The copy ensures the latest version is always find under the same name, this ensure I don’t have to umpate the .chezmoiexternal.toml.

Now, once the files are downloaded, I can use .chezmoiexternal.toml do extract the files into a dedicate place like ~/.local/share/externals/<toolname>

[ ".local/share/externals/trivy/" ]
    type = "archive"
    url = "file:///home/[email protected]/Downloads/packages/trivy.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true
[ ".local/share/externals/atuin/" ]
    type = "archive"
    url = "file:///home/[email protected]/Downloads/packages/atuin.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true
[ ".local/share/externals/tflint/" ]
    type = "archive"
    url = "file:///home/[email protected]/Downloads/packages/tflint.zip"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true
[ ".local/share/externals/tfdocs/" ]
    type = "archive"
    url = "file:///home/[email protected]/Downloads/packages/terraform-docs.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true
[ ".local/share/externals/skaffold/skaffold" ]
    type = "file"
    url = "file:///home/[email protected]/Downloads/packages/skaffold"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true
[ ".local/share/externals/oh-my-posh/oh-my-posh" ]
    type = "file"
    url = "file:///home/[email protected]/Downloads/packages/oh-my-posh"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
    executable = true

Now I have all (extracted) files in the same folder. At last, I will iterate over the folders and create a symlink to {{ .chezmoi.homeDir }}/.local/bin so I only have to add this folder to the PATH envioronment variable, so even adding a packed does not require updating the PATH

#!/usr/bin/env bash
{{ if eq .chezmoi.os "linux" }}
TARGET_BIN_DIR="{{ .chezmoi.homeDir }}/.local/bin"
SOURCE_BIN_DIR="{{ .chezmoi.homeDir }}/.local/externals"

mkdir -p "$TARGET_BIN_DIR"

for d in $SOURCE_BIN_DIR/*/ ; do
    echo "Executables in $d"
    for f in $d/* ; do
        echo "files $f"
        if [[ $f =~ "*" ]]; then
            echo "no binaries"
        else
            base_name=$(basename ${f})
            ln -sf $f "$TARGET_BIN_DIR/$base_name"
        fi
    done
done
{{- end }}

So now when I run chezmoi apply the script will run and download the files

...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   131  100   131    0     0    401      0 --:--:-- --:--:-- --:--:--   400
...

At last, the sym link is created

...
gpg: encrypted with 1 passphrase
Executables in /home/[email protected]/.local/externals/atuin/
files /home/[email protected]/.local/externals/atuin//atuin
Executables in /home/[email protected]/.local/externals/oh-my-posh/
files /home/[email protected]/.local/externals/oh-my-posh//oh-my-posh
Executables in /home/[email protected]/.local/externals/trivy/
files /home/[email protected]/.local/externals/trivy//trivy
Executables in /home/[email protected]/.local/externals/zellij/
files /home/[email protected]/.local/externals/zellij//zellij
Executables in /home/[email protected]/.local/externals/zoxide/
files /home/[email protected]/.local/externals/zoxide//zoxide
...

Unfoortunatley it does not work as expected - see Github Discussion as apply fails with

chezmoi apply
chezmoi: open /home/[email protected]/Downloads/packages/atuin_8.6.2.tar.gz: no such file or directory

So currently I have to

  1. Comment out the relevant section in .chezmoiexternal.toml.tmpl
  2. Run chezmoi apply
  3. Ucomment the relevant section in .chezmoiexternal.toml.tmpl
  4. Run chezmoi apply

Hope I find a better solution soon. Luckily at home I use NixOS so I have my packages at hand. But sometimes you have to use the distro your company offers you which may lack of desired packages, so these quirks are necessary.