bastion.html

  1. 6.x docs/bastion.html
  2. 4.x docs/bastion.html
  3. 5.x docs/bastion.html

File

docs/bastion.html
View source
<h1>Remote Operations on Drupal Sites via a Bastion Server</h1>
<p>
Wikipedia defines a <a href="http://en.wikipedia.org/wiki/Bastion_host">bastion server</a> as "a special 
purpose computer on a network specifically designed and configured 
to withstand attacks."</a>  For the purposes of this documentation,
though, any server that you can ssh through to reach other servers
will do.  Using standard ssh and drush techniques, it is possible
to make a two-hop remote command look and act as if the destination
machine is on the same network as the source machine.

<h2>Recap of Remote Site Aliases</h2>
<p>
Site aliases can refer to Drupal sites that are running on
remote machines simply including 'remote-host' and 'remote-user'
attributes:
<pre>
$aliases['internal'] = array(
    'remote-host' => 'internal.company.com',
    'remote-user' => 'wwwadmin',
    'uri' => 'http://internal.company.com',
    'root' => '/path/to/remote/drupal/root',
);
</pre>
With this alias defintion, you may use commands such as
`drush @internal status`, 'drush ssh @internal` and 
`drush rsync @internal @dev` to operate remotely on the 
internal machine.  What if you cannot reach the server 
that site is on from your current network?  Enter the bastion server.

<h2>Setting up a Bastion server in .ssh/config</h2>
<p>
If you have access to a server, bastion.company.com, which
you can ssh to from the open internet, and if the bastion
server can in turn reach the internal server, then it
is possible to configure ssh to route all traffic to the
internal server through the bastion.  The .ssh configuratin
file would look something like this:
<p>
In <b>.ssh/config:</b>
<pre>
Host internal.company.com
    ProxyCommand ssh user@bastion.company.com nc %h %p
</pre>
That is all that is necessary; however, if the dev machine
you are configuring is a laptop that might sometimes be
inside the company intranet, you might want to optimize
this setup so that the bastion is not used when the internal
server can be reached directly.  You could do this by
changing the contents of your .ssh/config file when your
network settings change -- or you could use drush.

<h2>Setting up a Bastion server via drush configuration</h2>
<p>
First, make sure that you do not have any configuration
options for the internal machine in your .ssh/config file.
The next step after that is to identify when you are connected
to your company intranet.  I like to determine this by using the
`route` command to find my network gateway address, since
this is always the same on my intranet, and unlikely to be
encountered in other places.
<p>
In <b>drushrc.php:</b>
<pre>
# Figure out if we are inside our company intranet by testing our gateway address against a known value
exec("route -n | grep '^0\.0\.0\.0' | awk '{ print $2; }' 2> /dev/null", $output);
if ($output[0] == '172.30.10.1') {
  drush_set_context('MY_INTRANET', TRUE);
}
</pre>
After this code runs, the 'MY_INTRANET' context will be set if our
gateway IP address matches the expected value, and unset otherwise.
We can make use of this in our alias files.
<p>
In <b>aliases.drushrc.php:</b>
<pre>
if (drush_get_context('MY_INTRANET', FALSE) === FALSE) {
  $aliases['intranet-proxy'] = array(
    'ssh-options' => ' -o "ProxyCommand ssh user@bastion.company.com nc %h %p"',
  );
}
$aliases['internal-server'] = array(
  'parent' => '@intranet-proxy',
  'remote-host' => 'internal.company.com',
  'remote-user' => 'wwwadmin',
);
$aliases['internal'] = array(
  'parent' => '@internal-server',
  'uri' => 'http://internal.company.com',
  'root' => '/path/to/remote/drupal/root',
);
</pre>
The 'parent' term of the internal-server alias record is ignored
if the alias it references ('@intranet-proxy') is not defined;
the result is that 'ssh-options' will only be defined when
outside of the intranet, and the ssh ProxyCommand to the bastion
server will only be included when it is needed.
<p>
With this setup, you will be able to use your site alias
'@internal' to remotely operate on your internal intranet
Drupal site seemlessly, regardless of your location -- a handy
trick indeed.