We have a shared Linux build PC. It runs Ubuntu 22.04.5 LTS. It only has one account. We log in using RDP from various PCs (usually running Windows). We want to have the proper git commit author name/email and the proper identity of the pusher (ssh-key) in bitbucket. Sometimes there is a mismatch and a wrong ssh-key is used that doesn't match the person who committed. In pull requests in bitbucket the pusher is listed as the one who updated a pull-request. We want the correct pusher to be detected.
In order to prevent people committing code under the wrong author we don't save the author name and email. Instead we add username and email to commands:
git -c user.email=email@example.com -c user.name='John Doe' some-git-command
This works and prevents people from accidentally committing under the previous user.
But this is inconvenient and doesn't update the ssh-key.
In order to select the matching ssh key I created a git hook pre-push
. It works by selecting the key based on the current author's email address.:
#!/bin/sh
remote="$1"
url="$2"
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
echo "pre-push global"
AUTHOR_NAME=$(git config user.name)
AUTHOR_EMAIL=$(git config user.email)
USER="UNKNOWN"
#echo $AUTHOR_NAME
#echo $AUTHOR_EMAIL
if [ "$AUTHOR_EMAIL" = "example1@email.com" ]; then
USER="E1"
elif [ "$AUTHOR_EMAIL" = "example2@email.com" ]; then
USER="E2"
elif [ "$AUTHOR_EMAIL" = "example3@email.com" ]; then
USER="E3"
#elif [ "$AUTHOR_EMAIL" = "" ]; then
# USER=""
else
echo "error: unknown user, cannot push"
exit 1
fi
echo $USER
# todo: select SSH key based on USER
cp "/home/build/.ssh/"id_ed25519_"$USER" "/home/build/.ssh/"id_ed25519
cp "/home/build/.ssh/"id_ed25519_"$USER".pub "/home/build/.ssh/"id_ed25519.pub
#ssh-add ~/.ssh/id_ed25519
#eval `ssh-agent -s`
exit 0
It does replace the ssh-key with a copy of the matching one, but it's not used. I think it's cached. Restarting the ssh-agent in the script does not work. However restarting it manually does work (it seemed to have worked only once). Another solution could involve modifying gitconfig and have the ssh-key depend on some condition.
I'm not necessarily looking to have this implementation fixed, but for a more generic solution. Involving at least:
We already know how to do 2 manually, by running a shell script with username in the file name manually. But this is tedious.
The challenge is to detect who logged in since the username is always build
. We don't want to create a new Ubuntu account. Perhaps there is such a thing as a "subaccount"? Or an account alias?
Perhaps we could detect the local ip-address of the connecting Windows PC. Local IP-adresses are long lease, but not fixed, so this is not a long-term solution. Perhaps a mac address? PCs are on the same network.
Perhaps there is a way to detect a specific RDP-client?
I found one solution. I discovered renaming keys doesn't work. So instead I change the ssh config file to use a different key. Since local IP addresses are not static I use the MAC address to detect who is connecting.
I detect RDP login using these files:
I added a single line at the top of these two files:
/home/build/username.sh
This file does two things:
username.sh:
/home/build/username.py
service ssh restart
username.py:
#!/usr/bin/env python
import re
from getmac import get_mac_address
from datetime import datetime
# Path to xrdp log file
log_path = "/var/log/xrdp.log"
# Example pattern to match client IPs
regex = r"connected to.*client_ip=::ffff:([\.\d]+)"
#print(f"opening file {log_path}")
last_ip = None
with open(log_path, 'r') as file:
for line in file:
#print(line)
m = re.search(regex, line)
if m:
#print(m.group(1))
last_ip = m.group(1)
#print(last_ip)
mac = get_mac_address(ip=last_ip).lower()
#print(f"MAC address of {last_ip}: {mac}")
user = None
if mac == "MAC1".lower():
user = "U1"
elif mac == "MAC2".lower():
user = "U2"
elif mac == "MAC3".lower():
user = "U3"
now = datetime.now()
file1 = open("/home/build/username.log", "a+") # append if exists, creates if it doesn't
if user:
file1.write(f"{now} {user}\n")
else:
file1.write(f"{now} {mac}\n")
file1.close()
ssh_config_path = "/home/build/.ssh/config"
if user:
regex = r"(~\/.ssh\/)(id_ed25519(_[A-Z]{2})*)"
with open(ssh_config_path, 'r') as f:
# Read the file contents into a single variable
config = f.read()
subst = "\\1id_ed25519_" + user
config = re.sub(regex, subst, config, 0, re.MULTILINE)
with open(ssh_config_path, 'w') as f:
# Read the file contents into a single variable
f.write(config)
The first MAC address is substituted for MAC1
and the first user credentials are substituted for U1
.
The config file ~/.ssh/config:
Host bitbucket.org
User git
IdentitiesOnly=yes
PreferredAuthentications publickey
PasswordAuthentication no
IdentityFile ~/.ssh/id_ed25519_XX
IdentitiesOnly yes
AddKeysToAgent yes