This field note documents the engineering workstation baseline used across the runbooks and field notes in this site. It is a living document — tools are added as they prove value and removed when they are retired.
OS Selection
Two distributions cover the majority of infrastructure engineering environments:
| Distribution | Strengths | Considerations |
|---|---|---|
| Ubuntu LTS (24.04+) | Broad package availability, largest community, NVidia driver support, first-class Snap/Flatpak support | Canonical’s Snap push can be invasive; pin to LTS to avoid churn |
| Debian Stable (12+) | Rock-solid stability, no corporate backing, minimal pre-installed cruft | Older packages; backports or third-party repos needed for newer tooling |
Both run the same toolchain. The choice is primarily about release cadence and package freshness vs. stability.
Hardware minimums for a daily-driver management workstation:
- CPU: 4+ cores (8 recommended for local container builds)
- RAM: 16 GB minimum, 32 GB recommended (multiple kubeconfigs, browser tabs, local kind/microk8s clusters)
- SSD: 256 GB minimum, 512 GB recommended (container images, multiple tool versions, git repos)
- Network: Reliable connectivity to cloud APIs, VPN, and internal infrastructure
Core Toolchain
Package Management
# Ubuntu / Debian
sudo apt update && sudo apt install -y \
curl wget git jq yq unzip \
gnupg lsb-release ca-certificates \
direnv tree htop iotop
# Enable unattended security upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Kubernetes Tooling
# kubectl — always match the cluster version or one minor version ahead
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install kubectl /usr/local/bin/ && rm kubectl
# Helm
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Velero CLI
curl -LO https://github.com/vmware-tanzu/velero/releases/latest/download/velero-v1.15.0-linux-amd64.tar.gz
tar xzf velero-*-linux-amd64.tar.gz && sudo mv velero-*/velero /usr/local/bin/ && rm -rf velero-*
# kustomize
curl -fsSL https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash
sudo mv kustomize /usr/local/bin/
# stern — tail multiple pods and containers
curl -Lo stern.tar.gz https://github.com/stern/stern/releases/latest/download/stern_*_linux_amd64.tar.gz
tar xzf stern.tar.gz && sudo mv stern /usr/local/bin/ && rm stern.tar.gz
# Popeye — cluster health scanner
curl -Lo popeye.tar.gz https://github.com/derailed/popeye/releases/latest/download/popeye_linux_amd64.tar.gz
tar xzf popeye.tar.gz && sudo mv popeye /usr/local/bin/ && rm popeye.tar.gz
Infrastructure-As-Code
# Terraform — use tfenv to pin per-project versions
git clone https://github.com/tfutils/tfenv.git ~/.tfenv
~/.tfenv/bin/tfenv install latest
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bashrc
# Terragrunt
curl -Lo terragrunt https://github.com/gruntwork-io/terragrunt/releases/latest/download/terragrunt_linux_amd64
sudo mv terragrunt /usr/local/bin/ && chmod +x /usr/local/bin/terragrunt
# tflint
curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
# Checkov — policy-as-code scanner
pip3 install checkov
Cloud CLIs
# AWS CLI v2
curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip
unzip awscliv2.zip && sudo ./aws/install && rm -rf aws awscliv2.zip
# Vault CLI
curl -fsSL https://releases.hashicorp.com/vault/1.18.0/vault_1.18.0_linux_amd64.zip -o vault.zip
unzip vault.zip && sudo mv vault /usr/local/bin/ && rm vault.zip
# govc (vSphere CLI)
curl -Lo govc.tar.gz https://github.com/vmware/govmomi/releases/latest/download/govc_$(uname -s)_$(uname -m).tar.gz
tar xzf govc.tar.gz && sudo mv govc /usr/local/bin/ && rm govc.tar.gz
Containers
# Docker CE
curl -fsSL https://get.docker.com | bash
sudo usermod -aG docker $USER
# Dive — container layer inspection
curl -Lo dive.tar.gz https://github.com/wagoodman/dive/releases/latest/download/dive_*_linux_amd64.tar.gz
tar xzf dive.tar.gz && sudo mv dive /usr/local/bin/ && rm dive.tar.gz
General Tooling
# bat — cat with syntax highlighting
sudo apt install -y bat # or: https://github.com/sharkdp/bat
# fzf — fuzzy finder
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install
# ripgrep — fast recursive grep
sudo apt install -y ripgrep
# httpie — human-friendly curl alternative
pip3 install httpie
# age — simple file encryption
sudo apt install -y age
Shell Hygiene
Kubectl Aliases And Completions
cat >> ~/.bashrc << 'EOF'
source <(kubectl completion bash)
alias k='kubectl'
alias kg='kubectl get'
alias kd='kubectl describe'
alias kdel='kubectl delete'
alias kl='kubectl logs'
alias kaf='kubectl apply -f'
alias kx='kubectl ctx' # requires kubectx
alias kn='kubectl ns' # requires kubens
# Switch context with tab completion
complete -F __start_kubectl k
EOF
# kubectx / kubens
sudo git clone https://github.com/ahmetb/kubectx /opt/kubectx
sudo ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
sudo ln -s /opt/kubectx/kubens /usr/local/bin/kubens
KUBECONFIG Management
The default ~/.kube/config merge approach becomes unwieldy with more than a few clusters.
If a newly downloaded kubeconfig works by itself but fails when merged with the workstation’s normal KUBECONFIG, check for duplicate user names and stale token shadowing before changing cluster RBAC. See KUBECONFIG Merge Order Can Shadow Fresh Rancher Tokens.
# Per-project kubeconfig directories
mkdir -p ~/.kube/configs
# Source the right config in each project via direnv
cat >> ~/.bashrc << 'EOF'
# KUBECONFIG merge helper — merges everything in ~/.kube/configs/
export KUBECONFIG=$(ls ~/.kube/configs/*.yaml 2>/dev/null | tr '\n' ':')
EOF
Create a .envrc per project to pin the kubeconfig:
# In each project root
echo 'export KUBECONFIG=~/.kube/configs/production.yaml' > .envrc
direnv allow
Terraform Workspace Prompt
# Show terraform workspace in the prompt
cat >> ~/.bashrc << 'EOF'
parse_terraform_workspace() {
if [ -f .terraform/environment ]; then
echo " (tf:$(cat .terraform/environment))"
fi
}
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(parse_terraform_workspace)\$ '
EOF
Session Persistence
Infrastructure work spans long-running apply operations, multi-step incident responses, and context switches across terminals.
Tmux
sudo apt install -y tmux
# Minimal configuration
cat >> ~/.tmux.conf << 'EOF'
set -g default-terminal "screen-256color"
set -g history-limit 50000
set -g mouse on
bind | split-window -h
bind - split-window -v
bind r source-file ~/.tmux.conf \; display-message "Reloaded"
EOF
Patterns:
| Situation | Tmux Pattern |
|---|---|
| Terraform plan/apply | tmux new -s infra-apply — stay attached until complete |
| Incident response | tmux new -s incident-<ticket> with panes for logs, kubectl, runbook |
| Long tail of tailing logs | Detach (C-b d) and reattach later (tmux attach -t <session>) |
| Multi-cluster operations | One window per cluster, named by context |
Secret Hygiene
Credentials live on the workstation temporarily and are never stored in plain text.
# Age key generation — one per workstation, backed up offline
age-keygen -o ~/.config/age/key.txt
chmod 600 ~/.config/age/key.txt
# Encrypt a secrets file
age -e -r "$(cat ~/.config/age/key.txt | age-keygen -y)" -o secrets.env.age secrets.env
# Decrypt inline
age -d -i ~/.config/age/key.txt secrets.env.age
# SOPS integration
cat >> ~/.sops.yaml << 'EOF'
creation_rules:
- age: >-
age1...
EOF
Never do these:
- Store cloud provider keys in
~/.bashrcor shell history - Commit
.envfiles to git - Use the same SSH key for GitHub and infrastructure access
- Leave
vault logintokens in the terminal scrollback
Bootstrap Automation
The entire workstation should be reproducible from a blank install.
# ~/bootstrap/bootstrap.sh — idempotent workstation setup
# Keep this in a private git repo
#!/usr/bin/env bash
set -euo pipefail
sudo apt update && sudo apt upgrade -y
# Install all tools (functions above)
# Clone dotfiles
# Set up SSH keys (requires out-of-band transfer)
# Install VS Code / extensions
A bootstrap script should be idempotent — running it twice produces the same result. Use which <tool> guards or install -C for binaries.
When To Update This Document
- A new CLI becomes part of the standard incident response workflow
- A tool in the chain reaches end-of-life or is superseded
- The team standardizes on a different container runtime or orchestrator
- A security practice changes (e.g., hardware SSH keys, new encryption scheme)