Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create users_sync.sh #78

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`users_sync.sh` has been created to automatically give members of the Armbian organization access to https://users.armbian.com (WIP)
173 changes: 173 additions & 0 deletions utils/users_sync.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#!/bin/bash


### TODO
# add blocklist/keeplist
# add update/refresh keys on existing user
# make sure concealed members are grabbed as well: https://docs.github.com/en/rest/orgs/members?apiVersion=2022-11-28#list-organization-members


### CONFIG
# where are the user directories?
# NO trailing slash!
# the owner of the parent directory must be "root"!
# configure nginx accordingly
USERPATH=/armbianusers

# which group is used to catch and jail users into their sftp chroot?
SFTPGROUP=sftponly

# classic token from any organization member with "read:org" permission
TOKEN=xxx

# the organization you want to read members from
ORG=armbian

# Users that shall not get access
BLOCKLIST='armbianworker|examplemember1|examplemember2'

# enable debugging
DEBUG=yes

### END CONFIG


### DO NOT EDIT BELOW! ###


### CHECKS
# Check if curl is installed
command -v curl >/dev/null 2>&1 || echo >&2 "\"curl\" not found. Aborting."

# Check if jq is installed
command -v jq >/dev/null 2>&1 || echo >&2 "\"jq\" not found. Aborting."


# validate token
RESPONSE=$(curl -sS -f -I -H "Authorization: token $TOKEN" https://api.github.com | grep -i x-oauth-scopes |grep -c read:org)
if [[ $RESPONSE != 1 ]]; then
echo "Token invalid or lacking permission."
echo "Exiting..."
exit 1
fi

# check for root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
echo "Exiting..."
exit 1
fi

# check for existing sftp group
if ! getent group sftponly &> /dev/null
then
echo "\"$SFTPGROUP\" group does not exist. Use \"groupadd $SFTPGROUP\" to add."
echo ""
echo "Add this to your \"sshd_config\" if not done already."
echo ""
echo "Match Group $SFTPGROUP"
echo " ChrootDirectory $USERPATH"
echo " ForceCommand internal-sftp"
echo " AllowTcpForwarding no"
echo ""
echo "Exiting..."
exit 1
fi
### END CHECKS


### FUNCTIONS

grab_keys() {
# $1 = username
echo "Trying to grab ssh keys for $1"
mkdir -p "$USERPATH"/"$1"/.ssh
curl -s https://github.com/"$1".keys > "$USERPATH"/"$1"/.ssh/authorized_keys
chown -R "$1":"$SFTPGROUP" "$USERPATH"/"$1"/.ssh
chmod 700 "$USERPATH"/"$1"/.ssh
chmod 600 "$USERPATH"/"$1"/.ssh/authorized_keys

# Check if grabbed stuff are actual ssh keys.
# curl response for members w/o keys is "not found" but exit code is still 0
# so this needs to be worked around
CHECK_KEYS=$(grep -c -E "^ssh" "$USERPATH"/"$1"/.ssh/authorized_keys)
if [[ $CHECK_KEYS != 0 ]]; then
echo "$i - $CHECK_KEYS key/s for $1 imported"
else
echo "(!) $1 - Either grabbing failed or $i does not have ssh key on git"
echo "(!) $1 won't be able to login"
rm "$USERPATH"/"$1"/.ssh/authorized_keys
fi
}


# grab a list of current remote org members, filter blocked ones
echo "Grabbing a list of all current members of \"$ORG\"."
echo "Excluded by blocklist are \"$BLOCKLIST\"."
ORGMEMBERS=$(curl -L -s \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/orgs/$ORG/members | jq -r ".[].login" \
| grep -v -E -- "$BLOCKLIST" )
if [ $DEBUG == "yes" ]; then echo -e "DEBUG: \$ORGMEMBERS:\n$ORGMEMBERS\n\n"; fi

# Grab a list of local directories...
# We assume that existing directory means locally existing user as well
cd $USERPATH || exit 1
LOCALMEMBERS=$(echo -n "`ls -d -- */`" | sed 's/\///g' | tr '\n' ' ')
echo "Already existing members at \"$USERPATH\": \"$LOCALMEMBERS\"."
# ...and make it comparable for shell (remove trailing slash, replace newline with | and add round brackets)
LOCALMEMBERS_COMPARE=$(echo -n "`ls -d -- */`" | sed 's/\///g' | tr '\n' '|' | sed -r 's/^/\(/' | sed -r 's/$/\)/')
if [ $DEBUG == "yes" ]; then echo -e "DEBUG: \$LOCALMEMBERS_COMPARE:\n$LOCALMEMBERS_COMPARE\n\n"; fi

# loop through remote org members and add if not existing
for i in $ORGMEMBERS; do

if ! [[ $i =~ $LOCALMEMBERS_COMPARE ]]; then # skip locally already existing users

# create local user and directory
echo "$i - no local directory found. Creating..."
if ! useradd -m -s /bin/false -G "$SFTPGROUP" -d "$USERPATH"/"$i" "$i"
then
echo "$i's directory could not be created for whatever reason"
exit 1
fi
echo "$i - user and directory created"

# grab ssh keys and put into user's .ssh/authorized_keys file
grab_keys "$i"

else
echo "$i - local directory found. Trying to update keys..."
grab_keys "$i"

fi
done

echo ""
echo "Removing no longer existing members of \"$ORG\""
echo ""
### remove local users not exsting in remote org
# make list of remote organization members comparable
ORGMEMBERS_COMPARE=$(echo "$ORGMEMBERS" | tr '\n' ' ' | sed 's/\ /\|/g'| sed -r 's/^/\(/' | sed -r 's/\|$/\)/')
if [ $DEBUG == "yes" ]; then echo -e "\nDEBUG: \$ORGMEMBERS_COMPARE:\n$ORGMEMBERS_COMPARE\n\n"; fi
if [ $DEBUG == "yes" ]; then echo -e "\nDEBUG: \$LOCALMEMBERS:\n$LOCALMEMBERS\n\n"; fi
# loop through org members and compare against local list
for i in $LOCALMEMBERS; do

if [[ $i =~ $ORGMEMBERS_COMPARE ]]; then # compare local user against list of remote org members. If not found carry on
echo "$i is still member of \"$ORG\". Skipping..."
else
echo -e "$i is not or no longer in the list of \"$ORG\" members or has been blocklisted.\nRemove the user and their files? (y/N)\nTHIS CANNOT BE UNDONE!\n"
read -n 1 INPUT
: "${INPUT:=n}"
if [ $INPUT == "y" ]; then
userdel --remove "$i"
else
echo "Keeping $i"
fi
fi
done


Loading