Back to Blog
Security2 July 2024Michael Hettwer5 min read

A second login factor on servers via PAM

How we add TOTP over PAM to interactive server logins: clean secret handover, working time sync, and a break-glass path built before the crisis.

Getting onto a server today usually takes a key. That is a factor, but only one: the key sits on the device the administrator connects from, and that device is the favorite entry point. A second factor on the login itself turns "who has the key" into "who has the key and the current one-time code". For interactive administrative logins this combination is the most sensible next step, and it can be built with the means already on board.

The sensible scope comes first

Second-factor logins pay off where humans work: the interactive login of administrators and every access that leads to a real login session. They do not pay off for machine communication: services, backups and automated flows authenticate with keys and tokens inside their own channels, and forcing them to read a one-time code only creates detours. The first decision is therefore the boundary: which logins get the second factor, and which stay deliberately outside.

The technique: TOTP through the PAM chain

The basis is the PAM framework through which Linux systems chain login checks. For time-based one-time codes the standard is TOTP, specified in RFC 6238, with mature PAM modules such as the one from the OATH toolkit. The pattern reads: key authentication is followed by an additional check demanding the time-based code. Whoever lacks the code does not get in, even though the key matches.

One detail deserves attention because practice overlooks it regularly: time-based codes only work when the server's clock is right. A server off by a few minutes makes codes suddenly unusable, and the troubleshooting starts at the wrong place. Time synchronization gets checked before rollout and watched afterwards, not discovered as a surprise later.

Handing out secrets without giving them away

The second factor stands or falls with the distribution of the secret. Every user receives an own seed from which the codes derive. The path to the user decides the value of the measure: seeds sent by mail are an affront, because they land in the same channel as everything else. The practice that holds is unspectacular: the seed is handed over in person or through a second, already secured channel, entered directly into the user's authenticator application, and the server keeps only the verification value.

Part of that agreement is what happens when a user changes devices: a new seed, issued through the same path as the first. The procedure should be ordinary enough that nobody works around it and controlled enough that not just any administrator can trigger it for anyone else.

Build the break-glass path first

Every second-factor measure raises a new question: what happens when the code does not arrive? A lost device, a skewed clock, a reinstalled application. The answer belongs before the rollout, not into the crisis. The proven path is a fallback that is deliberately narrower than the main door: physical access through console or a recovery system, logged and bound to a request. What must not happen is a back door that graciously bypasses the second factor, because exactly such doors show up later in incident reports.

Another boundary belongs in the expectations: a time-based code protects against stolen keys and stolen passwords, but it is fine prey for phishing pages that ask in real time. The second factor is one screw in the hardening, not its conclusion.

Whoever also wants login attempts to stay unprofitable finds the second-line tool in the post Brute force protection with fail2ban.

Getting started in four steps

  • Define the scope: interactive administrative logins yes, machine communication no.
  • Set up the PAM module and build the chain so the second factor is demanded after the key check.
  • Hand out seeds through a clean channel and check the time synchronization of the servers.
  • Document the break-glass path and rehearse it calmly once, before someone sees it for the first time in earnest.

What the rollout reveals about the own operation

Introducing a second factor is a small inventory with a side effect: it shows who logs into the server and how. The list of users needing a seed in the first days is also the list of interactive access points, and the surprises rarely sit where expected. An account unused for months, a login shared by two people, an access actually used only by an old script: all of that surfaces during seed distribution and gets decided properly for the first time.

The second side effect concerns the failure rate: in the first weeks the number of failed logins rises visibly, because codes get mistyped or the device was not at hand. That is no reason for worry but a measurable normalization that settles again after a few weeks. What remains afterwards is the interesting figure: failed logins where the key matched and the code did not. Exactly those reports deserve the attention previously spent on the general login attempts.

A word on the boundary downward belongs in the planning, because not every login is one that deserves the second factor: consoles of a recovery system, services with their own machine context, and transitions used during a restore follow their own rules. The boundary is therefore not kept as an exception list that grows, but as a rule with a reason: whoever has no interactive human in front of the screen is not asked for a code, and whoever does, gets both. This two-sided rule keeps the list small, and a small list is the only state in which such a decision remains surveyable even years later.

Those four steps make the door humans walk through considerably heavier, without irritating the automated paths. If you want to give your server access points a second factor, the security hardening and audits page describes the matching service, and the contact page is the fastest way to reach us.

Sources

  • IETF, RFC 6238 (TOTP: Time-Based One-Time Password Algorithm), https://datatracker.ietf.org/doc/html/rfc6238 (accessed 2026-11-03)
  • OATH toolkit, project page and documentation, https://www.nongnu.org/oath-toolkit/ (accessed 2026-11-03)
  • Linux-PAM project, https://github.com/linux-pam/linux-pam (accessed 2026-11-03)