Search code examples
gitpermissionsgitosisphp

Using git post-receive hook with nginx and php-fpm environment


I have a CentOS 6 server set up with git, gitosis, nginx, and php-fpm.

With our setup, nginx executes php scripts via php-fpm, which is configured on a per-site basis to run as a specific user for security purposes (i.e. not all under nginx:nginx) since we don't want the situation where if one site is compromised, all sites are compromised.

Our environment works great, but, when git is involved, php-fpm creates a fundamental issue.

Upon successfully running the following command locally:

$ git push origin

My post-receive hook is run:

#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.com/httpdocs git checkout -f

Normally, this would copy the contents of the repo into the httpdocs folder, however since php-fpm is installed and the directory+files are owned by a specific user, gitosis (or any other non-root user) can not write to the directory. This is made evident by the following error:

remote: error: git checkout-index: unable to create file index.php (Permission denied)

It makes sense, and that is what I would expect. However, I am wondering if there is a way to get around this issue in this specific case? Is there a way I can modify the post-receive hook to run as root (it is currently run by the gitosis user) or in some other fashion in order for it to succeed?

Just to be clear: there are no other problems with the setup, git works fine, nginx/php-fpm work fine, but this is a permissions issue which I am not quite sure how to get around.


Solution

  • You could use sudo to get the hook to run as user1, user2, user3, or whatever your system needs. You would need to consider the security implications of having the gitosis user able to masquerade as your web users, even if to a limited extent.

    Example recipe

    Given that the post-receive hook runs as user gitorious and assuming your web users are called user1, user2, user3 etc...

    Move your current post-receive hook into /usr/local/sbin/update-user1.sh, or some other suitable place, and make sure it's executable.

    Add something like these lines to /etc/sudoers:

    gitosis    localhost = (user1) NOPASSWD: /usr/local/sbin/update-user1.sh
    gitosis    localhost = (user2) NOPASSWD: /usr/local/sbin/update-user2.sh
    gitosis    localhost = (user3) NOPASSWD: /usr/local/sbin/update-user3.sh
    ... etc ...
    

    And then your post-receive hook for user1 could become something like:

    #!/bin/sh
    sudo -u user1 /usr/local/sbin/update-user1.sh
    

    Similarly for other users.

    Untested, so please test before implementing!