Generate keys
ssh-keygen -C "$(whoami)@$(hostname)-$(date -I)" -t ed25519
ssh-keygen -t rsa -b 4096
-C
Comment to identify the key. Add user name and date for easier management.-b
The number of bits.-t
Type of key.
Note: Types of keys
Types of keys: - `ed25519`: Newer and *should* be more secure. **Recomended** - `rsa`: Works with old software. *Should* be secure. - `ecdsa`: *Could* be compromised as uses NIST P-256 curve. [Source](https://safecurves.cr.yp.to/index.html). - `dsa`: **insecure**At this point in time no one can tell which is more "secure" because they are pretty much "unbreakable".
Add a password to the key whenever possible.
This command will generate two files a private ~/.ssh/id_ed25519
and a public ~/.ssh/id_ed25519.pub
; the public can be shared the private must be kept a secret.
Copy the keys to the server
Using an automated method (you need to have access to the server through SSH):
ssh-copy-id -i /path/to/key user@server
To manually copy the key to the server you have to put the content of the ~/.ssh/id_ed25519.pub
file into the server's ~/.ssh/authorized-keys
.
File permissions
chmod 700 ~/.ssh
chmod 400 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/known_hosts
Note: authorized_keys
may need to be read from other users or programs.
Configure the server
sshd
service
Running ssh as a socket (start an ssh
instance when there is a connection) is generally the recommended way unless you have many users as this method spans a ssh instance per connection systemctl --full | grep ssh
. It also allows you to kill individual connections. Source
Disable and stop ssh
sudo systemctl disable sshd
sudo systemctl stop sshd
Edit the IP address in which the ssh socket listens with /etc/systemd/system/sshd.socket.d/override.conf
or sudo EDITOR=vim systemctl edit sshd.socket
.
[Socket]
ListenStream=192.168.1.1:22
FreeBind=true
Enable ssh socket.
sudo systemctl start sshd.socket
sudo systemctl enable sshd.socket
Changing the port of SSH
By default SSH runs in port 22
, a privileged port; this means only root can run a program at that port. If you change the port to port 4567
any user can run anything in that port implying that someone with access can crash SSH and run a malicious service on that port.
If you want to still change the port add the following to iptables
. Source
sudo iptables -t nat -A PREROUTING -p tcp --dport 4567 -j CONNMARK --set-mark 4567
sudo iptables -t nat -A PREROUTING -p tcp --dport 4567 -j REDIRECT --to-port 22
sudo iptables -A INPUT -p tcp --dport 22 -m connmark ! --mark 4567 -j REJECT
sudo iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
/etc/ssh/sshd_config
sshd_config
Some options are commented out, that may mean they are the defaults.## Service listening options. Useless when using a socket.
#Port 22
#AddressFamily any ## inet (IPv4); inet6 (IPv6) or any for both
#ListenAddress 0.0.0.0 ## By default SSH listens on all interfaces
#ListenAddress :: ## Same but for IPv6
## Default Private SSH keys for the server
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key ## Insecure
#HostKey /etc/ssh/ssh_host_ecdsa_key ## Insecure
# Ciphers and keying
## maximum amount of data that may be transmitted before the session key is
## renegotiated
#RekeyLimit default none
# Logging
## Facility code used when logging messages
#SyslogFacility AUTH ## Arch Linux
SyslogFacility AUTHPRIV ## CentOS
## LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a
## clear audit track of which key was using to log in.
## Logs at ????
LogLevel VERBOSE
# Authentication:
## The server disconnects after this time if the user has not successfully
## logged in.
#LoginGraceTime 2m
## Allow login as root. without-password (public keys); forced-commands-only
## (only certain commands); yes; no (preferred)
PermitRootLogin no
## Check file modes and ownership of the user's files and home directory
## before accepting login.
#StrictModes yes
## Maximum number of authentication attempts permitted per connection.
MaxAuthTries 1
## Maximum number of open sessions (*shells*) per IP.
#MaxSessions 10
## Allow public keys to authenticate.
#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
## Specifies a file that lists principal names that are accepted for certificate
## authentication. Use with CA issued certificates.
#AuthorizedPrincipalsFile none
## Specifies a program to be used to look up the user's public keys.
#AuthorizedKeysCommand none
## Specifies the user under whose account the AuthorizedKeysCommand is run.
#AuthorizedKeysCommandUser nobody
## Specifies whether rhosts or /etc/hosts.equiv authentication together with
## successful public key client host authentication is allowed. This is old
## and is replaced with public keys.
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
## Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
## Disallow passwords for authentication.
PasswordAuthentication no
## Permit log in in accounts with no password.
#PermitEmptyPasswords no
## Disallow keyboard interactive passwords. Set to yes for TOTP.
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#KerberosUseKuserok yes
# GSSAPI options
## Used for kerberos authentication.
## Can be disabled if not used.
GSSAPIAuthentication no
#GSSAPICleanupCredentials no
GSSAPIStrictAcceptorCheck no
#GSSAPIKeyExchange no
#GSSAPIEnablek5users no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux
# and may cause several problems.
## Needed for TOTP
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
## Used to monitor whether the client is still available.
#TCPKeepAlive yes
## Client time out. 0 to disable.
ClientAliveInterval 60
## Number of keep alive packages to send.
ClientAliveCountMax 0
## The SSH server will look up the remote hostname and check with DNS if the resolved IP for the remote hostname matches.
## Disabling can speed up connections.
UseDNS no
#ShowPatchLevel no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
## Allow only these users.
AllowUsers yu user admin john
## Allow only the users in these groups.
AllowGroups sshusers
## All users except these.
DenyUsers root
## Only use SSH protocol 2.
Protocol 2
## Banner (motd) to display when login.
#Banner none
Banner /etc/issue.net
## Only accept specific KEX (Key Exchange) algorithms.
# ssh -Q kex
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,curve25519-sha256,diffie-hellman-group-exchange-sha256,sntrup761x25519-sha512@openssh.com,curve25519-sha256,diffie-hellman-group-exchange-sha256,sntrup761x25519-sha512@openssh.com
## Specifies the ciphers allowed.
# ssh -Q cipher
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
## Specifies the available MAC (message authentication code) algorithms.
# ssh -Q mac
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
## Specifies the host key signature algorithms that the server offers.
# ssh -Q HostKeyAlgorithms
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256
## Override default of no subsystems [leave].
#Subsystem sftp /usr/lib/ssh/sftp-server ## Arch Linux
#Subsystem sftp /usr/lib/openssh/sftp-server ## Debian
#Subsystem sftp /usr/libexec/openssh/sftp-server ## CentOS
## Log sftp level file access (read/write/etc.) that would not be easily
## logged otherwise.
## Logs at ????
Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO
## Multiple authentication methods (TOTP) (publickey and TOTP code).
## Publickey and TOTP code. Depending on `/etc/pam.d/sshd` it may ask for
## the user password too.
AuthenticationMethods publickey,keyboard-interactive
## Publickey and user password. Not recommended.
#AuthenticationMethods publickey,password
## Don't know if it works. Not recommended.
#AuthenticationMethods "publickey,password" "publickey,keyboard-interactive"
#PasswordAuthentication yes
## Accept locale-related environment variables.
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
## Other [leave].
#RhostsRSAAuthentication no
#RSAAuthentication yes
#KeyRegenerationInterval 3600
#ServerKeyBits 1024
# Example of overriding settings on a per-user basis
## More settings????
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
## rsync user
Match User rsync
ChrootDirectory /home/%u ## Must be owned by root??
PermitTTY no
ForceCommand rsync
AllowTcpForwarding no
X11Forwarding no
Restart ssh
if you are using a service instead of a socket.
systemctl restart sshd
Regenerate host SSH keys
Remove old keys.
rm -v /etc/ssh/ssh_host_*
Generate rsa and ed25519 host keys.
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
Generate all missing keys with ssh-keygen -A
Obtaining the public key fingerprint for the server
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
~/.ssh/authorized-keys
Some examples from man 8 sshd
where you can find all options.
# Plain key, no restrictions
ssh-rsa ...
# Forced command, disable PTY and all forwarding
restrict,command="dump /home" ssh-rsa ...
# Restriction of ssh -L forwarding destinations
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa ...
# Restriction of ssh -R forwarding listeners
permitlisten="localhost:8080",permitlisten="[::1]:22000" ssh-rsa ...
# Configuration for tunnel forwarding
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa ...
Configure the client
For global options edit /etc/ssh/ssh_config
Host *
IdentitiesOnly yes
MACs umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
Ciphers chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
For user specific options edit ~/.ssh/config
AddKeysToAgent yes
## All hosts
Host *
IdentitiesOnly yes
Host server
HostName 192.168.1.45
User yu
Port 4567
IdentityFile /home/yu/keys/server
All options explained in ssh_config(5).
Map a remote port
Socket forwarding
ssh -L /var/mysql/mysql.sock:/var/mysql/mysql.sock username@hostname
Port forwarding
Access a remote service from your local system.
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
ssh -L local-port:remote-hostname:remote-port username@hostname
Example to forward port 110 in the server to port 1100 in the client.
ssh -L 1100:127.0.0.1:110 mail.example.local
ssh -L 1100:mail.example.local:110 mail.example.local
Remote forwarding
Access a local service from a remote system.
-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-R [bind_address:]port
ssh -R local-port:hostname:client-port username@hostname
Example: the client is listening for connections on localhost:8080
and we want to connect from the server server.example.local
at localhost:9001
:
ssh -R 9001:localhost:8080 server.example.local
You can map the forwarded port to the server address to be accessible by your local network with:
ssh -R server.example.local:9001:localhost:8080 server.example.local
It has to be allowed in /etc/ssh/sshd_config
with:
GatewayPorts clientspecified
Dynamic forwarding (SOCKS proxy)
ssh -D [bind_address:]port
ssh -D 8000 server.example.com
Background forwarding
-fNn
will create (map) a tunnel in the background.
ssh -fNn -L 1100:127.0.0.1:110 mail.example.local
ssh -fNn -L localhost:1100:localhost:110 mail.example.local
Finish the connection with:
kill -QUIT "$( pgrep -xf "ssh -fNn -L 1100:127.0.0.1:110 mail.example.local" )"
SSH agent
Start ssh-agent
Manually.
eval `ssh-agent -s`
Or
eval "$(ssh-agent -s)"
In .bashrc
or .zshrc
.
[[ $SSH_AGENT_PID ]] || eval `ssh-agent -s` > /dev/null && ssh-add /path/to/key
In .xinitrc
.
exec ssh-agent sway
#exec ssh-agent i3
#exec ssh-agent openbox ## Openbox
#exec ssh-agent openbox-session ## Openbox alternative
#exec ssh-agent startkde ## KDE
Add keys
Add one key
ssh-add /path/to/key
ssh-add /path/to/key -t 3600 ## For 1 hour
man 1 ssh-add
Remove keys
Remove one key.
ssh-add -d /path/to/key
Remove all keys.
ssh-add -D
X11Forwarding
WIP
ssh -Y server.example.local firefox
Port knocking
WIP
$IPT -N stage1
$IPT -A stage1 -m recent --remove --name knock
$IPT -A stage1 -p tcp --dport 3456 -m recent --set --name knock2
$IPT -N stage2
$IPT -A stage2 -m recent --remove --name knock2
$IPT -A stage2 -p tcp --dport 2345 -m recent --set --name heaven
$IPT -N door
$IPT -A door -m recent --rcheck --seconds 5 --name knock2 -j stage2
$IPT -A door -m recent --rcheck --seconds 5 --name knock -j stage1
$IPT -A door -p tcp --dport 1234 -m recent --set --name knock
$IPT -A INPUT -m --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name heaven -j ACCEPT
$IPT -A INPUT -p tcp --syn -j door
Two factor authentication (TOTP)
What we need:
- pam-oath
. PAM module to authenticate with TOTP codes.
- A seed used to generate TOTP codes by the client and server.
- A users file to define TOTP type, username, pin (optional) and seed.
Install pam-oath
More information in pam-oath
.
Help: Installation
[Archlinux](https://www.nongnu.org/oath-toolkit/pam_oath.html)pacman -S oath-toolkit
Debian
apt install libpam-oath
CentOS
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -Uvh epel-release-latest-7.noarch.rpm
yum install pam_oath
Create a users file
Generate a seed. This seed is in hex format.
head -15 /dev/urandom | sha512sum | cut -b 1-30
---
6b400f7b322b33a98b9ace4dbeff3e
Create the users file /etc/users.oath
.
HOTP/T30 user - 6b400f7b322b33a98b9ace4dbeff3e
Users file documentation
- `HOTP/T30` is the token type (see below). - `user` is the user for which the token is for. - `-` is the PIN, which goes before the TOTP code. If the PIN is `4567` and the totp code is `72365962` the code ssh will ask for is `456772365962` - `6b400f7b322b33a98b9ace4dbeff3e` is the seed in hex.Sources
-Overview
The users file contains the secret information about users, PINs, and token keys on the server. It's location is configured via the `OTPAuthUsersFile` directive. This file is updated (rewritten) whenever the server needs to save new information. Therefore, you should only edit it when the server is stopped (or no authentication is occurring). You will need to create this file manually and be sure to set the permissions correctly (see below). Each line defines one user+token combination. Currently a user may only have a single associated token. Users may have an arbitrary length PIN, or a dash ("-") for no PIN, or a plus ("+") if the PIN is verified externally using the configured `OTPAuthPINAuthProvider` list (see [Configuration](Configuration) for details on external PIN verification). It is strongly recommended to set all PIN's to a plus sign and configure a `OTPAuthPINAuthProvider` for PIN verification. When a user has a PIN, it must precede the one-time password in the HTTP password field. For example, if a user has PIN "1234" and the token generates the one-time password of "567890", then the user must enter "1234567890" as their password for HTTP authentication. Tokens must be configured as event tokens or time tokens and of course the token's key must be entered. In addition, you may optionally specify the initial counter value (for event tokens) or relative time period offset adjustment (for time tokens); both values default to zero if not specified. For time based tokens, the length of a single time interval is specified as part of the token type (see below). See [OneTimePasswords](OneTimePasswords) and [Tokens](Tokens) for more information about how one-time passowords and tokens work.Permissions
The Apache web server must have permission to create files in the same directory as this file, and to delete (overwrite) this file with an updated copy. This is because the way **mod\_authn\_otp** updates the file is by writing out a new version under a temporary name and then renaming the temporary file to the real one. For example, on [openSuSE Linux](http://www.opensuse.org/) this means the file and parent directory should be owned by user `wwwrun` and group `www`. If it's not already obvious, because it contains sensitive security information **never put this file where it could be publicly visible**. For example, it should probably be in a directory that is only readable by the Apache process.Format
An example users file is included in the distribution and is reproduced here:#
# Example users file for mod_authn_otp
#
# Blank lines and lines starting with '#' are ignored. Fields are whitespace-separated.
#
# Fields:
#
# 1. Token Type See below
# 2. Username User's username
# 3. PIN User's PIN, or "-" if user has no PIN, or "+" to verify PIN via "OTPAuthPINAuthProvider"
# 4. Token Key Secret key for the token algorithm (see RFC 4226)
# 5. Counter/Offset Next expected counter value (event tokens) or counter offset (time tokens)
# 6. Failure counter Number of consecutive wrong OTP's provided by this users (for "OTPAuthMaxOTPFailure")
# 7. Last OTP The previous successfully used one-time password
# 8. Time of Last OTP Local timestamp when the last OTP was generated (in the form 2009-06-12T17:52:32L)
# 9. Last IP address IP address used during the most recent successful attempt
#
# Fields 5 and beyond are optional. Fields 6 and beyond should be omitted for new users.
#
# Token Type Field:
#
# This field contains a string in the format: ALGORITHM [ / COUNTERINFO [ / DIGITS ] ]
#
# The ALGORITHM is either "HOTP" (RFC 4226) or "MOTP" (http://motp.sourceforge.net/).
#
# The COUNTERINFO is either "E" for an event-based token, or "TNN" for a time based token
# where "NN" is the number of seconds in one time interval. For HOTP, the default is "E";
# for MOTP, the default is "T10".
#
# The DIGITS is the number of digits in the one-time password; the default is six.
#
# Examples:
#
# HOTP - HOTP event-based token with six digit OTP
# HOTP/E - HOTP event-based token with six digit OTP
# HOTP/E/8 - HOTP event-based token with eight digit OTP
# HOTP/T30 - HOTP time-based token with 30 second interval and six digit OTP
# HOTP/T60 - HOTP time-based token with 60 second interval and six digit OTP
# HOTP/T60/5 - HOTP time-based token with 60 second interval and five digit OTP
# MOTP - Mobile-OTP time-based token 10 second interval and six digit OTP
# MOTP/E - Mobile-OTP event-based token with six digit OTP
#
# For more info see: https://github.com/archiecobbs/mod-authn-otp/wiki/UsersFile
#
# Some users who have logged in at least once.
HOTP barney 1234 8a2d55707a9084982649dadc04b426a06df19ab2 21 0 820658 2009-06-12T17:52:32L 192.168.1.1
HOTP fred 5678 acbd18db4cc2f85cedef654fccc4a4d8bd537891 78 0 617363 2009-06-04T21:17:03L 192.168.1.2
HOTP/T joe 999999 ef654fccdef654fccc4a4d8acbd18db4cc2f85ce -2 2 883913 2009-06-04T21:17:03L 10.1.1.153
# Wilma and Betty are new users. Note betty does not have a PIN so "-" is used instead as a placeholder
HOTP wilma 5678 a4d8acbddef654fccc418db4cc2f85cea6339f00
HOTP betty - 54fccc418a4d8acbddef6db4cc2f85ce99321d64
# Here is a user who's PIN is verified externally using whatever "OTPAuthPINAuthProvider" list you have configured.
# E.g. to use an htpasswd type file, specify "OTPAuthPINAuthProvider file" and then "AuthUserFile /some/file".
HOTP bambam + d8acbddef6db4cc254fccc418a4f85ce99321d64
To add users, add new lines to the file containing only the first four or five fields (see for example `wilma`, `betty`, and `bambam`).
Some of the fields have been added to this file in newer **mod\_authn\_otp** versions. Newer versions of **mod\_authn\_otp**
are backward compatible with older versions' file formats and will automatically upgrade them the first time they are used.
Locking
**mod\_authn\_otp** creates a lock file in the same directory as the users file in order to synchronize server threads so they don't try to update the users file at the same time. The file is empty; it just needs to be there so it can be locked.Mobile-OTP
**mod\_authn\_otp** supports using the [Mobile-OTP](http://motp.sourceforge.net/) algorithm instead of HOTP/OATH. In this case the PIN (if any) should be entered into the token when generating the one-time password and _not_ as a prefix to the HTTP password. Use token type "MOTP" instead of "HOTP". Note: MOTP authentication is not compatible with the **OTPAuthPINAuthProvider** configuration directive. With MOTP tokens, the PIN must be explicitly provided in the users file.Change permissions of the file.
chmod 0600 /etc/users.oath
Edit PAM
Edit /etc/pam.d/sshd
to require TOTP for PAM authentication. Add after password-auth
auth required pam_oath.so usersfile=/etc/users.oath window=3 digits=6
Note: TOTP order
Example for Debian 11. `window` is the search depth. If the `window` is 3, it allows TOTP codes generated up to +-1min from now. It allows the current code, previous and next. Needed when the time is not synced. If the server has 14:30:45 it allows TOTP codes generated from 14:30:00 to 14:31:29, that would make three different TOTP codes are valid at 14:30:45 for a `window` of 3. `digits` is the number of digits the code has. Depending on the order you want: Password then TOTP: `required` after `@include common-auth`@include common-auth
auth required pam_oath.so usersfile=/etc/users.oath window=3 digits=8
TOTP then Password: `required` before `@include common-auth`
auth required pam_oath.so usersfile=/etc/users.oath window=3 digits=8
@include common-auth
TOTP only: `sufficient` before `@include common-auth`
auth sufficient pam_oath.so usersfile=/etc/users.oath window=3 digits=8
@include common-auth
SSH public key is required for all of them.
In theory `pam_oath.sh` should be added before or after `password-auth` but Debian does not have that line in the file so add if before or after `@include common-auth`.
Edit sshd_config
Edit /etc/ssh/sshd_config
to require the TOTP code.
Authenticationmethods publickey,keyboard-interactive
PasswordAuthentication no
ChallengeResponseAuthentication yes
(Optional) do not require TOTP code for LAN adding the following lines to /etc/ssh/sshd_config
.
Match Address 127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
Authenticationmethods publickey
Restart sshd
service unless you use a socket.
systemctl restart sshd
And you are good to connect using a TOTP code.
Generate TOTP code
With the seed 6b400f7b322b33a98b9ace4dbeff3e
(hex) you want to generate a TOTP code.
Using oathtool
:
oathtool --totp 6b400f7b322b33a98b9ace4dbeff3e --digits 8
You can also use keepasXC
, pass
or authenticator
(gnome).
The code only works once, if you want to open two or more instances you have to wait for the code to regenerate.
Generate QR code
You need a base32 code for qrencode
. You can get it with oathtool
.
6b400f7b322b33a98b9ace4dbeff3e
seed in hexNNAA66ZSFMZ2TC42ZZG357Z6
seed in base32
With the seed you generate the secret Base32 secret
. This code is the password and must be treated as such.
oathtool -v --digits 8 6b400f7b322b33a98b9ace4dbeff3e
---
Hex secret: 6b400f7b322b33a98b9ace4dbeff3e
Base32 secret: NNAA66ZSFMZ2TC42ZZG357Z6
Digits: 8
Window size: 0
Start counter: 0x0 (0)
23340342
Or oathtool --verbose --totp 6b400f7b322b33a98b9ace4dbeff3e --digits=8 | grep Base32 | cut -d ' ' -f 3
And create an image.
qrencode -o user.png 'otpauth://totp/user@machine?secret=NNAA66ZSFMZ2TC42ZZG357Z6&digits=8'
The QR code will be at user.png
and the comment of the key will be user@machine
.
You can also generate the QR code and the seed with gen-oath-safe
. Source
gen-oath-safe $USER totp
Configure SELinux
SELinux by default does not allow this method because ssh
can not write in /etc/
. The official documentation does not cover this issue.
Install audit2allow
in CentOS. Search for a package with yum provides \*/audit2allow
sudo yum install policycoreutils-python
Disable SELinux (permissive) to log the requests that ssh
makes.
sudo setenforce 0
May need to try to log in to generate logs.
You can see the error and the reason with:
sudo cat /var/log/audit/audit.log | grep ssh | audit2why
---------------------------------------------------------
type=AVC msg=audit(1565369402.846:97): avc: denied { nnp_transition } for pid=1584 comm="sh" scontext=system_u:system_r:init_t:s0 tcontext=system_u:system_r:iptables_t:s0 tclass=process2 permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
Create a policy for SELinux. This will list the rules that may fix the issue (they do) in order to revise them before creating a policy. I am sure there is a better, more secure way but this is the first time I used SELinux and this worked.
sudo grep sshd_t /var/log/audit/audit.log | audit2allow --module=sshdlocal
---------------------------------------------------------------------------
module sshdlocal 1.0;
require {
type etc_t;
type sshd_t;
class file { create rename unlink write };
}
#============= sshd_t ==============
#!!!! WARNING: 'etc_t' is a base type.
allow sshd_t etc_t:file { create rename unlink write };
Create a custom policy module for SELinux.
sudo grep sshd_t /var/log/audit/audit.log | audit2allow --module-package=sshdlocal
Enable SELinux (enforcing) again.
sudo setenforce 1
Install the module.
sudo semodule --install=sshdlocal.pp
Make sure the policy is loaded.
sudo semodule --list-modules | grep sshdlocal
Enforcing SELinux may disable the policy (Don't know how true this is).
Certificates
- The CA keys are just normal keys.
- You can use different keys to sing user and host certificates. Multiple CAs.
- A principal is a tag which can be used to grant permissions.
- If the key has no principals it is not permitted to authenticate.
- Check the ID and principals with
ssh-keygen -Lf id_ed25519-cert.pub
- If you implement this properly, a serial number
-z
must be used for key revoking. - Some recommend to not use any real username as a principal.
- If a key has a principal which matches a username, that key will be allowed to log in as that username.
sudo
is only needed to read the certificate. If your user can read the certificatesudo
is not needed.
Create the CA key pair
sudo ssh-keygen -t ed25519 -f /etc/ssh/ca
Authenticate users
You need a key pair to be signed. For this example it is /home/user/.ssh/id_ed25519.pub
Sign a key pair
sudo ssh-keygen -s /etc/ssh/ca -I user -n management,read -O permit-port-forwarding -V "-1m:forever" /home/user/.ssh/id_ed25519.pub
-s
path to CA key-I
ID of the key logged by the server when the certificate is used-n
principal of the key-O
key options. Refer to theman ssh-keygen
page.-V
validity of the key.
This process generates /home/user/.ssh/id_ed25519-cert.pub
Configure the server
Copy the CA's public key /etc/ssh/ca.pub
to the server.
/etc/ssh/sshd_config
---
TrustedUserCAKeys /etc/ssh/ca.pub
PasswordAuthentication no
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
Add principals to access a user.
The principal management
will be allowed to log in as logs
and psql
.
The principal read
will only be allowed to log in as logs
.
echo -e "management\nread\n" | sudo tee -a /etc/ssh/auth_principals/logs
echo -e "management" | sudo tee -a /etc/ssh/auth_principals/psql
Restart the service
sudo service sshd restart
Connect
ssh 10.0.0.1 -l user -i /home/user/.ssh/id_25519
Authenticate hosts
You need a host key pair to sign. They are /etc/ssh/ssh_host*
.
Sign the key
Copy /etc/ssh/ssh_host_ed25519_key.pub
from the server to sign it locally, sign it and upload it back to the server.
sudo ssh-keygen -s /etc/ssh/ca -I hostname -h -n host.domain.local,192.168.0.34 -V "-1m:forever" ssh_host_ed25519_key.pub
-s
path to CA key-I
ID of the key-h
make a host key instead of a user key.-n
principal(s) of the key. Allowed hostnames.-V
validity of the key.
Configure the server
Edit /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
Configure the client
Add the CA public key to ~/.ssh/known_hosts
to allow pricipals domain.local
and 192.168.1.0/24
:
@cert-authority *.domain.local,192.168.1.* ssh-ed25519 AAAA...
Or any pricipal:
@cert-authority * ssh-ed25519 AAAA...
*.domain.local
and 192.168.1.*
are the principal names that the SSH host key has been signed with (cert). *
is a wildcard.
This principals are the name (ssh host.domain.local
) you use to connect. They can be:
- An IP address (192.168.1.23
)
- An entry in /etc/hosts
(192.168.1.23 host.domain.local
)
- A DNS resolved name
Connect
Remove previously cache identities.
ssh-keygen -R 10.0.0.1
Log in
ssh 10.0.0.1 -l user -i /home/user/.ssh/id_25519
You will not see The authenticity of host '10.0.0.1 (10.0.0.1)' can't be established.
Single Packet Authorization SPA
TBD
- https://www.linuxjournal.com/article/9621
- https://man.archlinux.org/man/community/fwknop/fwknop.8.en Firewall Knock Operator
- http://www.cipherdyne.org/fwknop/docs/
Fail2ban
WIP
Install
sudo paman -S fail2ban
Default config at /etc/fail2ban/jail.conf
. This config may be overwritten, it is reccomended to create /etc/fail2ban/jail.local
.
Configure fail2ban
at /etc/fail2ban/jail.local
.
[DEFAULT]
bantime = 86400 ## 1 day
findtime = 120
maxretry = 2
logtarget = /var/log/fail2ban/fail2ban.log
Create the logging directory as root.
sudo mkdir /var/log/fail2ban
Configure a custom jail for ssh
at /etc/fail2ban/jail.d/sshd.local
.
[sshd]
enabled = true
filter = sshd
banaction = iptables
backend = systemd
maxretry = 5
#findtime = 86400 ## 1 day
bantime = 1209600 ## 2 weeks
ignoreip = 127.0.0.1/8 192.168.1.1/24 10.0.0.5
Hardening the fail2ban
service at /etc/systemd/system/fail2ban.service.d/override.conf
.
Make the directory first sudo mkdir /etc/systemd/system/fail2ban.service.d/
.
[Service]
PrivateDevices=yes
PrivateTmp=yes
ProtectHome=read-only
ProtectSystem=strict
NoNewPrivileges=yes
ReadWritePaths=-/var/run/fail2ban
ReadWritePaths=-/var/lib/fail2ban
ReadWritePaths=-/var/log/fail2ban
ReadWritePaths=-/var/spool/postfix/maildrop
CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW
Start and enable the service.
sudo systemctl daemon-reload
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
Check the status.
sudo fail2ban-client status sshd
---
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 8
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 192.168.100.1
Unban an IP
sudo fail2ban-client set sshd unbanip 192.168.100.1
Escape characters
Escape characters only work after a new line.
~.
Disconnect.~^Z
Background ssh.~#
List forwarded connections.~&
Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate.~?
Display a list of escape characters.~B
Send a BREAK to the remote system (only useful if the peer supports it).~C
Open command line (ssh console). Currently this allows the addition of port forwardings using the-L
,-R
and-D
options.~R
Request rekeying of the connection (only useful if the peer supports it).~V
Decrease the verbosity (LogLevel) when errors are being written to stderr.~v
Increase the verbosity (LogLevel) when errors are being written to stderr.
SSH console options.
ssh> -L 9001:127.0.0.1:80
ssh> -KL 9001
ssh> -R 10.0.0.1:22:127.0.0.1:9001
ssh> -KR 10.0.0.1:22
ssh> -h
In an anidated session, like a bastion host (A (client) -> B (bastion) -> C (server)), pressing ~
once will control the bastion session (A -> B) while pressing ~
twice will control the remote host (B -> C).
Rate limit
WIP
$IPT -A INPUT -i ${inet_if} -p tcp --dport ${ssh_port} -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT
TCP wrappers
This is an old way to restrict access without a firewall.
Chroot Jails
WIP
- https://www.tecmint.com/restrict-ssh-user-to-directory-using-chrooted-jail/
- https://unix.stackexchange.com/questions/542440/how-does-chrootdirectory-and-a-users-home-directory-work-together
Audit SSH
ssh-audit
Download
git clone https://github.com/jtesta/ssh-audit
Execute
python ssh-audit.py server.local
Results
[...]
# algorithm recommendations (for OpenSSH 8.0)
(rec) -diffie-hellman-group-exchange-sha256 -- kex algorithm to remove
(rec) +diffie-hellman-group14-sha256 -- kex algorithm to append
(rec) +diffie-hellman-group16-sha512 -- kex algorithm to append
(rec) +diffie-hellman-group18-sha512 -- kex algorithm to append
(rec) -hmac-sha2-256 -- mac algorithm to remove
(rec) -hmac-sha2-512 -- mac algorithm to remove
(rec) -umac-128@openssh.com -- mac algorithm to remove
Transform a PuTTY key to an OpenSSH one
puttygen private.ppk -O private-openssh -o private.ssh
Logs
WIP
Links
- My guide for SSH on Windows
- https://wiki.archlinux.org/index.php/OpenSSH
- https://www.openssh.com/
- https://www.cyberciti.biz/tips/linux-unix-bsd-openssh-server-best-practices.html
- https://safecurves.cr.yp.to/index.html
- https://framkant.org/2017/07/scalable-access-control-using-openssh-certificates/
sudo sshd -T ## test the validity of the keys sudo sshd -t