17

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.

3
  • 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, 2012 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, 2012 at 13:14
  • 1
    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, 2012 at 19:38

5 Answers 5

13

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.
6
  • 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, 2012 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).
    – CB Bailey
    Nov 2, 2012 at 11:49
  • Hence my caveat about only having trusted users commit to the main repository.
    – Abizern
    Nov 2, 2012 at 11:51
  • @Abizern: Fair enough. As I read it, your (1) and (2) looked to be describing alternative options.
    – CB Bailey
    Nov 2, 2012 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 Nov 2, 2012 at 15:33
9

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
2
  • 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, 2012 at 13:19
  • 2
    Well, you did ask on a Systems Administration site and I am a forensics examiner.... :)
    – Scott Pack
    Nov 2, 2012 at 13:26
5

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.

3

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.

2
  • 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, 2012 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, 2012 at 12:52
0

If all users have shell accounts with write access to the repository, you won't be able to set up a trustworthy audit log: they could still modify the repository without writing to the log, and they could write whatever they want to the log.

To be able to trust the audit log, you would need to prevent direct file-level write access to the repository, instead using something like gitolite (which runs in its own account) to mediate access to the repository.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .