norboten · cheat sheet

Every place a secret can leak from — cheat sheet

ai-services, users-permissions, logging-journald
# what an unprivileged account can see
sudo -u nobody systemctl show UNIT | grep -i key
sudo -u nobody systemctl cat UNIT  | grep -i key
ps -eo args | grep '[s]ecret'                  # command lines are public
sudo cat /proc/PID/environ | tr '\0' '\n'      # the process environment (owner and root)
sudo grep -rlF -f /path/to/secretfile /etc     # every copy under /etc — NOT grep "$SECRET":
                                               #   sudo logs the command line, secret included

# homes for a secret, best last
chown SVC:SVC /etc/app/key ; chmod 600 /etc/app/key     # a private file, read by path
# EnvironmentFile=/etc/app/env        with the env file 0600 root:root
# LoadCredential=name:/etc/app/key    → $CREDENTIALS_DIRECTORY/name, this unit only
systemd-creds encrypt --name=name plain.txt /etc/credstore.encrypted/name   # + LoadCredentialEncrypted=
# never: Environment= in a unit, or a flag on ExecStart=
sed -i '/^Environment=SECRET=/d' /etc/systemd/system/UNIT.service ; systemctl daemon-reload

# authentication
curl -s -o /dev/null -w '%{http_code}\n' URL                          # expect 401 anonymously
curl -s -H "Authorization: Bearer $tok" URL                          # expect 200
# 401 = who are you?   403 = I know who you are, and no.
# compare tokens in constant time: hmac.compare_digest(a, b)

# nginx rate limiting
# http{}:     limit_req_zone $binary_remote_addr zone=NAME:10m rate=2r/s;
#             limit_req_zone $http_authorization zone=pertoken:10m rate=2r/s;   (per client token)
# location{}: limit_req zone=NAME burst=5 nodelay;
#             limit_req_status 429;            (default is 503)
#             limit_req_dry_run on;            (log, do not reject — for choosing numbers)
#             limit_conn_zone / limit_conn     (concurrency rather than rate)
nginx -t && systemctl reload nginx
seq 40 | xargs -P 10 -I{} curl -s -o /dev/null -w '%{http_code}\n' URL | sort | uniq -c

# logs
id=$(systemctl show -p InvocationID --value UNIT)
journalctl _SYSTEMD_INVOCATION_ID=$id --no-pager       # this run only
journalctl -u UNIT --no-pager | grep -cF -f SECRETFILE  # all of history (pattern from a file)
journalctl --rotate ; journalctl --vacuum-time=1s      # purge (deletes ALL history)
getent group adm systemd-journal                       # who can read the journal
# never log: Authorization, Cookie, Set-Cookie, X-Api-Key, auth request bodies

# after any leak
# rotate the key at the provider, revoke the old one, reissue client tokens