It is possible to do this by chaining together PAM modules. But before I get into any details:
Incorrectly configuring PAM can and WILL prevent you from logging into your system
Thankfully you can always boot up into single user mode and fix the problem, but just be warned that PAM is not something you want to mess with more than necessary.
Anyway, the idea behind this is that it is possible to utilize stacking PAM modules to make sure that pam-google-authenticator
, pam_unix
(this checks your password) and the certificate module all have to succeed to allow you access. By default, PAM is configured to allow any authentication module to authenticate you, skipping the others.
In /etc/pam.d/common-auth, you will see near the top a line that looks similar to the following:
auth [success=2 default=ignore] pam_unix.so nullok_secure try_first_pass
This tells PAM that should pam_unix.so
succeed, it will skip the next two rules (which are usually another authentication module and then pam_deny.so
) and proceed to the optional modules. However, should the module fail, then it will be ignored, and control will pass on to the next module in the chain. This continues down each authentication module until either control skips to the optional block, or PAM hits pam_deny.so and fails right there.
This can be leveraged to ensure that pam-google-authenticator
, pam_unix.so
and your certificate PAM module all have to succeed to allow you access. I don't know the name of the Google authenticator module or the certificate module you are using, but you should be able to find them in your common-auth file. So by putting something like this at the top:
auth requisite pam_unix.so nullok_secure auth requisite pam_google_authenticator.so auth requisite pam_certificate_auth.so auth [success=<n>] pam_permit.so
Replacing <n>
with the number of modules between the pam_permit.so module here and the next pam_permit.so
module - in other words this should be set to the top-most auth module's [success=n default=ignore] code + 1. This syntax is a bit funky, but essentially skips the auth modules after the above modules have succeeded.
Of course, you may be wondering how to limit this three-step authentication to just your user account. This can be done with a pam_succeed_if.so
module, and should be inserted above the three-step auth block described above:
auth [success=ignore default=4] pam_succeed_if.so user = <username>
Where <username>
is replaced by your username. This line simply says that should pam_succeed_if.so succeed (aka your username matches the username on that line) then PAM should proceed with the next modules, which are the three-step auth modules. Otherwise, PAM should jump to the real modules, which are 4 modules away from this one.
To match multiple things, for example membership of a group along with a certain username, multiple lines must be used, for example:
auth [success=1 default=ignore] pam_succeed_if.so user = <username> auth [success=ignore default=4] pam_succeed_if.so user ingroup <group>
Before doing any of this, I would backup the common-auth file, and also get myself familiar with single user mode and how to restore the old file in case of emergency. This configuration has not been tested by me, but it should work.
For testing this the first time, get a root shell or two open, and just leave them alone. These act as fallbacks in case anything goes wrong, since you can easily replace common-auth with the backup. Then, make these changes. Next, try using su
to log in to your user account - you should need to go through the three-step authentication process.
Full documentation for the pam_succeed_if.so
module can be found at http://linux.die.net/man/8/pam_succeed_if