Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have a git server running over ssh and each user has a unix account on the system.

Given that two users have access to a repo, how can I be sure which user performed which commit, since the commit user name and email is submitted and controlled by the git client.

I am concerned that a user might try to impersonate another, even if they have the same authorization rights.

share|improve this question

migrated from stackoverflow.com Nov 2 '12 at 11:16

This question came from our site for professional and enthusiast programmers.

    
I'm confused. You say in the question that each user has their own shell account, but in a comment you say that they all share a single account and use separate keys for authentication. Which is it, or is it both? –  Scott Pack Nov 2 '12 at 13:11
    
Could be either. The current setup is the one described in the question (one ssh account per user), but this does not scale well and I might want to go with single user/many keys in the future. I am just looking for the most versatile solution that will not lock me into one or another authentication method. –  yannisf Nov 2 '12 at 13:14
    
It's worth pointing out that "the person that makes the commit" and "the person that pushes some commits to this repo" aren't necessarily the same in the general case. I could pull your commits from your repo and then push them (as me) to a third-party repo. –  nickgrim Nov 4 '12 at 19:38

4 Answers 4

up vote 13 down vote accepted

If you are that worried about it, there are a couple of ways of addressing the issue.

  1. Make your users sign your commits, there is support for GPG signing.
  2. Don't give users the right to commit to the main repository, have them commit to their own subrepository and then have a trusted user bring the changes into the main repository. That's why if you look at the log messages for some git projects (such as git itself) you'll see that their are separate fields for "Author" - the person who created the change. and "Committer" - the person who committed the change into the repository.
share|improve this answer
    
1. This suggestion seems to be the most apt for my purposes. Still, is there a mechanism to reject unsigned commits on the server side? 2. As far as this solution is concerned the user pulling from the subordinate repo will have to double check that the committer has not used forged username/email. True? –  yannisf Nov 2 '12 at 11:30
    
Be careful though, you can sign a commit with any committer and author identities that you care to choose. Obviously, you'll be able to see who did the forging (or didn't look after their private key). –  Charles Bailey Nov 2 '12 at 11:49
    
Hence my caveat about only having trusted users commit to the main repository. –  Abizern Nov 2 '12 at 11:51
    
@Abizern: Fair enough. As I read it, your (1) and (2) looked to be describing alternative options. –  Charles Bailey Nov 2 '12 at 12:04
1  
@yannisf Concerning your first question, the update hook (run server-side) might check the signatures and otherwise reject updating the respective refs. Have a look at the .git/hooks/update.sample for inspiration. Please @ notify me if you ask a question on this at SO, it would be interesting for me, too –  Tobias Kienzler Nov 2 '12 at 15:33

I see two good ways of getting this kind of information. One is by increasing the logging from sshd itself, and the other by doing deeper monitoring of the git repository on disk. Since neither one individually gives you the information you want, you may want to do both and correlate the log data using an external log analysis engine or on demand using human eyes and timestamps.

sshd Modifications

By default, as you've no doubt seen, you can see when a user logged in, and from where, using the ssh authentication logs. What you want to do is change the level at with you're logging out of sshd. So edit your /etc/ssh/sshd_config and find the line that looks like

#LogLevel INFO

and change that to

LogLevel VERBOSE

then restart the sshd service. This increases the logging level of sshd by 1 step, which gives a lot more information. Check out this log snippet of my remote access after making that change.

Nov  2 08:37:09 node1 sshd[4859]: Connection from 10.10.10.5 port 50445
Nov  2 08:37:10 node1 sshd[4859]: Found matching RSA key: f2:9e:a1:ca:0c:33:02:37:9b:de:e7:63:d5:f4:25:06
Nov  2 08:37:10 node1 sshd[4860]: Postponed publickey for scott from 10.10.10.5 port 50445 ssh2
Nov  2 08:37:10 node1 sshd[4859]: Found matching RSA key: f2:9e:a1:ca:0c:33:02:37:9b:de:e7:63:d5:f4:25:06
Nov  2 08:37:10 node1 sshd[4859]: Accepted publickey for scott from 10.10.10.5 port 50445 ssh2
Nov  2 08:37:10 node1 sshd[4859]: pam_unix(sshd:session): session opened for user scott by (uid=0)
Nov  2 08:37:10 node1 sshd[4859]: User child is on pid 4862
Nov  2 08:40:27 node1 sshd[4862]: Connection closed by 10.10.10.5
Nov  2 08:40:27 node1 sshd[4862]: Transferred: sent 30632, received 7024 bytes
Nov  2 08:40:27 node1 sshd[4862]: Closing connection to 10.10.10.5 port 50445
Nov  2 08:40:27 node1 sshd[4859]: pam_unix(sshd:session): session closed for user scott 

The important things to notice in here are two-fold

  1. We see the fingerprint of the public key used to authenticate me
  2. We see the timestamp of my log off

Using the default LogLevel (INFO) sshd logs neither of those items. Getting the fingerprint of a key is one extra step. You have to process the appropriate authorized_keys file with ssh-keygen as such.

[root@node1 ssh]# ssh-keygen -l -f /home/scott/.ssh/authorized_keys
4096 f2:9e:a1:ca:0c:33:02:37:9b:de:e7:63:d5:f4:25:06 /home/scott/.ssh/authorized_keys (RSA)

So now you know the following pieces of information:

  1. Username that logged on
  2. Time that user logged on
  3. Which public key was used for authentication
  4. Time that user logged off

Now that we have a way to attribute user action at a specific time, assuming both users weren't logged in at the same time, we can start looking at the changes made to the repository.

Directory Monitoring with Auditd

As sysadmin1138 said, this could be an excellent use case for the auditd subsystem. If you are not using a RedHat based distro there is probably an analogue, but you'll have to find it. The configuration for auditd is pretty intense and has a redonkulous number of configuration options. To get an idea of some of the options, please check out this question on our sister site for Information Security Professionals.

Minimally, I would recommend setting up what's called a "watch" on the directory on disk that contains your git repository in question. What this does is instruct the kernel module to report on attempts to perform file access calls, such as open() or creat(), on file handles pointing to the files or directories we list.

Here's a sample config that would do this, and only this. So be careful to read through, and understand, your existing /etc/audit/audit.rules in order to integrate changes appropriately.

# This file contains the auditctl rules that are loaded
# whenever the audit daemon is started via the initscripts.
# The rules are simply the parameters that would be passed
# to auditctl.

# First rule - delete all
-D

# Increase the buffers to survive stress events.
# Make this bigger for busy systems
-b 1024

-w /path/to/git/repos-p wa

# Disable adding any additional rules - note that adding *new* rules will require a reboot
-e 2
share|improve this answer
    
thank you so much for your detailed answer! It really is complete from a systems administrators perspective. What I was looking though was a solution that would not need one to resolve to so much low level auditing, and ideally will prevent forged commits rather than resolve to forensics after the fact. –  yannisf Nov 2 '12 at 13:19
2  
Well, you did ask on a Systems Administration site and I am a forensics examiner.... :) –  Scott Pack Nov 2 '12 at 13:26

Many ssh daemons make an entry in /var/log/audit.log or something similar when an ssh connection is received. Cross-referencing this log with the commit-log should give you an idea as to which ssh-user was used to issue a commit. This is an auditing step, to be used after the fact for verification.

Actually enforcing the correct ssh-user to appropriate git-user is for one of the other answers here.

share|improve this answer
    
There is still the setup that users login with the same ssh user but use different (authorized) keys. This makes the auditing even harder. –  yannisf Nov 2 '12 at 12:22
    
@yannisf: You're right, that does change things a bit. With any luck I helped address your extra need of dealing with non-attributable account access. –  Scott Pack Nov 2 '12 at 12:52

The only technical approach that you can take is to trust the identity of the ssh connection. You could then enforce that each user only pushes commits that he made by validating the committer of each new pushed commit.

For this to be reliable you almost certainly don't want to give your users unrestricted shell access to the box where the repository resides; you would want to ensure the use of something like git-shell only otherwise the restrictions are easily worked around.

Users would still be able to impersonate each other as authors, though. You could restrict this as well but this would lose of common workflows such as cherry-picking and rebasing and perhaps even branching (depending on your hook implementation) so you may not want to do this.

At some point, to some extent, you need to trust your developers.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.