What permissions settings does push-to-deploy require? - linux

The title is general, but I have more specific questions. I am deep in a permissions nightmare trying to set up a "push-to-deploy" system using Git.
From my local machine, I push by SSH to the server (Ubuntu 14.04). I have the server set up as the remote
git remote add development devuser#development.server:/home/dummyuser/bare/repo.git
This bare repository is within the home folder of a dummy user dummyuser that we use to handle deployment tasks. devuser is my own account on the development server.
I have a post-receive hook set up within the remote repository (development.server:/home/dummyuser/bare/repo.git/hooks/post-receive) that's intended to deploy files via git checkout to a web server directory on the same server, call it webfolder/. That folder currently has permissions
drwxr-xr-x dummyuser www-data webfolder/
where www-data is the group associated with the Apache user.
If I have the post-receive hook script use the command
git --work-tree=/var/www/webfolder --git-dir=/home/dummyuser/bare/repo.git checkout -f
I get errors that it can't write to webfolder/, which is predictable since I assume the script is running as me (devuser) since I did the instigating push via SSH, and devuser doesn't have any permissions on webfolder/.
However, if I change the script to act as dummyuser,
sudo -u dummyuser git --work-tree=/var/www/webfolder --git-dir=/home/dummyuser/bare/repo.git checkout -f
just to see what happens, I have the error
warning: unable to access '/home/devuser/.config/git/attributes': Permission denied
There's a couple of things I don't understand about this:
1) Neither /home/devuser/.config/ nor /home/dummyuser/.config/ exist. That's fine, but if Git needs to access a .config/ folder, why wasn't it complaining before when I was setting up bare repos and executing hooks as devuser?
2) Now that I'm trying to act as dummyuser, why is Git looking in ~devuser/ for a .config/ folder? Why isn't it looking in ~dummyuser/?
I've been working on this tiny slice of one single problem in the maddening shitshow that is "using Git" for coming up on four hours now, and my brain is fuzzy, so please use small words.

The problem is something involving sudo -u dummyuser not setting the environment variables that Git expects. If I add HOME=/home/dummyuser to the post-receive hook, the deployment works as expected.
If anyone can provide more details about what's happening or a better solution, write it as an answer and I'll accept it. Couple of notes:
dummyuser doesn't have a login, so using sudo -iu dummyuser in the post-receive script won't work
After setting HOME=/home/dummyuser manually and successfully executing the script, I find that echo $HOME from the terminal returns /home/devuser, so there's no permanent change to $HOME
After successfully executing the hook script, neither ~devuser/ nor ~dummyuser/ nor /root/ have a .config/ folder. So... I still have no idea why Git was hung up on it.

Git expects a .config folder in the user's home directory. If $HOME isn't set correctly, e.g. if it points to a different user's home, Git will try to access $HOME/.config, not knowing that it actually doesn't even exist. However, since the user, and thus Git, doesn't have access to that $HOME, you will receive an error saying Permission denied.
To test that, try to run as dummyuser:
[ -d /home/devuser/.config ] && echo '.config exists!'
You're trying to test if the directory /home/devuser/.config exists. However, since you don't have the needed permissions, you get Permission denied, and you still don't know whether the directory exists or not.
Instead of setting $HOME manually, you could possibly use -H or --set-home:
sudo -Hu dummyuser git --work-tree=/var/www/webfolder --git-dir=/home/dummyuser/bare/repo.git checkout -f

Related

Doing a 'git pull' with Apache from a Bash script

I have a Git repository on Bitbucket named "foo-apps". I have a Linux web server with a local clone of this repository, and I want this server's associated Apache web page to do some Git commands with this repository, such as git pull and git checkout, via a Bash script. The problem is, only the user "foo" has permission to associate with the "foo-apps" repository, and the web page runs as the Apache user, "www-data".
It seems that www-data can do git log and some other commands on the local repository, but not the git pull or the git checkout command. (Just so you know my system: I have an HTML file that contains JavaScript, which contains an AJAX request, which calls a PHP file, which calls my Bash script, which has the Git commands in it.)
What are some ways that I can successfully get those Git commands to work when the process is triggered by the web interface? I am not opposed to any working suggestions, even if they include a complete overhaul of my system... however, I would like to have the simplest effective solution with what I've already got.
Here are some ideas I've thought of and tried out a bit. None of them seem to work, but keep in mind that I've only "half tried" them as I didn't have confidence I was using preferred methods:
Giving www-data permission on my Bitbucket repository
Giving Apache access to foo's ssh keys
Somehow switching to user foo in the script, like with sudo, su, etc.. (I think this type of thinking is more along the lines of what I want... I don't have a lot of control over the settings of the Bitbucket repository. I am fine putting a password in a script, too.)
This web server is on a closed network, and security is not a very high concern for me.
I don't know if it's useful, but here are some of the main Git related errors I've received when trying these methods:
error: cannot open .git/FETCH_HEAD: Permission denied
fatal: BUG: get_tempfile_fd() called for inactive object
/usr/bin/git: /usr/bin/git: cannot execute binary file
I found the answer on this page (thanks odyniec).
I had to add this line to the /etc/sudoers file:
www-data ALL=(foo) NOPASSWD: /var/www/html/my_bash_script.sh
This let Apache have the permission to run that specific script I wanted. And then from my PHP file, instead of running
shell_exec("/var/www/html/my_bash_script.sh");
I had to run
shell_exec("sudo -u foo /var/www/html/my_bash_script.sh");
This answer seems secure and simple.

Mercurial - execute as other user

I use a mercurial repository for global configuration. The system config files are linked to /opt/config which is a hg repo owned by root.
I d like all users to be able to update settings from repo i.e. to call hg pull -u in /opt/config
I tried to create the following script
# -rwsr-x--x 1 root users 343 Mar 15 14:10 /bin/update_config
#! /bin/bash
cd /opt/config
hg pull -u
(Pay attention, the s-bit is set) . In this case, hg does not read the settings from /root/.hgrc which contain the HTTP login parameter (user cannot does not know the parameters)
even if I do export HOME=/root the hgrc file is not read.
How should I change my script to make it possible?
EDIT
It seems to be a general permission problem. I use sles11. The line touch /root/bla does not work in this script, why?
Mercurial being a distributed versioning system, it seems to me that you are not using it correctly. If users are required to modify the repository, every user should handle its own repository and then configure it to push into your desired location (/opt/config). Hence, the mercurial workflow will handle the merge problems. If they are only consumers of the repository, you should either 1) create a cron entry to update it automatically or 2) use a continuous integration system like Jenkins or TeamCity that will automatically update the repository when something is pushed to it.
If you still want to realize what you asked, you should look into the sudo command for this purpose. Make the /opt/config ownership to a new passwordless user, configure sudo to allow the switch to this user without password and make the configuration only in ~theuser/.hgrc . This will make it easier to maintain (only a single .hgrc to handle).

Deploying Node Apps via Gitolite and post-receive hook

I'm trying to get a fairly simple deploy process going for a Node app using Gitolite. I have Gitolite setup and working on my server, and I'm able to push to it fine.
Gitolite is running under a user called git, and I've setup a node user that I'm hoping to use to run the Node app.
My plan is to push the Node app to Gitolite, and then use a post-receive hook script to move the app files to the directory where the app lives, in this case /var/local/node-apps/my-node-app/. I created the Node app folder like this:
sudo mkdir -p /var/local/node-apps/my-node-app
sudo chown node /var/local/node-apps/my-node-app
The problem is that I'm a Unix noob and I haven't got my head round file/folder permissions and wotnot.
/var/local/node-apps (and also /var/local/node-apps/my-node-app) is owned by the node user, so when the git user tries to checkout to this location I get a bunch of permission denied errors. The command I'm using in the post-receive is:
GIT_WORK_TREE=/var/local/node-apps/my-node-app git checkout -f
And I get errors like this:
remote: error: git checkout-index: unable to create file XXXX (Permission denied)
remote: fatal: cannot create directory at 'XXXX': Permission denied
What's the best way to resolve this? Do I need to grant the git user password-less sudo rights to su as the node user? Or can this be somehow fixed by changing groups and folder permissions? Or a different approach entirely? I'm lost!
Thanks!
Using sudo would certainly work, you have one example at "post-receive hook permission denied “unable to create file” error", wrapping the git commands in a script.
Changed post-receive to:
sudo sh /usr/local/sbin/prgetsimpleappscom
Changed sudoers with visudo
git ALL = (root) NOPASSWD: /bin/sh /usr/local/sbin/prgetsimpleappscom
The other approach would be a cron job as node user regularly fetching and (if there are new commit) pulling in the destination repo.

Auto Deploying with Git

I am wondering if anyone has a better strategy for this scenario.
I am currently hosting my own remote git repo on the same box as the webserver.
All git repos are under the git user.
sudo -uwww-data -gwww-data git --git-dir=/var/www/website/.git --work-tree=/var/www/website pull
I have a cron job running as root every minute that executes this command. The git repo in the web folder is cloned from the same box to git's home dir where it's stored instead of through ssh.
So my question: Since git doesn't own the web files, it can't move the site using a git hook. I would assume I don't want git to have sudo, nor would that work via a git hook, right? Is there something that will deploy the site faster than every minute? I don't want the operation to be very expensive.
Is there some kind of daemon root could run and listen for some kind of notification? Like having it watch a file's last modified time?
Note that this article (in French, translated through Google) reports that sudo works with your approach:
change sudo to allow the gitosis user to use this command as www-data.
To do this, by running "visudo" add the line:
git ALL = (www-data) NOPASSWD: /usr/local/bin/pullhere
Then, in each repository where necessary, add the next hook in a post-receive file:
sudo -u www-data /usr/local/bin/pullhere /html/u/user/here
eg in / home/git/repositories/projet1.git/hooks/post-receive
This might interest you if you're still looking at a way to perform automatic deploys after a git push:
https://github.com/JamesBrooks/git-runner (with the git-runner-deploy gem).

git: can't push (unpacker error) related to permission issues

I have this problem when i try to push in git:
error: insufficient permission for adding an object to repository database ./objects
fatal: failed to write object
error: unpack failed: unpack-objects abnormal exit
To ssh://<repo url>/<repo dir>
! [remote rejected] master -> master (n/a (unpacker error))
error: failed to push some refs to 'ssh://<repo url>/<repo dir>'
I've had this before sporadically and we've always had to solve it by each user sshing to the repo and setting group permissions on all the files therein with
chmod -R g+w *
This was never a satisfactory solution and now it's bitten us in the arse as one of the guys is away and no-one knows his repo user's password. So, i'm trying to solve it properly.
The error seems to occur when someone tries to push up a change that will alter a repo dir that is owned by another user (hence setting the group write option above). I've done a bit of googling around this and have found a couple of solutions being discussed (neither of which worked for me)
1) make sure that the group that the repo dirs are shared with is each users' primary group (i believe that is the case already: each user has only one group so that must be their primary group, right?)
2) git repo core.sharedRepository setting, as detailed here: Git: Can't push from one computer
I changed this but it didn't make any difference. Do i need to reload the config or something to actually effect the change?
Here's what my repo config looks like atm:
[core]
repositoryformatversion = 0
filemode = true
bare = true
sharedRepository = all
[receive]
denyNonFastForwards = True
Grateful for any advice or suggestions!
max
I had this error for two weeks, and the majority of the solutions stated 'chmod -R' as the the answer, unfortunately for me my git repos (local / remote / shared - with team) were all on Windows OS, and even though chmod -Rv showed all the files changed to 'rwxrwxrwx', a subsequent 'ls -l' still showed all files as 'rwxr-xr-x' and the error repeated itself. I eventually saw this solution by Ariejan de Vroom. It worked and we were all able to pull and push again.
On both local (the local that is having trouble pushing) and remote repos, run the following commands:
$ git fsck
$ git prune
$ git repack
$ git fsck
On a side note, I tried using Windows' native file permissions / ACL and even resorted to elevating the problem user to Administrator, but none of that seemed to help. Not sure if the environment is important, but it may help someone with a similar setup - problem team member and remote (Windows Server 2008 R2 Standard), my local (Windows 7 VM).
A simpler way to do this is to add a post-receive script which runs the chmod command
after every push to the 'hub' repo on the server. Add the following line to hooks/post-receive inside your git folder on the server:
chmod -Rf u+w /path/to/git/repo/objects
It is a permission error. The way that was most appropriate and secure for me was adding users to a supplementary group that the repo. is owned by (or vice versa):
groupadd git
chgrp -R git .git
chgrp -R git ./
usermod -G -a git $(whoami)
In case anyone else is stuck with this: it just means the write
permissions are wrong in the repo that you’re pushing to. Go and chmod
-R it so that the user you’re accessing the git server with has write access.
For me, this error occurred when I was out of space on my remote.
I just needed to read the rest of the error message:
error: file write error (No space left on device)
fatal: unable to write sha1 file
error: unpack failed: unpack-objects abnormal exit
For the permission error using git repository on AWS instance, I successfully solved it by creating a group, and assigning it to the repository folder recursively(-R), and give the written right to this group, and then assign the default aws instance user(ec2-user or ubuntu) to this group.
1. Create a goup name share_group or something else
sudo groupadd share_group
2. change the repository folder from 'root' group to 'share_group'
sudo chgrp -R share_group /path/to/your/repository
3. add the write authority to share_group
sudo chmod -R g+w /path/to/your/repository
4. The last step is to assign current user--default user when login (by default ec2 is 'ec2-user', user of ubuntu instance is 'ubuntu' in ubuntu on aws) to share_group. I am using ubuntu insance on aws, so my default user is ubuntu.
sudo usermod -a -G share_group ubuntu
By the way, to see the ownership of the folder or file just type:
ls -l /path/to/your/repository
'
Output:
drwxr-x--x 2 root shared_group
(explanation please see:https://wiki.archlinux.org/index.php/File_permissions_and_attributes).
After step 3, you will see
drwx--x--x 2 root root
changed to
drwxr-x--x 2 root share_group
In this case, I did not assign user 'ubuntu' to root group, for the consideration of security. You can just try to assign you default user to root according to step 4 (just skip the first 3 steps
In another way, tried the solution by :
chmod -Rf u+w /path/to/git/repo/objects
It did not work for me, I think it should be the reason that my repository folder belong to the root user, not to Ubuntu user, and 'git' by default use the default user(ec2-user or Ubuntu user. You can try to change the user and test it.
Finally, below code definitely work for me, but 777 is not good for security
sudo chmod -R 777 /path/to/your/repo
I use gitosis for managing this kind of stuff. Gitosis has a single user (usually called "git") that owns all the repositories, and it uses public-key-based access control to each repo. It might not suit your setup but is probably worth checking out (no pun intended).
This problem can also occur after Ubuntu upgrades that require a reboot.
If the file /var/run/reboot-required exists, do or schedule a restart.
I was getting similar error and please see below how I resolved it.
My directory structure:
/opt/git/project.git
and git user is git
$ cd /opt/git/project.git
$ sudo chown -R git:git .
chown with -R option recursively changes the ownership and and group (since i typed git:git in above command) of the current directory. chown -R is necessary since git changes many files inside your git directory when you push to the repository.
I was having trouble with this too, thinking my remote gitolite-admin was corrupted or something wrong.
My setup is Mac OS X (10.6.6) laptop with remote Ubuntu 10 server with gitolite.
It turned out that the problem was with my local checkout of gitolite-admin.
Despite the "unpack failed" error, it turned out the the problem was local.
I figured this out by checking it out again as gitolite-admin2, making a change, and the pushing.
Voila! It worked!
For what it worth, I had the same problem over my own VPS and it was caused by my low hard disk space on VPS. Confirmed by df -h command and after i cleaned up my VPS' hard disk; the problem was gone.
Cheers.
Where I work we have been using this method on all of our repositories for a few years without any problems (except when we create a new repository and forget to set it up this way):
Set 'sharedRepository = true' in the config file's '[core]' section.
Change the group id of the repository to a group shared by all users who are allowed to push to it:
chgrp -R shared_group /git/our_repos
chmod -R g+w /git/our_repos
Set the setgid bit on all directories in the repository so that new files/directories keep the same group:
find /git/our_repos -type d -exec chmod g+s {} +
Add this line to the pre-receive hook in the repository to ensure new file permissions allow group read/write:
umask 007
For me its a permissions issue:
On the git server run this command on the repo directory
sudo chmod -R 777 theDirectory/
A git configuration mistake can also product this error. I give my students and example of configuration like this:
git config --global user.name "John Doe"
git config --global user.email johndoe#example.com
One of my students was getting the unpacker error. Other students were fine, but I still did a double check on the git server's permissions and to be sure the student was in proper group.
Finally, I had the student do a git log and saw that he had John Doe for his configuration, but his branch was his own name.
Setting up his configuration properly eliminated the error .
I had similar problem like this before:
! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'https://mywebsite.com/my-git-directory.git'
In my case, I have checked wrong directory ownership with ls -l. I change the directory owner to www-data to solve the problem like this:
sudo chown -R www-data:www-data my-git-directory.git/
But in this case I not use SSH method, I use HTTP method.
Maybe when we make sure the directory owner is correct, it can solve the problem.

Resources