gitubunturemote-desktop

How can I automatically switch git user (commit author and ssh-key for pushing) on a shared Linux account?


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:

  1. automatically clearing username, email and selected ssh-key upon logging in/out (even logging in when someone else is logged in who will automatically be logged out).
  2. automatically detecting user's identity/connecting PC's identity and setting username,email and key

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?


Solution

  • 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:

    1. /etc/xrdp/startwm.sh
    2. /etc/xrdp/reconnectwm.sh

    I added a single line at the top of these two files:

    /home/build/username.sh
    

    This file does two things:

    1. Call a python script to change credentials by changing ssh config
    2. reset the ssh service

    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