visudo


If you’re here, thanks for keeping up. It’s been a bit since I updated this, and this is kind of a part two in regards to a side project and the wonderful issues I’ve been having to overcome as a result of big ambitions and little time. If you’re not caught up, check out touch remote dev so you have some context before continuing.


Christmas break didn’t bring many opportunities to sit down and hack on anything, but I did get one day – a day was all that was needed apparently. This day afforded me the ability to sit down and dig into the underlying issue I was experiencing with tenancy/multi-tenant. The problem was pretty straight forward, www-data was not allowed to execute /usr/sbin/nginx configtext. Well, duh! nginx is only supposed to be executed by root and it spawns child processes under the specified user parameter.


Google, you suck


Now I knew one of the fundamental issues I was having when I initially embarked on this journey months ago – it didn’t have to do with ACLs or permissions. It had to do with a basic system property that is in place to ensure no one mischevious does anything vile. So, how is one to fix this problem? Well, what tenancy won’t mention in their documentation (literally, this isn’t mentioned anywhere) is you have to modify src/config/webserver.php to look something like this:


<?php

/*
 * This file is part of the hyn/multi-tenant package.
 *
 * (c) Daniël Klabbers <daniel@klabbers.email>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @see https://tenancy.dev
 * @see https://github.com/hyn/multi-tenant
 */

return [
    /**
     * Redacted some apache stuff...
     */

    /**
     * Nginx webserver support.
     *
     * @see http://nginx.org
     */
    'nginx' => [
        /**
         * Whether the integration with nginx is currently active.
         */
        'enabled' => true,

        /**
         * The php sock to be used.
         */
        'php-sock' => 'unix:/var/run/php/php7.3-fpm.sock',

        /**
         * Define the ports of your nginx service.
         */
        'ports' => [
            /**
             * HTTP, non-SSL port.
             *
             * @default 80
             */
            'http' => 80,
            /**
             * HTTPS, SSL port.
             *
             * @default 443
             */
            'https' => 443
        ],

        /**
         * The generator taking care of hooking into the nginx services and files.
         */
        'generator' => \Hyn\Tenancy\Generators\Webserver\Vhost\NginxGenerator::class,

        /**
         * The view that holds the vhost configuration template.
         */
        'view' => 'tenancy.generators::webserver.nginx.vhost',

        /**
         * Specify the disk you configured in the filesystems.php file where to store
         * the tenant vhost configuration files.
         *
         * @info If not set, will revert to the default filesystem.
         */
        'disk' => null,

        'paths' => [

            /**
             * Location where vhost configuration files can be found.
             */
            'vhost-files' => [
                '/ABSOLUTE/PATH/TO/YOUR/PROJECT/src/app/tenancy/webserver/nginx'
            ],

            /**
             * Actions to run to work with the Nginx service.
             */
            'actions' => [
                /**
                 * Action that asserts nginx is installed.
                 */
                'exists' => '/etc/init.d/nginx',
                /**
                 * Action to run to test the nginx configuration.
                 *
                 * @info set to a boolean to force the response of the test command.
                 *  true succeeds, false fails
                 */
                'test-config' => 'sudo /etc/init.d/nginx configtest',
                /**
                 * Action to run to reload the nginx service.
                 *
                 * @info set to null to disable reloading.
                 */
                'reload' => 'sudo /etc/init.d/nginx reload'
            ]
        ]
    ]
];


There are a couple things here that tenancy doesn’t mention in their docs, at least not where I could find. The first is the fact that 'enabled' isn’t controlled by an environment variable and is set to false to begin with. Toggle that to true, if you’re using nginx. If you’re using apache, you’re SOL, I can’t help you. Next, the important lines are the ones regarding 'test-config' and 'reload'. These are commands that tenancy will call, when a new user attempts to register on your platform, and if www-data cannot run those commands, tenancy fails in all kinds of weird and frustrating ways. We’re not done yet, though. Just because you slap sudo on the front of those commands doesn’t mean shit yet. www-data needs to be added to /etc/sudoers if this is to work.


$ sudo visudo

#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

#www-data ALL=(ALL:ALL) NOPASSWD: /etc/init.d/nginx configtest, /usr/sbin/service nginx configtest, /usr/sbin/service nginx reload
www-data ALL=(ALL:ALL) NOPASSWD: ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d


Now, you can see there are a couple additions in there over your default configuration. I will start by saying this, regarding those modifications: the modification I am using is insecure and needs revision. Given www-data is the webserver user, which PHP is running as, this user should be heavily restricted, especially given the context we’re working in right here. Should a user figure out how to inject a command, and it be executed by www-data, all they’d have to do is add sudo and the server would be totally pwned.


Either way, I was receiving some other dumb error because sudo kept spewing it’s “great power comes great responsibility” message, and I’ve forgotten how to shut that stupid thing up. As soon as I completed this step, registration started working. With due time, I’ll get back to that, but for now. It finally fucking works.


Finally!


Then I turned around and broke the shit out of it by trying to convert the entire auth flow to vue.


You broke it.


Oh well, it’s been a learning experience. I’m going to scrap everything again and this time, as I follow the chain of random tutorials and guides, and docs, I’m going to document the hell out of my workflow and dump it all here. Maybe that’ll be my New Year’s Day task – give people an actively correct guide to getting a base tenancy system set up and working. Till next time.