├── access.json ├── pam_oauth2.so ├── LICENSE ├── github_ssh_init.sh └── README.md /access.json: -------------------------------------------------------------------------------- 1 | {"root":"root","ec2-user":"ec2-user","readonly":"readonly"} 2 | -------------------------------------------------------------------------------- /pam_oauth2.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaylevi2/githubssh/HEAD/pam_oauth2.so -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Shay Levi 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /github_ssh_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$#" -ne 2 ]; then 4 | echo "Usage: $0 " >&2 5 | exit 1 6 | fi 7 | 8 | if [ ! -f /etc/ssh_banner.txt ]; then 9 | ## Build 10 | # if ! type 'apt' > /dev/null; then 11 | # yum install -y gcc make git libcurl-devel pam-devel 12 | # else 13 | # apt install -y gcc make git libcurl4-openssl-dev libpam-dev 14 | # fi 15 | # git clone https://github.com/CyberDem0n/pam-oauth2 16 | # cd pam-oauth2 && git submodule init && git submodule update && make && make install && cd .. 17 | 18 | ## Use Pre-Built 19 | if [ -d '/lib64/security' ]; then 20 | curl -L -s -o /lib64/security/pam_oauth2.so https://github.com/shaylevi2/githubssh/raw/main/pam_oauth2.so 21 | chmod 644 /lib64/security/pam_oauth2.so 22 | elif [ -d '/lib/security' ]; then 23 | curl -L -s -o /lib/security/pam_oauth2.so https://github.com/shaylevi2/githubssh/raw/main/pam_oauth2.so 24 | chmod 644 /lib/security/pam_oauth2.so 25 | elif [ -d '/lib/x86_64-linux-gnu/security' ]; then 26 | curl -L -s -o /lib/x86_64-linux-gnu/security/pam_oauth2.so https://github.com/shaylevi2/githubssh/raw/main/pam_oauth2.so 27 | chmod 644 /lib/x86_64-linux-gnu/security/pam_oauth2.so 28 | else 29 | echo "Failed to find /lib/security" >&2 30 | exit 1 31 | fi 32 | 33 | sed -i "1i## Github SSH Access Control" /etc/pam.d/sshd 34 | sed -i "2iauth sufficient pam_oauth2.so https://raw.githubusercontent.com/${2#*.com/}/refs/heads/main/access.json?token= $1" /etc/pam.d/sshd 35 | sed -i "3iaccount sufficient pam_oauth2.so https://raw.githubusercontent.com/${2#*.com/}/refs/heads/main/access.json?token= $1" /etc/pam.d/sshd 36 | 37 | sed -i "1i## Github SSH Access Control" /etc/ssh/sshd_config 38 | sed -i "2iKbdInteractiveAuthentication yes" /etc/ssh/sshd_config 39 | sed -i "3iChallengeResponseAuthentication yes" /etc/ssh/sshd_config 40 | sed -i "4iUsePAM yes" /etc/ssh/sshd_config 41 | sed -i "5iBanner /etc/ssh_banner.txt" /etc/ssh/sshd_config 42 | 43 | if [ $1 = "root" ]; then 44 | sed -i "2iPermitRootLogin yes" /etc/ssh/sshd_config 45 | fi 46 | 47 | echo '**********************************' >> /etc/ssh_banner.txt 48 | echo "* Your login user should be $1" >> /etc/ssh_banner.txt 49 | echo "* To get a login password open https://github.com/${2#*.com/}/blob/main/access.json on your browser" >> /etc/ssh_banner.txt 50 | echo '* Click on "Raw" (on the top) and then use the "?token=" value of the current URL' >> /etc/ssh_banner.txt 51 | echo '**********************************' >> /etc/ssh_banner.txt 52 | 53 | systemctl restart sshd || systemctl restart ssh 54 | 55 | echo "Github SSH Access Control Configured" 56 | fi 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enabling SSH Access Control Using Github Repo Permissions (No Key File) 2 | The described technique is using some undocumented capabilities, everything is provided without any warranty, use with caution and at your own risk. 3 | 4 | ### Motivation 5 | SSH keys are super annoying to maintain, they sprawl around, sent and received all over emails, slack channels and whatnot. It would be great if SSH access could be managed in a better way. 6 | 7 | ### The Better Way (if you can access a chosen repo => you can SSH to the host) 8 | The next time you will SSH to the host (without key file), you will see the following banner: 9 | 10 | ![Github SSH Access Control Example](https://i.imgur.com/SKik3YO.png) 11 | 12 | Following the instructions in the banner, which you'll only be able to complete if you have access to the repo, would give you a temporary token that can be used as a password for the SSH completion. 13 | 14 | ### How To Enable 15 | 1. Run the following on hosts you want to enable Github repo based SSH access control: 16 | ```sh 17 | curl -L -s https://tinyurl.com/githubsshinit | sed 's/\r//' | sudo sh -s - 18 | 19 | # example: curl -L -s https://tinyurl.com/githubsshinit | sed 's/\r//' | sudo sh -s - root shaylevi2/ssh 20 | ``` 21 | 22 | 2. On the repo used for access control you'll need a file called "access.json" with the following content: `{"root":"root"}` 23 | 24 | * If you want to use a different user, just add more key-value pairs to the JSON. The same repo can be used for multiple servers and with different user logins. 25 | 26 | ### How Does It Work?? (the interesting part) 27 | 28 | We are leveraging [CyberDem0n/pam-oauth2](https://github.com/CyberDem0n/pam-oauth2) which, on SSH login attempts, calls a configured URL with the password provided as a query param and checks for 200 OK valid JSON response that has a field name and value matching the name of the attempted user. 29 | 30 | We are combining it with Github's raw file access capability which happens to fit our use-case (no doubt that it wasn't developed for it, but if it's there, I'll use it). 31 | 32 | Basically, when you click "Raw" on a private repo file on Github, you'll be redirected to a URL which contains a temporary token in the query (at the time of writing, it's 10 minutes) that enables you to access the file even if you are logged out. 33 | 34 | Why Github? Github repo access is granular and can be easily gated with any SSO provider and Github are rather trusted in securely handling sensitive access tokens. 35 | 36 | So the complete flow is pam-oauth2 SSH module performing curl "raw.githubusercontent.com/[REPO]/main/access.json?token=[PASSWORD]" expecting to get a JSON response that has a key-value of the username used. This will only work if the password provided is a valid access token. 37 | 38 | You can see the code here: [tinyurl.com/githubsshinit](https://tinyurl.com/githubsshinit), or on this repo: [shaylevi2/githubssh](https://github.com/shaylevi2/githubssh). 39 | 40 | I think this is pretty cool! 41 | --------------------------------------------------------------------------------