Last active
July 23, 2024 17:31
-
-
Save luizberti/bc9dd3b17508d8fdf197d2a3a69ebf2d to your computer and use it in GitHub Desktop.
My stash of useful and perhaps over-engineered POSIX tricks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -o errexit | |
set -o pipefail | |
set -o nounset | |
if [ "$EUID" = 0 ]; then echo "DO NOT RUN THIS AS ROOT!" >&2 && exit 1; fi | |
# GLOBAL PARAMETERS | |
user='luizberti' # sometimes used when $USER would yield incorrect results | |
# USER AND SSH KEY MANAGEMENT | |
# =========================== | |
# MAKE USER A PASSWORDLESS SUDOER FOR NON-INTERACTIVE USE (LINUX ONLY) | |
# 1. You need to set the `user` variable to the user this operation should take effect on; | |
# 2. This operation needs to be performed by a user who is already a non-interactive sudoer, | |
# or by the `root` user itself by stripping the `sudo` from the second command; | |
# 3. Provided the conditions from nº 2 are satisfied, this command runs non-interactively; | |
# 4. `visudo` validates that the edit hasn't corrupted the sudoers file, as it's dangerous | |
# to edit the file without it. If the edit fails validation, this command will error; | |
# 5. Setting $EDITOR to `tee -a` causes `visudo` to open it, rather than an interactive | |
# editor to modify the sudoers file. `tee -a` will slurp STDIN appending to sudoers | |
# non-interactively and then exiting. | |
user_promote-to-passwordless-sudoer() ( | |
# ENV PARAM user: the user the operation should be performed on | |
set -o errexit | |
set -o pipefail | |
set -o nounset | |
# TODO add to `wheel` group instead of granting passwordless sudoing directly? | |
echo "$user ALL=(ALL) NOPASSWD:ALL" | sudo EDITOR='tee -a' visudo > /dev/null | |
) | |
# IDEMPOTENTLY CREATE NEW PASSWORD-LESS SSH KEY | |
# 1. Most non-interactivity is provided by `-q -N ''`, which enables quiet mode and sets | |
# the password to an empty-string, which disables the password prompt; | |
# 2. Security parameter is set by `-a 100`, which at this time seems like a good margin; | |
# 3. Stores key in new format with `-o`, only supported by OpenSSH 6.5+. This is already | |
# the default for Ed25519 keys, but this makes it explicit, and allows an easier | |
# adaptation of this command to produce RSA keys; | |
# 4. Key type is set to Ed25519 instead of RSA with the `-t ed25519` option; | |
# 5. The output path for generated keys is specified with `-f <path>`. Private key is | |
# written to `<path>`, public is written to `<path>.pub`; | |
# 6. Key comment is set with `-C <comment>`. I generally use either `luizberti`, `<hostname>` | |
# when the key is bound to a specific computer, `luizberti@<hostname>` when the key is | |
# bound to a shared computer, or work email for corporate infrastructure; | |
# 7. The `< /dev/zero` makes that file STDIN for the process. This answers a "no" to the | |
# "overwrite?" prompt that shows up if the `-f` argument already exists, making the command | |
# more idempotent, and bypassing that interaction for better non-interactivity; | |
# 8. The tailing `&>/dev/null` shushes the rest of the outputs that haven't been turned off | |
# by the "quiet" option, such as the prompt from nº 7; | |
# 9. The `ssh-add` part ensures the identity is added to ssh-agent for Agent Forwarding and | |
# other features to work properly. On macOS it needs to use the `-K` flag so that the identity | |
# is added to the user's keychain otherwise it won't persist across reboots, while on Linux | |
# it's just added to the ssh-agent directly. | |
ssh_keygen() ( | |
# ENV PARAM name: choose name for key as `id_ed25519.<name>[.pub], if empty defaults to `id_ed25519[.pub]` | |
# ENV PARAM comment: set the key's comment, if unset defaults to $USER | |
set -o errexit | |
set -o nounset | |
local file="$(if [ -z "${name:-}" ]; then echo id_ed25519; else echo id_ed25519."$name"; fi)" | |
ssh-keygen -q -N '' -o -a 100 -t ed25519 -f ~/.ssh/"$file" -C "${comment:=$USER}" </dev/zero &>/dev/null | |
if [ "$(uname -s)" = Darwin ]; then ssh-add --apple-use-keychain ~/.ssh/"$file"; else ssh-add ~/.ssh/"$file"; fi | |
) | |
# SETS CORRECT PERMISSIONS FOR SSH KEYS | |
# 1. This command takes effect on the SSH directory relative to the calling user, thus you should | |
# not be in a rooted shell for this, else it will point at the wrong directories and give the | |
# wrong $USER the permissions; | |
# 2. You might need to customize the fourth command if you have private keys that aren't named | |
# as `id_*`. A good naming scheme for keys is `id_<algorithm>.<purpose>[.pub]`, and you should | |
# try using that or something like it if possible (e.g. id_ed25519.build-server[.pub]); | |
# 3. The `touch` command ensures that the configuration and access management files are present, | |
# so that they can pick up the correct permissions from the subsequent commands; | |
# 4. The `chown` command ensures that the current user's SSH directory and its contents are owned | |
# by that user; | |
# 5. The `chmod` commands modify its permissions relative to the owner set by `chown`. 700 on a | |
# directory allows only the owner to write to the directory, 600 allows only the owner to read | |
# and write to them, 644 allows only the owner to write but makes it globally readable | |
ssh_fix-permissions() ( | |
set -o errexit | |
sudo mkdir -p ~/.ssh | |
sudo touch ~/.ssh/{authorized_keys,known_hosts,config} | |
sudo chown $USER:$USER ~/.ssh ~/.ssh/* | |
sudo chmod 700 ~/.ssh | |
sudo chmod 600 ~/.ssh/id_* # could arguably be ~/.ssh/* but let's be conservative | |
sudo chmod 644 ~/.ssh/*.pub | |
sudo chmod 644 ~/.ssh/{authorized_keys,known_hosts,config} | |
) | |
# SUBCOMMAND INVOKATION LOGIC AND FLAG PARSING | |
# ============================================ | |
AVAILABLE="$(declare -F | awk '{print $NF}')" | |
"$1" "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment