Jail the control-panel terminal to the customer's home (chroot)
Deploy Ladill Hosting / deploy (push) Successful in 45s
Deploy Ladill Hosting / deploy (push) Successful in 45s
SECURITY: the browser terminal ran an unconfined login shell as the account's system user, so customers could browse the whole host (/var/www, other tenants, /etc). Run it inside a jailkit chroot instead: a vetted, sudo-scoped launcher (/usr/local/sbin/ladill-jailsh) enters a private mount namespace, bind-mounts ONLY that user's home into /home/jail, and chroots as the user. They can no longer see anything outside their own home. Provisioning committed in deployment/ (setup-terminal-jail.sh + ladill-jailsh) so it is reproducible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e86f95ddc7
commit
2a1228b40e
@@ -131,7 +131,10 @@ class RunHostingTerminalWorkerCommand extends Command
|
||||
$launchCommand = $this->buildUserShellBootstrap($account, $relativePath, $cols, $rows);
|
||||
|
||||
if ($this->shouldUseLocalExecution($account->node)) {
|
||||
return new LocalPtyShellSession($this->buildLocalLaunchCommand($account, $launchCommand));
|
||||
// Confine the customer to a jailkit chroot (only their own home is
|
||||
// visible) via the vetted, sudo-scoped launcher. SECURITY: never run
|
||||
// an unjailed login shell here — it exposes the whole host filesystem.
|
||||
return new LocalPtyShellSession($this->buildJailedLaunchCommand($account, $relativePath));
|
||||
}
|
||||
|
||||
$ssh = $provider->connect($account->node);
|
||||
@@ -145,6 +148,27 @@ class RunHostingTerminalWorkerCommand extends Command
|
||||
return new RemoteSshShellSession($ssh, $remoteCommand, $cols, $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local jailed shell: run the customer inside the jailkit chroot
|
||||
* (config('hosting.terminal_jail_launcher')) as their own user. The launcher
|
||||
* derives uid/gid, binds only that user's home into the jail, and chroots —
|
||||
* so the customer can never see the host filesystem (/var/www, other homes,
|
||||
* /etc, secrets). Invoked via sudo -n, scoped in /etc/sudoers.d/ladill-jailsh
|
||||
* because the terminal worker runs as www-data.
|
||||
*/
|
||||
private function buildJailedLaunchCommand(HostingAccount $account, string $relativePath): string
|
||||
{
|
||||
$launcher = (string) config('hosting.terminal_jail_launcher', '/usr/local/sbin/ladill-jailsh');
|
||||
$rel = $relativePath !== '' ? $relativePath : '/public_html';
|
||||
|
||||
return implode(' ', [
|
||||
'sudo', '-n',
|
||||
escapeshellarg($launcher),
|
||||
escapeshellarg($account->username),
|
||||
escapeshellarg($rel),
|
||||
]);
|
||||
}
|
||||
|
||||
private function buildUserShellBootstrap(HostingAccount $account, string $relativePath, int $cols, int $rows): string
|
||||
{
|
||||
$homeDirectory = "/home/{$account->username}";
|
||||
|
||||
Reference in New Issue
Block a user