Any suggestions on how I can speed up setting secure file and directory permissions?

I’m currently using gitlab-runner to deploy a Drupal site. In the interests of security in depth, I configured the vm so that the gitlab-runner user could change the file and directory permissions of the site to the recommended settings. I set very explicit nopasswd sudoers rules in /etc/sudoers.d.

First I chown the directory so that gitlab-runner can rsync the files over. Then, after the rsync, I run a script I found in Drupal’s documentation to set the file and group permissions. The script can be found here: https://www.drupal.org/node/244924#script-based-on-guidelines-given-above

This all takes about 15 seconds.

My developer has discovered that he sometimes runs into php errors, right after he pushes to the repository. That’s not something we can allow on our production instance. Which means he has to wait until off hours to deploy to production.

Since it used to be “instant” when we just used a webhook to make a script run and git pull the changes in, I’d like to speed it up.

Does anyone have any suggestions?

My .gitlab-ci.yml looks similar to:

deploy_master:
  stage: deploy_master
  script:
    - sudo chown -R gitlab-runner:gitlab-runner /var/www/projectname
    - |
      /usr/bin/rsync \
        --progress \
        -avz \
        --delete \
        --exclude=".git/" \
        --exclude=".gitignore" \
        --exclude=".gitlab-ci.yml" \
        --exclude="sites/default/settings.php" \
        --exclude="sites/default/files" \
        --exclude="sites/default/private" \
        docroot/ /var/www/projectname/docroot
    - sudo /usr/local/bin/fix-drupal-permissions --drupal_path=/var/www/projectname/docroot --drupal_user=root --httpd_group=www-data
  only:
    - master
  tags:
    - deploy_master

How about creating a project-specific runner that runs as the Drupal user instead of as a separate gitlab-runner user? That way, you don’t need to worry about the permissions.

Also, you should never have your website code owned by root unless you have a very good reason for doing so. Create a new user, maybe named drupal or website, and have that user own the website code and be the user that runs the CI runner.

I had a similar situation, managing Nagios configuration using GitLab CI, where the CI runner would update the Nagios config and send a signal to the nagios server to restart if the config was valid. The nagios server runs as the user nagios, and the project-specific runner also runs as that same user.

I do want to run the fix-drupal-permissions script on every run. It will stomp any odd files that somehow end up with an execute permission for “other”.

I’m currently looking into rsyncing to a staging directory, running the perms script, then rysncing to the docroot. If I change ownership to a drupal user like you suggest, that would help limit (maybe eliminate) how many sudo calls I need. Thanks for the suggestion. :slight_smile: I had forgotten that I could change the user gitlab-runner runs as.

So, I fully understand not wanting to let code be executed as root. I also understand how using a new drupal user as owner can increase security. But I do not see why having the files owned by root is a bad thing. Files owned by root can only be modified by users with root access. Can you explain your reasoning?

The reasoning is pretty simple. If your files are owned by root, then changes must be made by root (or by the group, but here the group exists to allow the webserver to read the files and that may not be the same as who owns them). If the files are owned by a user with lower privileges, then you only need to be that user to modify the files.

Not having the files owned by root is just an easy way of minimizing the number of things that would usually require root access to work with them. I have seen dozens of cases of servers (and MacOS laptops) wrecked by users who needed to work with files owned by root in ways that never could have happened if the files had been owned by some other user instead.

The truth is that in your case, since theoretically only the GitLab CI Runner, the number of cases in which a human will have to touch these files (and therefore become root) is minimal, but I like to stick to this rule anyway.

Hmm… I can see your point. But the point of making files owned by root, is to make sure only users with root access can modify them. And I don’t give root access out unless I really really really have to.

How do you keep the user specific gitlab-runner instance running between reboots and such?

I’m currently thinking of a systemd user specific service file. I haven’t had time to set it up yet, so I figured I’d ask.

A Systemd service is how I do it:

/etc/systemd/system/gitlab-runner-nagios.service

[Unit]
Description=GitLab Runner for Nagios
After=syslog.target network.target
ConditionFileIsExecutable=/usr/bin/gitlab-ci-multi-runner

[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/usr/bin/gitlab-ci-multi-runner "run" "--working-directory" "/usr/local/nagios" "--config" "/etc/gitlab-runner/config-nagios.toml" "--service" "gitlab-runner-nagios" "--syslog" "--user" "nagios"

Restart=always
RestartSec=120

[Install]
WantedBy=multi-user.target

It is identical to the regular GitLab Runner Systemd service, except for the changes to the paths and the username. Note that this example uses the old (v1.x and 9.x) filename.

You can also do the same thing using the --service, --working-directory, and --user arguments to gitlab-runner install. See the linked documentation for details.

Thanks!

Unfortunately, I ran into the fact my server is actually on Ubuntu 14.04. Copying the gitlab-runner upstart file and making appropriate modifications didn’t help. start-stop-daemon can’t get over the fact another gitlab-runner instance is already present.

From the man page:

start-stop-daemon will scan the process table looking for any processes which match the process name, parent pid, uid, and/or gid (if specified). Any matching process will prevent --start from starting the daemon.

afaik, there is no way to tell start-stop-daemon to not check the process name.

Um, I guess I could go looking for a sysv-init script…

Any other ideas?

Oh look, sysv-init uses start-stop-daemon… https://gitlab.com/gitlab-org/gitlab-runner/blob/3801ca230af59afc77abac64d3e89ac5703a58e5/packaging/sysv/root/etc/init.d/gitlab-ci-multi-runner

Sorry. I thankfully have no more Ubuntu 14.04 machines.

You should consider upgrading if you can - 14.04 has only one year (through April 2019) of support/updates left and that will be over before you know it.

Upgrading is on the todo list.