PAM password expiration behavior during non-interactive SSH sessions
0 reputation · 28 Jun 2026, 12:28 UTC
0 reputation · 28 Jun 2026, 12:28 UTC
Linux systems utilize the pam_unix and pam_expire modules to enforce password aging policies based on the /etc/shadow file. While these modules consistently force a password change during local TTY logins, the behavior varies when credentials expire for users connecting via non-interactive SSH sessions (e.g., SFTP or automated SCP transfers).
The goal is to maintain a least-privilege security posture where expired credentials immediately invalidate all access paths, regardless of the session type. However, there is uncertainty regarding how different PAM stack configurations handle the expiration trigger when no interactive shell is available to prompt the user for a new password.
pam_expire consistently deny access to non-interactive SSH sessions when a password has expired, or does it allow the session to proceed if no TTY is allocated?pam_unix and pam_expire differ across common Linux distributions when handling expired credentials for automated service accounts?34775 reputation · 28 Jun 2026, 13:07 UTC
pam_expire is not TTY-aware. It runs in the PAM account phase and returns PAM_NEW_AUTHTOK_REQD when /etc/shadow aging fields require a password change. The application—here, sshd—must decide what to do with that status. With OpenSSH compiled with PAM support and UsePAM yes, a non-interactive SFTP or SCP session that receives PAM_NEW_AUTHTOK_REQD is treated as a failed authentication, not as a successful login. A missing TTY does not turn that return code into success; it simply means sshd cannot satisfy the requirement by prompting.
The confirmed behavior is that pam_expire signals aging in the account phase and that sshd's PAM path enforces it when PAM is active. The likely explanation for observed variation is not TTY detection inside PAM, but differences in the local PAM stack and sshd configuration:
/etc/pam.d/sshd (or an included file) omits an account-phase pam_unix.so or pam_expire.so check, an expired password may never produce PAM_NEW_AUTHTOK_REQD for that connection.optional or sufficient control flags, or a bypass rule precedes it, the expiration can be non-fatal even when the module exists.UsePAM no, it may perform its own shadow checks and never invoke pam_expire, changing the decision point entirely.Debian and Ubuntu systems typically assemble the sshd account stack through pam-auth-update includes such as common-account. RHEL-family distributions commonly include password-auth or system-auth. In both cases, whether pam_expire.so is present, whether pam_unix.so is marked required or requisite, and whether a management tool has rewritten the files are local configuration choices. These choices—not the presence of a TTY—explain most cross-distro inconsistency.
Key-based authentication does not automatically bypass the PAM account phase when sshd runs PAM. If the service account's password is aged and the stack returns PAM_NEW_AUTHTOK_REQD, automation will fail. If your security policy requires expiration to invalidate all access paths, keep the account-phase check and expect non-interactive sessions to be denied. If policy permits an exception for that account, disable password aging for it explicitly and rely on key restrictions; do not weaken aging globally.
grep -E '^account' /etc/pam.d/sshd. Then inspect any included files (for example, common-account or system-auth).sshd -T | grep -i usepam.chage -l testacct and passwd -S testacct.chage -d 0 testacct, attempt sftp testacct@host and scp file testacct@host:, then inspect the log with journalctl -u sshd or /var/log/auth.log / /var/log/secure.If your stack already contains an account-phase check and UsePAM is enabled, the detail that determines the next step is the server-side log message: does the failed non-interactive attempt show PAM_NEW_AUTHTOK_REQD or a password-expiry message, or does the connection simply close with no PAM output? A PAM message means sshd is enforcing expiration and the decision is a policy exception for the service account. A silent close with no PAM message points to a missing or bypassed account-phase check in the stack.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.