Deployer: Symfony4 recipe: setfacl: Operation not permitted

Created on 1 May 2020  路  10Comments  路  Source: deployphp/deployer

Describe the bug
I'm using the symfony4 recipe. On second deployment (after using the application), the following error occurs:

  The command "cd /opt/myapp/releases/2 && (setfacl -L -R -m u:"www-data":rwX -m u:`whoami`:rwX var)" failed.

  Exit Code: 1 (General error)

  Host Name: myhost

  ================
  setfacl: var/sessions/prod/sess_pneuui5pv24bk12cig5vsoglm0: Operation not permitted

The reason is that this file was created by the web server user "www-data", so the ACL cannot be changed by the deployment user.

I see that this is exactly what you are trying to prevent already:
https://github.com/deployphp/deployer/blob/5095b5de166498aedb6ef7ffff98d7243fa036ea/recipe/deploy/writable.php#L79

I assume this doesn't work due to the fact that shared dirs are inside the writable directory:

set('shared_dirs', ['var/log', 'var/sessions']);
set('shared_files', ['.env.local.php', '.env.local']);
set('writable_dirs', ['var']);

... but shared directories are processed before writables. This breaks the hasfacl check here:
https://github.com/deployphp/deployer/blob/5095b5de166498aedb6ef7ffff98d7243fa036ea/recipe/deploy/writable.php#L86

My suggestion is to place deploy:writable before deploy:shared in the deployment task of the symfony4 recipe.

Environment

  • Deployer version: 6.7.3
  • PHP version: 7-2
  • Deployment target(s) OS: Ubuntu 18

Content of deploy.php

<?php
namespace Deployer;

//require 'recipe/rsync.php';
require 'vendor/deployer/recipes/recipe/rsync.php';
require 'recipe/symfony4.php';

// Project name
set('application', 'myapp');

set('rsync', [
    'exclude' => ['.git', 'meta', 'var', 'app/config/parameters.yml'],
    'flags' => 'rzcE',
    'timeout' => '300',
]);
set('rsync_src', 'src');

// #WORKAROUND --no-dev does't work, because those dependencies are expected on cache:warmup
set('composer_options', '{{composer_action}} --verbose --prefer-dist --no-progress --no-interaction --optimize-autoloader --no-suggest');

add('shared_files', ['app/config/parameters.yml', 'var/.htpasswd']);
add('shared_dirs', ['var/logs', 'var/sessions', 'var/uploads']);

inventory('hosts.yml');
host('myapp');

task('deploy', [
    'deploy:info',
    'deploy:prepare',
    'deploy:lock',
    'deploy:release',
    //'deploy:update_code',
   'rsync',
    'deploy:shared',
    'deploy:vendors',
    'deploy:writable',
    'deploy:cache:clear',
    'deploy:cache:warmup',
    'deploy:symlink',
    'deploy:unlock',
    'cleanup',
]);

after('deploy:failed', 'deploy:unlock');
bug

Most helpful comment

Fixed!

All 10 comments

But how this is going to help? If you still not have permission. Maybe I don't understand it.
Can you explain it a little bit more? What is your setup? Now is a perfect time to make some changes as new v7 is coming.

There are 2 users, deployer and www-data. This is how it currently works:

  • 1st deployment

    • deploy:shared



      • creates dirs var/logs, var/sessions, var/uploads in new release dir


      • creates symlinks



    • deploy:vendors writes into the dirs created in the shared task as user deployer

    • deploy:writable



      • doesn't create var because it's already there


      • runs setfacl -L -R -m u:"www-data":rwX -m u:`whoami`:rwX var



  • app is being used

    • Symfony4 creates files in shared dirs with owner www-data

  • 2nd deployment

    • deploy:shared



      • creates dirs var/logs, var/sessions, var/uploads in new release dir; notice that it also creates the var directory without FACL


      • creates symlinks



    • deploy:vendors writes into the dirs created in the shared task as user deployer

    • deploy:writable



      • doesn't create var because it's already there


      • runs setfacl -L -R -m u:"www-data":rwX -m u:`whoami`:rwX var and crashes because it is recursive but user deployer cannot change the facls of the files created by www-data above.



So, how is my suggestion to move deploy:writable before deploy:shared and deploy:vendors going to help?

First, it's important to notice that deploy:writable uses the -d flag to set the default facl entries for the writable dir. This means that all files created inside will also have the facl entries.

It works, because on second deployment, deploy:writable will create an empty var dir in the new release dir. It's empty, because deploy:shared hasn't been running yet. So it can run the facl command, as there are no files owned by www-data yet. After that, deploy:shared will create the sub-directories (logs, sessions, uploads), but not var itself, so the facl of var is still available and the sub-directories will inherit the facl, due to the -d flag.

In my first comment I wrote that deploy:shared breaks the hasfacl-check, but I was wrong.

BTW you wrote that there will be a new version. Did you also see my comment here? https://github.com/deployphp/deployer/commit/5923e442eea8811762c1e211e55741642b8d303e#r38820081
I don't know if authors are notfied about such code comments.

I get the notification but can not find it there as commit is really big.

I experience exactly the same issue.
The deploying user is myuser

First deployment : succeeds, creates shared dirs and setfacl is OK. (Typically var/log)
Then the app is used and creates var/log/prod.log, owned by www-data (who runs the webserver)
Second deployment : deployer tries to setfacl on var/log, and fails. 馃

Does anyone know of a workaround for this? I've just upgraded a Symfony app from 3.4 to 4.4 and I'm now getting this as well.

@BT643 Use the suggestion in the issue description as workaround: Override the deploy task and put deploy:writable before deploy:shared

I was wondering why I didn't experience this issue. But then remembered I added some stuff to my sudoers file. Consider this a second viable work around if everything is running locally and with use of single deploy user.

I run everything as a deploy user, and added this to /etc/sudoers.d/99-deploy.conf :

`
deploy prod-w2 = (root) NOPASSWD: /bin/chown

deploy prod-w2 = (root) NOPASSWD: /bin/chmod

deploy prod-w2 = (root) NOPASSWD: /bin/chgrp

deploy prod-w2 = (root) NOPASSWD: /bin/setfacl
`

Fixed!

@kjellk doesn't this break your whole security and effectively makes your deploy user as powerful as root?

Btw, deployer v7 can detect sudo and will ASK passwords to you.

Was this page helpful?
0 / 5 - 0 ratings