Two Factor Authentication (2FA)
Setting an Arch server for two-factor authentication is pretty straightforward.
- OpenSSH is already installed and running.
- Your server's IP address is 192.168.1.100 - change this to your IP
- You want to connect on port 454647 - change the port number to something high to avoid the lazier scans, between 30,000-65,535
- Your username is foo - probably change this from the example
pacman -S libpam-google-authenticator
Edit config files
#%PAM-1.0 # Disable remote root auth required pam_securetty.so # Require two-factor authentication auth required pam_google_authenticator.so # But don't allow password attempts #auth include system-remote-login account include system-remote-login password include system-remote-login session include system-remote-login # Log authenticator fails in pam_tally2 # Lock for 5m (300s) after 3 attempt fails auth required pam_tally2.so deny=3 unlock_time=300 onerr=succeed account required pam_tally2.so
# --- Hardened sshd config w/comments --- # See sshd_config(5) for more information. # Change from the default port value (22) Port 454647 # Manually designate the addresses to listen on ListenAddress 192.168.1.100 # Disable SSH version 1 Protocol 2 # Limit HostKeys for protocol version 2 in order of preference HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key # Limit key exchange algorithms to more secure versions KexAlgorithms email@example.com,diffie-hellman-group-exchange-sha256 # Limit our cipher suite to more secure versions Ciphers firstname.lastname@example.org,email@example.com,firstname.lastname@example.org # Limit our message authentication codes to more secure versions MACs email@example.com,firstname.lastname@example.org,email@example.com,hmac-sha2-512,hmac-sha2-256,firstname.lastname@example.org # Logging LogLevel VERBOSE # NO ROOT LOGINS. PERIOD. PermitRootLogin no # Strict adherence to file permissions (~/.ssh/) StrictModes yes # 30s to login (2FA timeout), 3 tries to login, only 1 unauth connection at a time LoginGraceTime 30 MaxAuthTries 3 MaxStartups 1 # Specifies the maximum number of open shell, login or subsystem (e.g. sftp) sessions permitted per network connection. MaxSessions 3 # Specifies whether public key authentication is allowed. PubkeyAuthentication yes # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 # but this is overridden so installations will only check .ssh/authorized_keys AuthorizedKeysFile .ssh/authorized_keys # Disable host-based authentication, like .rhost it's not rock solid. HostbasedAuthentication no # Don't read the user's ~/.rhosts and ~/.shosts files IgnoreRhosts yes # Disable password authentication PasswordAuthentication no PermitEmptyPasswords no # Allow keyboard-interactive so we can ask for our 2FA ChallengeResponseAuthentication yes # Order matters for AuthenticationMethods. Ask for the pubkey first, then go interactive. # The comma is important as well, as it asks for pubkey AND 2FA. A space would be either/or. AuthenticationMethods publickey,keyboard-interactive:pam # Allow pam use so the 2FA library can be loaded UsePAM yes # Do not allow SSH agent key management AllowAgentForwarding no # Disable SSH tunnels PermitTunnel no # Do not allow TCP port forwarding by default AllowTcpForwarding no # Do not forward buggy X11 X11Forwarding no # Disable SSH binding local port forwardings to the loopback address GatewayPorts no # Specifies whether pty(4) allocation is permitted. Default yes PermitTTY yes # Specifies whether sshd should print /etc/motd when a user logs in interactively. PrintMotd no # set it in pam # Print the date and time of last user login PrintLastLog yes # Specifies whether the system should send TCP keepalive messages to the other side. # Default is yes, lets host notice network outage/infinite hangs. TCPKeepAlive yes # Specifies whether ~/.ssh/environment and environment= options # in ~/.ssh/authorized_keys are processed by sshd. Default = no PermitUserEnvironment no # enable compression only after authentication Compression delayed # idle timeout interval ClientAliveInterval 300 ClientAliveCountMax 0 # Force sshd to use DNS UseDNS yes # Warning banner path Banner /etc/issue.net # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise. Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO # Setup only one user able to connect AllowUsers foo # Allow only that user to do tunneling Match User foo AllowTcpForwarding yes PermitTunnel yes
Generate secret key
For each user you want to connect via 2FA, run the google-authenticator selecting a time-based key that disallows code reuse.
┌(foo@server)─(05:32 AM Sat Jun 16)─(~) └> google-authenticator -t -d Warning: pasting the following URL into your browser exposes the OTP secret to Google: https://www.google.com/chart?chs=200x200&chld=M%7C0&cht=qr&chl=otpauth://totp/foo@bar%3Fsecret%3DLJ6V5LANKTMP527CRIDPXJLKHQ%26issuer%3Dbar Failed to use libqrencode to show QR code visually for scanning. Consider typing the OTP secret into your app manually. Your new secret key is: LJ6V5LANKTMP527CRIDPXJLKHQ Enter code from app (-1 to skip): -1 Code confirmation skipped Your verification code is 723310 Your emergency scratch codes are: 60442280 57972493 12160216 20891460 10983155 Do you want me to update your "/home/foo/.google_authenticator" file? (y/n) y By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n) n If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n) y
Copy the generated secret key listed and save a scratch key if you really want to. Just log in locally, lazy. Install FreeOTP on the device of your choice (thanks Red Hat!) and accept the default options while adding a key.
Restart the service
sudo systemctl restart sshd
Connecting your clients
┌(foo@bar)─(05:33 AM Sun Jun 17)─(~) └> ssh -p 454647 email@example.com This is your warning. Remember, I warned you. Verification code: Last login: Sun Jun 17 05:40:48 2018 from bar.localdomain.local ┌(foo@server)─(05:33 AM Sun Jun 17)─(~) └>
Connect via PuTTY as you normally would. You'll be prompted for a verification code once the public key is verified:
- Make sure the account isn't locked on the server
┌(foo@server)─(05:37 AM Sun Jun 17)─(~) └> sudo pam_tally2 -u foo Login Failures Latest failure From foo 3 06/17/18 05:59:36 bar.localdomain.local
If it is, reset the account's tally
┌(foo@server)─(05:37 AM Sun Jun 17)─(~) └> sudo pam_tally2 -u foo --reset Login Failures Latest failure From foo 3 06/17/18 05:59:36 bar.localdomain.local ┌(foo@server)─(05:37 AM Sun Jun 17)─(~) └> sudo pam_tally2 -u foo Login Failures Latest failure From foo 0