[xwiki-users] totally groovy! (using groovy SSH script to securely launch unix processes out of Xwiki)
This might be useful for those wanting to do server administration functions (start/stop tomcat, reboot, stats, etc) out of an Xwiki doc (make sure your doc is password protected or more, if it allows people to reboot your server!; Anything needing root or tomcat user would use /etc/sudoers to grant specfic permissions to specific programs needed by user tomcat-ssh-slave): Input:
==== Use Groovy Script run server processes and display result ====
See [[SshHelperClass?viewer=code]], [[ http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/]]
==== Call parseGroovyFromPage("Groovy.SshHelperClass") ====
{{velocity}} #set( $sshHelper = $xwiki.parseGroovyFromPage("Groovy.SshHelperClass") ) $sshHelper.openSession("127.0.0.1", "22", "tomcat-ssh-slave",
"/usr/share/tomcat6/.ssh/id_dsa", "")
{{/velocity}}
==== Output from 'uname -a'====
##{{velocity}}$sshHelper.runCommand("uname -a"){{/velocity}}##
==== Output from 'free' ====
##{{velocity}}$sshHelper.runCommand("free"){{/velocity}}##
==== Output from 'ps -l U tomcat-ssh-slave U tomcat U apache' ====
##{{velocity}}$sshHelper.runCommand("ps -l h U tomcat-ssh-slave U tomcat U
apache"){{/velocity}}##
==== Output from 'df -H' ====
##{{velocity}}$sshHelper.runCommand("df -H"){{/velocity}}##
==== Output from 'top -b -n 1' ====
##{{velocity}}$sshHelper.runCommand("top -b -n 1"){{/velocity}}##
==== Close the connection and exit tomcat-ssh-slave shell ====
warning: if something breaks above, hopefully this will get called otherwise
we
get a left-over sub-process tomcat-ssh-slave ##{{velocity}}$sshHelper.close(){{/velocity}}## Output:
Use Groovy Script run server processes and display result
See SshHelperClass ,
http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/
*Call parseGroovyFromPage("Groovy.SshHelperClass")*
*Output from 'uname -a'*
Linux ce 2.6.27.29-170.2.78.fc10.x86_64 #1 SMP Fri Jul 31 04:16:20 EDT
2009 x86_64 x86_64 x86_64 GNU/Linux
*Output from 'free'*
total used free shared buffers cached
Mem: 1928992 1778932 150060 0 47272 532128
-/+ buffers/cache: 1199532 729460
Swap: 3866616 78776 3787840
*Output from 'ps -l U tomcat-ssh-slave U tomcat U apache'*
5 S 92 18792 18788 0 80 0 - 22060 select ? 0:00 sshd:
tomcat-ssh-slave@notty
0 R 92 18879 18792 1 80 0 - 22453 - ? 0:00 ps -l h U tomcatssh-slave U
tomcat U apache
0 S 91 31695 1 0 80 0 - 463955 futex_ ? 7:47 /usr/java/default/bin/java
-server -Xms160m -Xmx1024m -XX:PermSize=160m -XX:MaxPermSize=320m ...
*Output from 'df -H'*
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00 242G 26G 204G 12% /
/dev/sda1 200M 15M 175M 8% /boot
tmpfs 988M 353k 988M 1% /dev/shm
*Output from 'top -b -n 1'*
top - 11:17:20 up 2 days, 16:21, 3 users, load average: 0.78, 0.68, 0.56
Tasks: 150 total, 2 running, 148 sleeping, 0 stopped, 0 zombie
Cpu(s): 7.7%us, 1.7%sy, 0.0%ni, 90.2%id, 0.3%wa, 0.1%hi, 0.1%si, 0.0%st
Mem: 1928992k total, 1794420k used, 134572k free, 47304k buffers
Swap: 3866616k total, 78776k used, 3787840k free, 532356k cached
...
Special Installation Instructions To make this run (Fedora Linux): 1. sudo yum install trilead-ssh2 trilead-ssh2-javadoc 2. sudo ln -s /usr/share/java/trilead-ssh2-213.jar /usr/share/java/tomcat6/trilead-ssh2.jar 3. Make sure "tomcat" user exists in /etc/passwd, and create an additional uid=92 gid=92 account "tomcat-ssh-slave": • tomcat:x:91:91:Apache Tomcat:/usr/share/tomcat6:/bin/sh ° "tomcat" user created as "disabled" by installing tomcat6-6.0.18-6.2.fc10 • tomcat-ssh-slave:x:92:92:User for SSH Subprocesses From Tomcat:/home/tomcat-ssh-slave:/bin/bash ° create this using fedora admin utility 'system-config-users' or by hand-editing /etc/passwd... 4. sudo passwd -u tomcat • unlock tomcat account temporarily 5. sudo passwd tomcat • set password for tomcat account 6. Login to "tomcat" account using SSH from current account terminal. 7. ssh-keygen -t dsa • Leave "empty for no passphrase" for decrypting the DSA-key produced by ssh-keygen, although it can be specified as last parameter for sshHelper.openSession("localhost", "22", "tomcat-ssh-slave", "/usr/share/tomcat6/.ssh/id_dsa", ""). 8. From the "tomcat" account, run "ssh [email protected]" • answer Yes: "Are you sure you want to continue connecting (yes/no)? yes" • enter password for tomcat-ssh-slave set above via system-config-users. • exit the connection. • The purpose of this step is to test the account, and init /usr/share/tomcat6/.ssh/known_hosts 9. sudo cp /usr/share/tomcat6/.ssh/id_dsa.pub tomcat-ssh-slave/.ssh/authorized_keys 10. From the "tomcat" account, do "ssh [email protected]" again • verify that login happens w/o password prompt, which is what happens when authorized_keys is set to the public key of the account accessing SSH. • exit from tomcat-ssh-slave account. It's now ready to run out of tomcat. 11. passwd -l tomcat • lock the tomcat account from further logins, now that it's been setup and the dsa public/private keys have been generated. 1. *TODO:* remove password from user tomcat-ssh-slave ('!!' in passwd field of /etc/shadow) password not needed for login 2. *TODO:* alternately, is there a local customization to ensure certs only used for login to the account? I know this can be done globally in /etc/ssh/sshd_config: "PasswordAuthentication no" and "PermitEmptyPasswords no" 3. *TODO:* for user tomcat-ssh-slave, integrate "limited command processing" by replacing /bin/sh as login shell with /usr/local/bin/tomcat-ssh-shell (or equiv): #!/bin/sh -noprofile ############################################################################### # # File: sshslave-shell # RCS: $Header: $ # Description: Shell to allow execution of remote commands from a tomcat server. # For security purposes, this "login" is limited in commands it can # perform, and runs as a separate user from the tomcat server, separating # the ability to directly modify tomcat state from the functionality provided # by user tomcat-ssh-slave. This shell is run as the "login shell" (via # /etc/passwd) for account tomcat-ssh-slave, which is accessed via SSH. # The account is preferably a nonprivileged user account with pid>500, Home # directory /home/tomcat-ssh-slave must exist, with correct permisssions. # /home/tomcat-ssh-slave contains scripts referred to via fully qualified # filenames in this script. The directory would also store the accounts' # .ssh settings, keys, etc. Secure, password-less access to the tomcat-ssh-slave # account can be achieved by having tomcat's SSH public identity /usr/share/tomcat6/.ssh/id_dsa.pub # installed as /home/tomcat-ssh-slave/.ssh/authorized_keys (and keeping id_dsa secret) # This would prevent use of tomcat-ssh-slave "account" from being used by anything # other than preauthorized accounts. # # Here's some example commands: # # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot # Author: Niels P. Mayer # Created: Monday 8/10/2009 # Modified: # Language: Shell-script # Package: N/A # Status: Production # # (C) Copyright 2009, Niels Mayer, all rights reserved. # ############################################################################### # make sure nothing funny goes on PATH="/bin:/usr/bin" # make sure they rsh or ssh in with a single command if [ -z "$1" ] || [ "$1" != "-c" ] then echo You must use ssh -c to access this account exit 1 else shift SSHSLAVE_COMMAND="$@" fi # only let them run specific commands, eg. # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot case ${SSHSLAVE_COMMAND} in cleanlog \ getlog \ getdbglvl \ tomcat-restart \ apache-restart \ tomcat-start \ apache-start \ top \ ps \ df \ free \ reboot \ ) #single argument commands -- exact match to SSHSLAVE_COMMAND exec "/home/tomcat-ssh-slave/${SSHSLAVE_COMMAND}" ;; setdbglvl* \ #e.g., setdbglvl 'INFO' ... multiple argument command. Beware command injection. ) exec `echo "/home/tomcat-ssh-slave/${SSHSLAVE_COMMAND}" | cut -f1 -d" "` `echo "${SSHSLAVE_COMMAND}" | cut -f2- -d" "` ;; * ) exec echo You are not authorized to do that. ;; esac Niels http://nielsmayer.com
I forgot to include the Groovy script itself that does all the heavy-lifting in my previous mail - see Groovy.SshHelperClass below. Also, there's a much better way of calling this groovy "sshHelper" class out of a single groovy invocation in a 2.0 document. Groovy directly outputs wikitext, the renderer takes care of the rest. ==== Use Groovy Script run server processes and display result ==== See [[SshHelperClass?viewer=code]], [[ http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/]] {{groovy}} println "==== Call parseGroovyFromPage('Groovy.SshHelperClass') ====" def sshHelper = xwiki.parseGroovyFromPage("Groovy.SshHelperClass") sshHelper.openSession("127.0.0.1", "22", "tomcat-ssh-slave", "/usr/share/tomcat6/.ssh/id_dsa", "") println "==== Output from 'uname -a' ====" println "##" + sshHelper.runCommand("uname -a") + "##" println "==== Output from 'free' ====" println "##" + sshHelper.runCommand("free") + "##" println "==== Output from 'ps -l U tomcat-ssh-slave U tomcat U apache' ====" println "##" + sshHelper.runCommand("ps -l h U tomcat-ssh-slave U tomcat U apache") + "##" println "==== Output from 'df -H' ====" println "##" + sshHelper.runCommand("df -H") + "##" println "==== Output from 'top -b -n 1' ====" println "##" + sshHelper.runCommand("top -b -n 1") + "##" println "==== Close the connection and exit tomcat-ssh-slave shell ====" sshHelper.close() {{/groovy}} However, the Groovy.SshHelperClass script must be saved as a 1.0 document in order to call it at the top level via: "xwiki.parseGroovyFromPage("Groovy.SshHelperClass")". Is there a 2.0 syntax that works with parseGroovyFromPage()? Groovy.SshHelperClass in xwiki/1.0 format (with special comment hacks per http://platform.xwiki.org/xwiki/bin/view/DevGuide/GroovyClassHelloWorldTutor...): ................................... /* Groovy Class for [SshHelperTest], orig [ http://blog.asyd.net/wp-content/uploads/2008/12/sshhelper.groovy] #* */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import com.trilead.ssh2.Connection; import com.trilead.ssh2.Session; import com.trilead.ssh2.StreamGobbler; /** * * @author asyd, modified by NielsMayer */ class SshHelper { def connection def session void openSession(hostname, port, username, identityfile, password) { def identityIOFile = new File(identityfile) this.connection = new Connection(hostname, Integer.parseInt(port)) this.connection.connect() if (!connection.authenticateWithPublicKey(username, identityIOFile, password)) { println "Authentication failed!" } } String runCommand(command) { this.session = connection.openSession() this.session.execCommand(command) def stdoutStream = new StreamGobbler(this.session.getStdout()) def stdoutReader = new BufferedReader(new InputStreamReader(stdoutStream)) def lineout = "" def stdoutOutput = "" while ((lineout = stdoutReader.readLine()) != null) { stdoutOutput += (lineout + "\n") } this.session.close() this.session = null return stdoutOutput } void close() { if (this.session != null) { this.session.close() } this.connection.close() } /* *# */ ................................... -- Niels http://nielsmayer.com
Of course, one can forgo the 1.0 document and calling parseGroovyFromPage(), and just put the class directly inside one's 2.0 groovy script and call new SshHelper(). Of course, this still doesn't solve the problem of wanting to reuse groovy classes across multiple documents, while wanting to use Xwiki documents for the groovy code for easier development. Thus I still seek a 2.0-compatible version of parseGroovyFromPage('Groovy.SshHelperClass')... Here's the all-in-one version of the previous SSH/groovy/run-a-unix-process-out-of-a-webpage example ==== Standalone version of SshHelperTest ==== See also [[HowtoSetupUserTomcatSshSlave]] [[SshHelperTest]] [[ http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/]] {{groovy}} /* orig [http://blog.asyd.net/wp-content/uploads/2008/12/sshhelper.groovy] #* */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import com.trilead.ssh2.Connection; import com.trilead.ssh2.Session; import com.trilead.ssh2.StreamGobbler; /** * * @author asyd, modified by NielsMayer */ class SshHelper { def connection def session void openSession(hostname, port, username, identityfile, password) { def identityIOFile = new File(identityfile) this.connection = new Connection(hostname, Integer.parseInt(port)) this.connection.connect() if (!connection.authenticateWithPublicKey(username, identityIOFile, password)) { println "Authentication failed!" } } String runCommand(command) { this.session = connection.openSession() this.session.execCommand(command) def stdoutStream = new StreamGobbler(this.session.getStdout()) def stdoutReader = new BufferedReader(new InputStreamReader(stdoutStream)) def lineout = "" def stdoutOutput = "" while ((lineout = stdoutReader.readLine()) != null) { stdoutOutput += (lineout + "\n") } this.session.close() this.session = null return stdoutOutput } void close() { if (this.session != null) { this.session.close() } this.connection.close() } } /* * Using class above, open an SSH connection to tomcat-ssh-slave * using user tomcat6's private key created via 'ssh-keygen -t dsa' * while logged in as ~tomcat6 */ def sshHelper = new SshHelper(); sshHelper.openSession("127.0.0.1", "22", "tomcat-ssh-slave", "/usr/share/tomcat6/.ssh/id_dsa", "") println "==== Output from 'uname -a' ====" println "##" + sshHelper.runCommand("uname -a") + "##" println "==== Output from 'free' ====" println "##" + sshHelper.runCommand("free") + "##" println "==== Output from 'ps -l U tomcat-ssh-slave U tomcat U apache' ====" println "##" + sshHelper.runCommand("ps -l h U tomcat-ssh-slave U tomcat U apache") + "##" println "==== Output from 'df -H' ====" println "##" + sshHelper.runCommand("df -H") + "##" println "==== Output from 'top -b -n 1' ====" println "##" + sshHelper.runCommand("top -b -n 1") + "##" println "==== Close the connection and exit tomcat-ssh-slave shell ====" sshHelper.close() /* *# */ {{/groovy}} -- Niels http://nielsmayer.com
Nice, I've been trying to do something similar to just relaunch the JVM itself from the Wiki itself. I could not however find a solution to the JVM killing the /etc/init.d/tomcat restart script just after "stop" when the JVM itself is killed.. This made the "start" not happen.. Running it from another XWiki is another solution which though requires more credentials settings.. Ludovic Niels Mayer a écrit :
This might be useful for those wanting to do server administration functions (start/stop tomcat, reboot, stats, etc) out of an Xwiki doc (make sure your doc is password protected or more, if it allows people to reboot your server!; Anything needing root or tomcat user would use /etc/sudoers to grant specfic permissions to specific programs needed by user tomcat-ssh-slave):
Input:
==== Use Groovy Script run server processes and display result ====
See [[SshHelperClass?viewer=code]], [[ http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/]]
==== Call parseGroovyFromPage("Groovy.SshHelperClass") ====
{{velocity}}
#set( $sshHelper = $xwiki.parseGroovyFromPage("Groovy.SshHelperClass") )
$sshHelper.openSession("127.0.0.1", "22", "tomcat-ssh-slave",
"/usr/share/tomcat6/.ssh/id_dsa", "")
{{/velocity}}
==== Output from 'uname -a'====
##{{velocity}}$sshHelper.runCommand("uname -a"){{/velocity}}##
==== Output from 'free' ====
##{{velocity}}$sshHelper.runCommand("free"){{/velocity}}##
==== Output from 'ps -l U tomcat-ssh-slave U tomcat U apache' ====
##{{velocity}}$sshHelper.runCommand("ps -l h U tomcat-ssh-slave U tomcat U
apache"){{/velocity}}##
==== Output from 'df -H' ====
##{{velocity}}$sshHelper.runCommand("df -H"){{/velocity}}##
==== Output from 'top -b -n 1' ====
##{{velocity}}$sshHelper.runCommand("top -b -n 1"){{/velocity}}##
==== Close the connection and exit tomcat-ssh-slave shell ====
warning: if something breaks above, hopefully this will get called otherwise
we
get a left-over sub-process tomcat-ssh-slave
##{{velocity}}$sshHelper.close(){{/velocity}}##
Output:
Use Groovy Script run server processes and display result
See SshHelperClass ,
http://blog.asyd.net/2008/12/xwiki-cest-decidemment-magique/
*Call parseGroovyFromPage("Groovy.SshHelperClass")*
*Output from 'uname -a'*
Linux ce 2.6.27.29-170.2.78.fc10.x86_64 #1 SMP Fri Jul 31 04:16:20 EDT
2009 x86_64 x86_64 x86_64 GNU/Linux
*Output from 'free'*
total used free shared buffers cached
Mem: 1928992 1778932 150060 0 47272 532128
-/+ buffers/cache: 1199532 729460
Swap: 3866616 78776 3787840
*Output from 'ps -l U tomcat-ssh-slave U tomcat U apache'*
5 S 92 18792 18788 0 80 0 - 22060 select ? 0:00 sshd:
tomcat-ssh-slave@notty
0 R 92 18879 18792 1 80 0 - 22453 - ? 0:00 ps -l h U tomcatssh-slave U
tomcat U apache
0 S 91 31695 1 0 80 0 - 463955 futex_ ? 7:47 /usr/java/default/bin/java
-server -Xms160m -Xmx1024m -XX:PermSize=160m -XX:MaxPermSize=320m ...
*Output from 'df -H'*
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00 242G 26G 204G 12% /
/dev/sda1 200M 15M 175M 8% /boot
tmpfs 988M 353k 988M 1% /dev/shm
*Output from 'top -b -n 1'*
top - 11:17:20 up 2 days, 16:21, 3 users, load average: 0.78, 0.68, 0.56
Tasks: 150 total, 2 running, 148 sleeping, 0 stopped, 0 zombie
Cpu(s): 7.7%us, 1.7%sy, 0.0%ni, 90.2%id, 0.3%wa, 0.1%hi, 0.1%si, 0.0%st
Mem: 1928992k total, 1794420k used, 134572k free, 47304k buffers
Swap: 3866616k total, 78776k used, 3787840k free, 532356k cached
...
Special Installation Instructions
To make this run (Fedora Linux): 1. sudo yum install trilead-ssh2 trilead-ssh2-javadoc 2. sudo ln -s /usr/share/java/trilead-ssh2-213.jar /usr/share/java/tomcat6/trilead-ssh2.jar 3. Make sure "tomcat" user exists in /etc/passwd, and create an additional uid=92 gid=92 account "tomcat-ssh-slave": • tomcat:x:91:91:Apache Tomcat:/usr/share/tomcat6:/bin/sh ° "tomcat" user created as "disabled" by installing tomcat6-6.0.18-6.2.fc10 • tomcat-ssh-slave:x:92:92:User for SSH Subprocesses From Tomcat:/home/tomcat-ssh-slave:/bin/bash ° create this using fedora admin utility 'system-config-users' or by hand-editing /etc/passwd... 4. sudo passwd -u tomcat • unlock tomcat account temporarily 5. sudo passwd tomcat • set password for tomcat account 6. Login to "tomcat" account using SSH from current account terminal. 7. ssh-keygen -t dsa • Leave "empty for no passphrase" for decrypting the DSA-key produced by ssh-keygen, although it can be specified as last parameter for sshHelper.openSession("localhost", "22", "tomcat-ssh-slave", "/usr/share/tomcat6/.ssh/id_dsa", ""). 8. From the "tomcat" account, run "ssh [email protected]" • answer Yes: "Are you sure you want to continue connecting (yes/no)? yes" • enter password for tomcat-ssh-slave set above via system-config-users. • exit the connection. • The purpose of this step is to test the account, and init /usr/share/tomcat6/.ssh/known_hosts 9. sudo cp /usr/share/tomcat6/.ssh/id_dsa.pub tomcat-ssh-slave/.ssh/authorized_keys 10. From the "tomcat" account, do "ssh [email protected]" again • verify that login happens w/o password prompt, which is what happens when authorized_keys is set to the public key of the account accessing SSH. • exit from tomcat-ssh-slave account. It's now ready to run out of tomcat. 11. passwd -l tomcat • lock the tomcat account from further logins, now that it's been setup and the dsa public/private keys have been generated.
1. *TODO:* remove password from user tomcat-ssh-slave ('!!' in passwd field of /etc/shadow) password not needed for login 2. *TODO:* alternately, is there a local customization to ensure certs only used for login to the account? I know this can be done globally in /etc/ssh/sshd_config: "PasswordAuthentication no" and "PermitEmptyPasswords no" 3. *TODO:* for user tomcat-ssh-slave, integrate "limited command processing" by replacing /bin/sh as login shell with /usr/local/bin/tomcat-ssh-shell (or equiv):
#!/bin/sh -noprofile ############################################################################### # # File: sshslave-shell # RCS: $Header: $ # Description: Shell to allow execution of remote commands from a tomcat server. # For security purposes, this "login" is limited in commands it can # perform, and runs as a separate user from the tomcat server, separating # the ability to directly modify tomcat state from the functionality provided # by user tomcat-ssh-slave. This shell is run as the "login shell" (via # /etc/passwd) for account tomcat-ssh-slave, which is accessed via SSH. # The account is preferably a nonprivileged user account with pid>500, Home # directory /home/tomcat-ssh-slave must exist, with correct permisssions. # /home/tomcat-ssh-slave contains scripts referred to via fully qualified # filenames in this script. The directory would also store the accounts' # .ssh settings, keys, etc. Secure, password-less access to the tomcat-ssh-slave # account can be achieved by having tomcat's SSH public identity /usr/share/tomcat6/.ssh/id_dsa.pub # installed as /home/tomcat-ssh-slave/.ssh/authorized_keys (and keeping id_dsa secret) # This would prevent use of tomcat-ssh-slave "account" from being used by anything # other than preauthorized accounts. # # Here's some example commands: # # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot # Author: Niels P. Mayer # Created: Monday 8/10/2009 # Modified: # Language: Shell-script # Package: N/A # Status: Production # # (C) Copyright 2009, Niels Mayer, all rights reserved. # ###############################################################################
# make sure nothing funny goes on PATH="/bin:/usr/bin"
# make sure they rsh or ssh in with a single command if [ -z "$1" ] || [ "$1" != "-c" ] then echo You must use ssh -c to access this account exit 1 else shift SSHSLAVE_COMMAND="$@" fi
# only let them run specific commands, eg. # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot
case ${SSHSLAVE_COMMAND} in cleanlog \ getlog \ getdbglvl \ tomcat-restart \ apache-restart \ tomcat-start \ apache-start \ top \ ps \ df \ free \ reboot \ ) #single argument commands -- exact match to SSHSLAVE_COMMAND exec "/home/tomcat-ssh-slave/${SSHSLAVE_COMMAND}" ;;
setdbglvl* \ #e.g., setdbglvl 'INFO' ... multiple argument command. Beware command injection. ) exec `echo "/home/tomcat-ssh-slave/${SSHSLAVE_COMMAND}" | cut -f1 -d" "` `echo "${SSHSLAVE_COMMAND}" | cut -f2- -d" "` ;; * ) exec echo You are not authorized to do that. ;; esac
Niels http://nielsmayer.com _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Ludovic Dubost Blog: http://blog.ludovic.org/ XWiki: http://www.xwiki.com Skype: ldubost GTalk: ldubost
(answering out of order) On Wed, Aug 12, 2009 at 12:28 AM, Ludovic Dubost wrote:
I've been trying to do something similar to just relaunch the JVM itself from the Wiki itself.
I could not however find a solution to the JVM killing
the /etc/init.d/tomcat restart script just after "stop" when the JVM itself is killed..
This made the "start" not happen.. I believe a restart from a separate shell like the ssh-slave-shell from my example should not have this problem if you use the "restart" command that actually consists of two sequential subcommands: stop and start. That is the whole point of the "restart" command -- that the "start" is going to happen after the "stop" independent of whether the invoking process that invoked the command is still around. Running it from another XWiki is another solution which though requires more credentials settings.. The credentials settings are trivial with the ssh-slave-shell approach. The technique works just as well with remote machines as it does for localhost. You could, for example, have a single administrative host/wiki dedicated to running processes via the ssh-slave-shell. In order to access the SSH-server, each host that wanted to use the ssh-slave-shell needs its specific ~tomcat6/.ssh/id_dsa.pub installed into the ssh-host's /home/tomcat-ssh-slave/.ssh/authorized_keys . I'm sure there's an old version of this "idea" helping run things quietly behind the scenes at places like java.net, openoffice.org netbeans.org and ipssources.com :-). Useful for little things like adding x509 certificates to servers, or setting up secure network tunnels via SSH without requiring a system login account. Nice, Thanks! It's a very powerful bit of code. One of the things it's been making me think about, is the use of this feature vs. JSR-223 languages in computing custom web pages. Lets say that I setup one SSH connections per machine that I want to subdivide the task of rendering a bunch of user's "portal" pages, each containing tools and information that they've chosen to have presented on each login. Places like Yahoo and Google have spent considerable effort in decomposing the computations needed for each "portlet" to be farmed out to a separate processor. They employ a massive amount of parallelism in order to render numerous custom and dynamic pages with adequate performance: http://research.yahoo.com/files/pnuts.pdf . Of course with an adequate "cloud" backing up a java implementation, the same could be considered true for launching a groovy-based set of "portlets" that each render as their own separate thread, and then dynamically come back and -- through AJAX -- update the part of the web page that just got farmed off to a separate processor which finally completed it's computation/thread. Is the overhead of the aforementioned way of employing parallelism in a high-volume web-app high enough that a solution where my much lighter-weight groovy-based "portlets" would use this passwordless, pub/priv SSH key exchange method of invoking computation on a remote machine? If there was a way of persisting the actual SSH connection across the web-session, then the overhead of authentication and connection occurs only once, after a user logs in to the "portal." Thereafter, one can simply invoke sshHelper.runCommand("compute-portal-info-as-wikitext") which would return it's results as wikitext to be rendered along with the rest of the current document. At application close or logout, the sshHelper.close() gets called and the remote "restricted shell" dies. Is this a bad idea, and if so, why? ....................... As for the restricted shell, on which the security of such a setup depends I had some errors in the previous script (i see some syntax there from it's other former life controlling a cable/satellite set-top-box running Linux :-) ). now it's working, so if you give it parameters or a command it doesn't expect, it gives an error. E.g. println "==== Output from '/bin/rm -rf /' ====" println "##" + sshHelper.runCommand("/bin/rm -rf /") + "##" Renders as: *Output from '/bin/rm -rf /'* You are not authorized to do that. A recognized command: println "==== Output from 'top' ====" println "##" + sshHelper.runCommand("top") + "##" Always ends up running a shell script "wrapper" associated with the restricted command, which ensures no command-injection is possible. In the case of "top" the wrapper script ends up calling "/usr/bin/top -b -n 1" and outputting the result. To get this working on FireFox (see instructions in prev mails for rest of setup) (1) Add a user to /etc/passwd that looks like this: tomcat-ssh-slave:x:592:592:User for SSH Subprocesses From Tomcat:/home/tomcat-ssh-slave:/home/tomcat-ssh-slave/bin/ssh-slave-shell (2) add a group to /etc/group that looks like this: tomcat-ssh-slave:x:592: (3) setup /home/tomcat-ssh-slave/.ssh as mentioned previously (4) add /home/tomcat-ssh-slave/bin, populate with shell scripts you call from: (5) /home/tomcat-ssh-slave/bin/ssh-slave-shell is an executable script implementing the restricted shell used by tomcat-ssh-slave: #!/bin/sh -noprofile ############################################################################### # # File: sshslave-shell # RCS: $Header: $ # Description: Shell to allow execution of remote commands from a tomcat server. # For security purposes, this "login" is limited in commands it can # perform, and runs as a separate user from the tomcat server, separating # the ability to directly modify tomcat state from the functionality provided # by user tomcat-ssh-slave. This shell is run as the "login shell" (via # /etc/passwd) for account tomcat-ssh-slave, which is accessed via SSH. # The account is preferably a nonprivileged user account with pid>500, Home # directory /home/tomcat-ssh-slave must exist, with correct permisssions. # /home/tomcat-ssh-slave contains scripts referred to via fully qualified # filenames in this script. The directory would also store the accounts' # .ssh settings, keys, etc. Secure, password-less access to the tomcat-ssh-slave # account can be achieved by having tomcat's SSH public identity /usr/share/tomcat6/.ssh/id_dsa.pub # installed as /home/tomcat-ssh-slave/.ssh/authorized_keys (and keeping id_dsa secret) # This would prevent use of tomcat-ssh-slave "account" from being used by anything # other than preauthorized accounts. # # Here's some example commands: # # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot # Author: Niels P. Mayer # Created: Monday 8/10/2009 # Modified: # Language: Shell-script # Package: N/A # Status: Production # # (C) Copyright 2009, Niels Mayer, all rights reserved. # ############################################################################### # make sure nothing funny goes on PATH="/bin:/usr/bin" # make sure they rsh or ssh in with a single command if [ -z "$1" ] || [ "$1" != "-c" ] then echo You must use ssh -c to access this account exit 1 else shift SSHSLAVE_COMMAND="$@" fi # only let them run specific commands, eg. # ssh -x [email protected] cleanlog # ssh -x [email protected] getlog # ssh -x [email protected] setdbglvl 'INFO' # ssh -x [email protected] getdbglvl # ssh -x [email protected] tomcat-restart # ssh -x [email protected] apache-restart # ssh -x [email protected] tomcat-start # ssh -x [email protected] apache-start # ssh -x [email protected] top # ssh -x [email protected] ps # ssh -x [email protected] df # ssh -x [email protected] free # ssh -x [email protected] reboot case ${SSHSLAVE_COMMAND} in cleanlog | \ getlog | \ getdbglvl | \ tomcat-restart | \ apache-restart | \ tomcat-start | \ apache-start | \ top | \ ps | \ df | \ free | \ reboot \ ) #single argument commands -- exact match to SSHSLAVE_COMMAND exec "/home/tomcat-ssh-slave/bin/${SSHSLAVE_COMMAND}" ;; setdbglvl* ) #e.g., setdbglvl 'INFO' ... multiple argument command. Beware command injection. exec `echo "/home/tomcat-ssh-slave/bin/${SSHSLAVE_COMMAND}" | cut -f1 -d" "` `echo "${SSHSLAVE_COMMAND}" | cut -f2- -d" "` ;; * ) #disallow anything else exec echo You are not authorized to do that. ;; esac
participants (2)
-
Ludovic Dubost -
Niels Mayer