Manage SSH Users, authorized_keys, and sudo

Good SSH access management separates people, service identities, keys, and privileged actions. Give each person a named account, each automation job a narrowly scoped identity, and each public key an owner and review date. Use authorized_keys restrictions to reduce what a key can do, then use sudo policy to limit elevation. Neither a key nor a sudo rule should be treated as proof that an account is entitled to every host action.

Never share a private key or a root login. Add a new administrator through a second, tested session, retain a documented recovery account, and remove old access through a reviewed change. Do not make a key valid everywhere merely because it is convenient.

Map accounts to responsibilities

Before creating an account, document its human owner or service owner, host scope, login shell, key source, required commands, and expiry or review date. A human administrator should normally use a named account and sudo. A deployment identity should normally have no interactive shell and should run only the deployment operation it needs. Do not use an application account as a shared human login.

# Inspect the existing boundary before changing it.
getent passwd
getent group ssh-admins
sudo sshd -T | grep -E '^(permitrootlogin|allowusers|allowgroups|pubkeyauthentication) '

Create users with your operating system’s supported account tool. For a named administrator on a Debian-family system:

sudo adduser alice
sudo usermod -aG sudo alice

Use the distribution’s administrator group and account lifecycle policy; do not assume the group is called sudo. Confirm the new account can log in with its own key before removing any old administrator access.

Install one public key safely

Generate the key on the client and transfer only its public half. The server-side directory and file must be owned by the account, not writable by other users. A trusted console or existing administrator session can prepare the location:

sudo -iu alice
umask 077
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
chown -R alice:alice ~/.ssh

Append the reviewed public key as one unwrapped line. Do not use a shell variable containing untrusted text or paste a private key. Check the resulting line with ssh-keygen -lf on a protected workstation or with the approved inventory.

# On the client, show the fingerprint of the public key.
ssh-keygen -lf ~/.ssh/id_ed25519_alice.pub

When using ssh-copy-id, specify the intended identity with -i and verify the host key first. A successful copy does not prove that the key has the intended restrictions or that the account is allowed by AllowUsers/AllowGroups.

Apply authorized_keys restrictions

Each key line may begin with comma-separated options. Restrictions are evaluated before the key is accepted and are valuable defense in depth, especially for automation keys. The following examples use private management addresses; replace them with the smallest approved source range or a single address.

# Human key: no agent, TCP, or X11 forwarding for this account key.
restrict,from="192.168.50.20" ssh-ed25519 AAAA... alice-admin

# Automation key: source-bound and forced to one reviewed command.
restrict,from="192.168.50.30",command="/usr/local/sbin/deploy-site" ssh-ed25519 AAAA... deploy-site

restrict disables PTY allocation, agent forwarding, X11 forwarding, and TCP forwarding (unless an explicit exception is added). It is supported by modern OpenSSH; on older systems, express the needed restrictions explicitly with no-pty, no-agent-forwarding, no-port-forwarding, and no-X11-forwarding. Other useful options include from=, command=, and carefully scoped environment=. Avoid environment= unless PermitUserEnvironment and the trust model have been reviewed.

A forced command must validate its input, not trust SSH_ORIGINAL_COMMAND, and must use absolute paths and a controlled environment. Remember that a forced command key can still expose output or act through whatever permissions the account has. Test it with a disposable, non-production target first.

Do not use no-port-forwarding as a substitute for a server-wide forwarding policy, and do not add command="..." to a human key unless the restriction is intentional and documented. Keep comments non-secret: they identify ownership, not a password or token.

Use sudo as a second boundary

Put narrowly scoped rules in a file under /etc/sudoers.d/, using a name that contains only letters, digits, underscore, or hyphen as required by the distribution. Edit with visudo, which checks syntax before installation.

sudo visudo -f /etc/sudoers.d/alice-site

# Example policy after reviewing the actual executable and arguments:
alice ALL=(root) /usr/bin/systemctl reload nginx
alice ALL=(root) /usr/bin/journalctl -u nginx --no-pager

Prefer a root-owned wrapper with fixed arguments when an operation needs several checks. Avoid granting a shell, an editor, an interpreter, package management, or a wildcard path: many such commands can execute arbitrary code as root. Do not add NOPASSWD unless the risk and recovery implications are explicitly accepted.

Validate and inspect the resulting policy:

sudo visudo -c
sudo -l -U alice

Test with the named account in a fresh session. A user’s SSH key authenticates that account; it does not bypass sudo’s authorization, password, MFA, logging, or command policy.

Rotate and revoke access

  1. Record the key fingerprint, owner, purpose, source restriction, and review date in the protected inventory.
  2. Enroll a replacement key and test it in a second session before removing the old key.
  3. Remove a lost, retired, or transferred key from every relevant authorized_keys file and revoke any agent copy on the client.
  4. Disable or expire the account through the normal identity process when its owner leaves or its service ends. Check scheduled jobs and recovery procedures before changing a service identity.
  5. Review ownership, modes, group membership, sudo rules, authentication logs, and the effective sshd -T policy.

Do not “revoke” by deleting a whole account directory or by removing files without an inventory; that can destroy evidence or break an unrelated service. Use the smallest reversible change and retain an approved backup of policy metadata, never private keys.

Continue with Transfer Files with SFTP, SCP, and rsync over SSH for controlled file movement.

Sequence navigation

Previous: Install and Harden an OpenSSH Server · Next: Transfer Files with SFTP, SCP, and rsync over SSH

References