Securing the Magento 2 CLI on MageStack

A customer raised a good question about using the Magento 2 CLI binary (bin/magento) on MageStack and asked how it works with domain group isolation.

On Magento 1, we encourage a strong security practice for all CLI/cron activity by using wrappers for the commands, to constrain the command being run within the domain group - and to ensure a consistent environment between web and acc nodes.

Background

On MageStack, the server consists of a series of mini environments (domain groups) - these are isolated from each other for security purposes.

But for ease of management, in the access server, you are able to access all domain groups. But, when executing commands in the context of a domain group - you should do it from within the domain group itself, not using the global php commands.

This is why if you look at how we recommend running Magento cron jobs - that it locks the process into the domain group - so that the configuration mirrors the web server exactly (and leaves no room for error).

By running a command outside of the domain group, you introduce a security risk and a change in platform (as the settings won't be consistent with the web server).

An example

On Magento 2 stacks, there is support for multi-php, so that each domain group has its own PHP version. So there's a basic example we can use to demonstrate the differences between running a command in the global access server, and the domain group itself.

On the access server, a simple php -v would show,

php -v
PHP 5.4.45 MageStack (cli) (built: Feb 22 2016 19:20:20)

But in a Magento 2 domain group,

php -v
PHP 5.6.18 MageStack (cli) (built: Feb 22 2016 19:26:49)

This basic example shows the difference between the two environments. So whilst it is possible to run commands in the global context of the access server, its always recommended to use the domain-group itself to execute site-specific commands.

Simplifying dropping into a domain-group

Dropping into the context of a domain group isn't a difficult process, its really simple,

Eg. To drop into the example domain group,

fakechroot /usr/sbin/chroot /microcloud/domains/example /bin/bash

We can make this even simpler/shorter by making a quick bash function to add to our .bash_profile

function example()
{
  local CMD="fakechroot /usr/sbin/chroot /microcloud/domains/example /bin/bash"
  if [ $# -gt 0 ]; then
    echo "$@" | $CMD
  else
    $CMD
  fi
}

Then you could drop into the domain-group environment as easily as,

[www-data@acc1 .microcloud ~]
[~]$ example
bash-4.1$

Or execute a command in the context of the domain group like so,

[www-data@acc1 .microcloud ~]
[~]$ example ls
bin  dev  domains  etc  home  lib  lib64  logs  proc  sbin  tmp  usr  var  version

Running M2 CLI via domain group drop-in function

With the new function in place, it is as simple as running the command - just prefixed with the function name.

Eg. To reindex,

example php /domains/example.com/http/bin/magento indexer:reindex
Customer Grid index has been rebuilt successfully in 00:00:00
Category Products index has been rebuilt successfully in 00:00:00
Product Categories index has been rebuilt successfully in 00:00:00
Product Price index has been rebuilt successfully in 00:00:00
Product EAV index has been rebuilt successfully in 00:00:00
Stock index has been rebuilt successfully in 00:00:00
Catalog Rule Product index has been rebuilt successfully in 00:00:00
Catalog Product Rule index has been rebuilt successfully in 00:00:00
Catalog Search index has been rebuilt successfully in 00:00:00

Making the function portable

If you've got a lot of domain groups, you can make it much more portable by making the function use variables to define the environment and just pass the domain group name in as an argument.

function dg()
{
  local DG="$1"
  local CMD="fakechroot /usr/sbin/chroot /microcloud/domains/$DG /bin/bash"
  shift
  if [ $# -gt 0 ]; then
    echo "$@" | $CMD
  else
    $CMD
  fi
}

Make it a permanent change by opening /home/www-data/.bash_profile and appending the function to the end of the file. Then use the new command like so,

dg [domain-group] [command]

Eg.

dg example php -v