├── LICENSE ├── README.md └── systemd-user-pam-ssh /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Evan Purkhiser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Systemd User PAM SSH script 2 | 3 | This script has a rather specific use case. If you fit the following demographic 4 | then this script might just be for you! 5 | 6 | * You use systemd 7 | * You login at the linux VT using a getty 8 | * You have a `systemd --user` service called `ssh-agent.service` that starts 9 | your ssh agent. 10 | * You have to type your passphrase after logging in in order to 11 | decrypt your SSH key. 12 | 13 | This script allows you to only type your password once. When logging in, your 14 | SSH key will be decrypted and added to your ssh-agent for you. 15 | 16 | ## Installation 17 | 18 | (1) Set up your ssh-agent systemd user service with the proper 19 | environment using lingering to start it at boot 20 | 21 | # setup module 22 | echo '[Unit] 23 | Description=SSH key agent 24 | 25 | [Service] 26 | Type=simple 27 | Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket 28 | ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK 29 | 30 | [Install] 31 | WantedBy=default.target' \ 32 | > ~/.config/systemd/user/ssh-agent.service 33 | 34 | # setup environment 35 | echo 'SSH_AUTH_SOCK DEFAULT="${XDG_RUNTIME_DIR}/ssh-agent.socket"' \ 36 | > ~/.pam_environment 37 | 38 | # enable now and at boot 39 | systemctl --user start ssh-agent 40 | systemctl --user enable ssh-agent 41 | 42 | # enable lingering 43 | loginctl enable-linger $(whoami) 44 | 45 | (2) Install the script to a well-known location (You can modify `/usr/lib`) 46 | 47 | sudo curl -o /usr/lib/systemd/systemd-user-pam-ssh \ 48 | https://raw.githubusercontent.com/capocasa/systemd-user-pam-ssh/master/systemd-user-pam-ssh 49 | chmod +x /usr/lib/systemd/systemd-user-pam-ssh 50 | 51 | (3) Configure pam 52 | 53 | echo "auth optional pam_exec.so expose_authtok /usr/lib/systemd/systemd-user-pam-ssh" \ 54 | | sudo tee -a /etc/pam.d/login 55 | 56 | (4a) Use your system password as your private key passphrase (not recommended) 57 | 58 | ssh-keygen -p -f ~/.ssh/id_rsa 59 | # type your system password 60 | 61 | 62 | (4b) Encrypt a passphrase with your system password and a heavy derivation function (recommended) 63 | 64 | ## Change your passphrase (optional) 65 | 66 | ssh-keygen -p -f ~/.ssh/id_rsa 67 | # type your passphrase 68 | 69 | ## Save your passphrase encrypted with your system password 70 | 71 | read -s PASSWORD 72 | # type your system password 73 | 74 | read -s PASSPHRASE 75 | # type your passphrase 76 | 77 | echo $PASSPHRASE | openssl enc -pbkdf2 -in - -out ~/.ssh/passphrase -e -aes256 -k "$PASSWORD" 78 | 79 | unset PASSWORD 80 | unset PASSPHRASE 81 | 82 | --- 83 | This is an extended version of the [original script by EvanPurkhiser](https://github.com/EvanPurkhiser/systemd-user-pam-ssh) 84 | -------------------------------------------------------------------------------- /systemd-user-pam-ssh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # For use with pam_exec.so 3 | # 4 | # auth optional pam_exec.so expose_authtok /usr/lib/systemd/systemd-user-pam-ssh 5 | # 6 | # Takes a password from STDIN, starts the ssh-agent as a systemd user service, 7 | # and decrypts the ssh key using the provided password, adding it to the agent. 8 | 9 | # Handle inital checks as root 10 | if [ $(id -u) = 0 ] 11 | then 12 | # Don't execute if the systemd --user instance isn't running 13 | systemctl -q is-active user@$(id -u ${PAM_USER}) || exit 0 14 | 15 | # Re-execute this script as the user to add their key (while piping STDIN) 16 | cat | exec su ${PAM_USER} -c "$0 initialize" 17 | 18 | # Handle adding the key as the user 19 | else 20 | 21 | if [ "$1" = "initialize" ]; then 22 | # We need to specify the XDG_RUNTIME_DIR because pam_systemd won't have run 23 | export XDG_RUNTIME_DIR=/run/user/$(id -u) 24 | 25 | # Get the SSH_AUTH_SOCK variable from the user session 26 | export $(systemctl --user show-environment | grep ^SSH_AUTH_SOCK=) 27 | 28 | # Use self as askpass to work around ssh-add not reading stdin 29 | # on some systems 30 | export SSH_ASKPASS="$0" 31 | 32 | #Fake display to coax to actually use SSH_ASKPASS 33 | export DISPLAY=nodisplay 34 | 35 | ssh-add 36 | exit 0 37 | 38 | # Double as SSH_ASKPASS 39 | else 40 | # Decrypt passhrase if file exists 41 | FILE="$HOME/.ssh/passphrase" 42 | if [ -e "$FILE" ]; then 43 | # to use a different passphrase, prepare file with 44 | # read -s PASSWORD 45 | # openssl enc -pbkdf2 -in - -out ~/.ssh/passphrase -e -aes256 -k 46 | read PASSWORD 47 | openssl enc -pbkdf2 -in "$FILE" -out - -d -aes256 -k "$PASSWORD" 48 | if [ $? -ne 0 ]; then 49 | exit 1 50 | fi 51 | 52 | # Use password as passphrase 53 | else 54 | cat 55 | fi 56 | exit 0 57 | fi 58 | fi 59 | --------------------------------------------------------------------------------