From f3d0995e9078c0b6a99793a90ce6671afc756ee1 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Wed, 18 May 2011 13:46:45 +0200 Subject: CPANization --- .gitignore | 9 ++++++ Build.PL | 21 ++++++++++++ COPYING | 3 ++ Makefile | 21 ------------ README | 57 ++++++++++---------------------- bin/ssh-forcecommand | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ssh-forcecommand | 37 --------------------- t/01-compile-pl.t | 2 +- t/60-regression.t | 2 +- 9 files changed, 143 insertions(+), 100 deletions(-) create mode 100644 .gitignore create mode 100644 Build.PL create mode 100644 COPYING delete mode 100644 Makefile create mode 100755 bin/ssh-forcecommand delete mode 100755 lib/ssh-forcecommand diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..558fa12 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/_build +/Build +/blib +/cover_db/ +/MANIFEST +/MANIFEST.bak +/MANIFEST.SKIP +/MANIFEST.SKIP.bak +/MYMETA.yml diff --git a/Build.PL b/Build.PL new file mode 100644 index 0000000..0409c7c --- /dev/null +++ b/Build.PL @@ -0,0 +1,21 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use Module::Build; + +Module::Build->new( + build_requires => { + 'Test::Command' => 0, + 'Test::Compile' => 0, + 'Test::More' => 0, + }, + dist_name => 'ssh-forcecommand', + dist_version_from => 'bin/ssh-forcecommand', + license => 'unrestricted', + requires => { + 'perl' => '5.10.0', + }, + script_files => 'bin/ssh-forcecommand', + +)->create_build_script(); diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..de727a8 --- /dev/null +++ b/COPYING @@ -0,0 +1,3 @@ +lib/ssh-forcecommand is licensed under the following terms: + + 0. You just DO WHAT THE FUCK YOU WANT TO diff --git a/Makefile b/Makefile deleted file mode 100644 index 783b3cc..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -PREFIX ?= /usr/local - -main_dir = ${DESTDIR}${PREFIX} -lib_dir = ${main_dir}/lib - -all: - @echo "There is nothing to make, you can just make install" - -install: - @echo installing lib/ssh-forcecommand to ${lib_dir} - @mkdir -p ${lib_dir} - @cp lib/ssh-forcecommand ${lib_dir} - @chmod 755 ${lib_dir}/ssh-forcecommand - -test: - @prove - -uninstall: - rm -f ${lib_dir}/ssh-forcecommand - -.PHONY: all install test uninstall diff --git a/README b/README index fb54622..2089c84 100644 --- a/README +++ b/README @@ -1,52 +1,29 @@ ssh-forcecommand - Whitelist remote commands via ssh config +----------------------------------------------------------- -ssh-forcecommand is a trivial script to safely execute remote commands via -ssh. It is especially aimed at automated remote commands (so, ssh keys not -secured via password), where a compromise of the remote system (-> private -key) could also compromise the local system. +* -To prevent this, you can put the forcecommand into the ssh config -(authorized_keys, to be precise), so the remote system can only execute a set -of statically defined commands. This way, compromising the local system is -made much more difficult. +Dependencies +------------ -SETUP ------ + * perl version 5.10 or newer -First, run "make install". You will now have the script in -/usr/local/lib/ssh-forcecommand. -Next, for every publickey you want to restrict to the forcecommand, add the -following line to ~/.ssh/authorized_keys: +Installation +------------ -command="/usr/local/lib/ssh-forcecommand /etc/forcecommand/foo.cfg",no-agent-forwarding,no-port-forwarding,no-pty,no-X11-forwarding ssh-rsa yourfunkykey +$ perl Build.PL +$ perl Build +$ sudo perl Build install -command="..." sets the forcecommand, the other options disable potentially -dangerous stuff like port forwardig (Though that is not meant to be an -exhaustive list). +By default, ssh-forcecommand is installed as /usr/local/bin/ssh-forcecommand. +In most cases, this does not make sense. For example, if you are using the +forcecommand for nagios checks, you might want to do this instead: -As you see, the forcecommand accepts exactly one argument, which is the config -defining the allowed commands. This way, you can restrict different ssh keys -to different sets of commands. For example configs, see the examples -directory. +$ sudo perl Build install --install_path script=/usr/lib/nagios +Testing +------- -USAGE ------ - -Assume you have the following line in your forcecommand config: - -home = tar -C / -cf - home - -Now, on the remote system, run this: - -ssh user@yourhost home - -On your system, this will translate to: - -tar -C / -cf - home - -The forcecommand is 100% static, variables or appending of stuff is not -supported. No part of the original ssh command will be dynamically used in -the resulting command. This makes ssh-forcecommand quite secure. +FIXME diff --git a/bin/ssh-forcecommand b/bin/ssh-forcecommand new file mode 100755 index 0000000..c1b37eb --- /dev/null +++ b/bin/ssh-forcecommand @@ -0,0 +1,91 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +my $conffile = shift or die("Usage: $0 \n"); +my %commands; +my $input = $ENV{'SSH_ORIGINAL_COMMAND'} or die("No command\n");; + +my $VERSION = '0.0'; + +open(my $conf, '<', $conffile) or die("Can't open $conffile: $!\n"); + +while (my $line = <$conf>) { + my ($key, $value) = ($line =~ m{ ^ ([^=]+?) \s* = \s* (.+) $ }x); + if ($key and $value) { + $commands{$key} = $value; + } +} +close($conf) or die("Cannot close $conffile: $!\n"); + +if (exists $commands{$input}) { + exec($commands{$input}); + exit 1; +} + +die("Unknown command\n"); + +__END__ + +=head1 NAME + +ssh-forcecommand - Whitelist remote commands via ssh config + +=head1 SYNOPSIS + +In .ssh/authorized_keys: + + command="/usr/local/lib/ssh-forcecommand /etc/forcecommand/backup",no-agent-forwarding,no-port- + forwarding,no-pty,no-X11-forwarding $key + +=head1 DESCRIPTION + +B is a trivial script to safely execute remote commands via +ssh. It is especially aimed at automated remote commands (so, ssh keys not +secured via password), where a compromise of the remote system (-> private +key) could also compromise the local system. + +To prevent this, you can put the forcecommand into the ssh config +(authorized_keys, to be precise), so the remote system can only execute a set +of statically defined commands. This way, compromising the local system is +made much more difficult. + +=head1 CONFIGURATION + +For every public key you want to restrict to the forcecommand, add a line like +in SYNOPSIS to the F<.ssh/authorized_keys>. + +command="..." sets the forcecommand, the other options disable potentially +dangerous stuff like port forwardig (Though that is not meant to be an +exhaustive list). + +As you see, the forcecommand accepts exactly one argument, which is the config +defining the allowed commands. This way, you can restrict different ssh keys +to different sets of commands. A few example configs are provided with this +script, see the examples directory. + +=head1 USAGE + +Assume you have the following line in your forcecommand config: + + home = tar -C / -cf - home + +Now, on the remote system, run this: + + ssh user@yourhost home + +On your system, this will translate to: + + tar -C / -cf - home + +The forcecommand is 100% static, variables or appending of stuff is not +supported. No part of the original ssh command will be dynamically used in +the resulting command. This makes ssh-forcecommand quite secure. + +=head1 AUTHOR + +Copyright (C) 2011 by Daniel Friesel Ederf@finalrewind.orgE + +=head1 LICENSE + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/lib/ssh-forcecommand b/lib/ssh-forcecommand deleted file mode 100755 index 6352b13..0000000 --- a/lib/ssh-forcecommand +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env perl -# Copyright © 2010,2011 by Daniel Friesel -# License: WTFPL: -# 0. You just DO WHAT THE FUCK YOU WANT TO. -# -# SSH forcecommand to be used for nagios ssh checks etc. -# Example line for ssh authorized_keys file: -# command="/usr/local/lib/ssh-forcecommand /etc/forcecommand/backup.cfg",no-agent-forwarding,no-port-forwarding,no-pty,no-X11-forwarding $key -# -# Configfile format: -# ssh_command = real_command -# Example: -# home = tar -C / -cf - home - -use strict; -use warnings; - -my $conffile = shift or die("Usage: $0 \n"); -my %commands; -my $input = $ENV{'SSH_ORIGINAL_COMMAND'} or die("No command\n");; - -open(my $conf, '<', $conffile) or die("Can't open $conffile: $!\n"); - -while (my $line = <$conf>) { - my ($key, $value) = ($line =~ m{ ^ ([^=]+?) \s* = \s* (.+) $ }x); - if ($key and $value) { - $commands{$key} = $value; - } -} -close($conf) or die("Cannot close $conffile: $!\n"); - -if (exists $commands{$input}) { - exec($commands{$input}); - exit 1; -} - -die("Unknown command\n"); diff --git a/t/01-compile-pl.t b/t/01-compile-pl.t index 661fbfb..7c81c91 100755 --- a/t/01-compile-pl.t +++ b/t/01-compile-pl.t @@ -5,4 +5,4 @@ use 5.010; use Test::More; use Test::Compile; -all_pl_files_ok('lib/ssh-forcecommand'); +all_pl_files_ok('bin/ssh-forcecommand'); diff --git a/t/60-regression.t b/t/60-regression.t index 8faa8c5..828c127 100644 --- a/t/60-regression.t +++ b/t/60-regression.t @@ -13,7 +13,7 @@ sub test_fc { my $out = ($conf{'out'} ? $conf{'out'} . "\n" : q{}); my $err = ($conf{'err'} ? $conf{'err'} . "\n" : q{}); - my $cmd = Test::Command->new(cmd => 'lib/ssh-forcecommand t/config'); + my $cmd = Test::Command->new(cmd => 'bin/ssh-forcecommand t/config'); $cmd->stdout_is_eq($out); $cmd->stderr_is_eq($err); -- cgit v1.2.3