Allows secure creation and execution of scripts over a REST API
Telekinesis is a server that provides hosting and execution of simple shell scripts over a REST API. As an added bonus, it has a user and permission model that lets you control access to the scripts you make.
It's for when you want to be able to run arbitrary commands over the web, without writing and setting up the entire CGI module that would traditionally let you do that.
Fun story: one day, I wrote a script for someone to port a mailing list from one service to another. He wasn't ready for it to run immediately, and he wasn't technical enough for me to just hand off the python file and be done with it, so we had to coordinate when I would run the script to migrate the lists.
This scenario would have been easier if I had been able to just hand him a URL, saying "push this button when you're ready". This is the use case I had in mind when I designed Telekinesis.
You can try the binaries located here
For usage, see
./telekinesis -h
A simple setup running on port 8080 would be
./telekinesis -a admin -p mypassword --port 8080
(Requires python3, virtualenv)
First, clone and enter the repository
git clone https://github.com/antonpaquin/Telekinesis
cd Telekinesis
Set up the python virtual environment
virtualenv env -p python3
source env/bin/activate
Install requirements
pip install -r requirements.txt
And it's ready to run!
cd src
python run.py -a <admin username> -p <admin password> --port <what port to listen on>
Warning: if you're running this on a public network, I highly recommend using https. Otherwise, any password or session token you send can be sniffed, and you might be exposing your computer to arbitrary remote shell access, which is a very bad thing.
To protect your machine, you can run Telekinesis as an unprivileged user, or in a chroot jail, container, or virtual machine.
To build the binaries, we can use pyinstaller and the "/build/Telekinesis.spec" file
First, setup the virtualenv and install requirements as above.
Then, use pyinstaller to build the binary
cd build/
pyinstaller Telekinesis.spec
The results will be put in "build/dist/telekinesis"
Valid options are:
If any arguments are specified in a config file and in command line arguments, the command line arguments take priority.
A simple example, without any security options and serving on port 8080, is
./telekinesis -a administrator -p correct_horse_battery_staple --port 8080
Note: the "/" endpoint returns this file which can be pasted into this editor (or fetched with swagger-ui) to generate docs.
Let's start out by creating a script under the admin user. First, we log in as the admin (using 127.0.0.1 and port 8080 -- set these to wherever you're hosting)
curl -XPOST http://127.0.0.1:8080/login -d '{"username": "myuser", "password": "mypassword"}'
> {"session":"4c3cf5f7a7ab487abd01e4b0c7965f00"}
This token grants full access until the next time the user logs in, so keep it secret.
We'll save it to use in future calls
export COOKIE="session=4c3cf5f7a7ab487abd01e4b0c7965f00"
Now let's create a simple script
curl -b $COOKIE -XPUT http://127.0.0.1:8080/script -d '{"script": "echo Hello World!", "description": "Prints a simple message", "fork": "False"}'
> {"description":"Prints a simple message","fork":false,"public_token":"d4c84e3ef1ac440b936f7b924415e065","script":"echo Hello World!","script_id":1}
We get back a new script with the info we sent it, a "script_id", and a "public_token".
Let's call that script with the script ID to see what it gives us
curl -b $COOKIE -XPOST http://127.0.0.1:8080/script/1
> {"exit_status":0,"pid":11467,"stderr":"","stdout":"Hello World!\n"}
We can see it printed "Hello World!" to stdout and exited successfully.
Now say I want to send that script to my friend so he can run it. I'll send him the URL with the public token
http://127.0.0.1:8080/script/1/d4c84e3ef1ac440b936f7b924415e065
(Note: You'd need to be serving on a publicly accessible host and port for your friend to reach the server. 127.0.0.1 would not work from another machine)
And my friend can call and see the results of the script by POSTing that URL
curl -XPOST http://127.0.0.1:8080/script/1/d4c84e3ef1ac440b936f7b924415e065
> {"exit_status":0,"pid":11470,"stderr":"","stdout":"Hello World!\n"}
Let's say I trust my friend with my machine, and I want to give him the ability to write scripts on his own.
We'll create the user:
curl -b $COOKIE -XPUT http://127.0.0.1:8080/user -d '{"username": "myfriend", "password": "newpassword"}'
(Sorry, password change endpoint is not written yet. Put an issue in this repo if you would like this feature)
This default user can't do anything, so let's give him the "script.create" permission
curl -b $COOKIE -XPUT http://127.0.0.1:8080/permission -d '{"username": "myfriend", "permission": "script.create"}'
Now he can create his own scripts, and he'll have full access to anything he creates.
Valid permissions are:
When a script is created, the user "#script.public.[x]" is automatically created and given script.read.[x] and script.execute.[x] on that script. This user is only accessible via the public token created and stored in the script's "public_token" field (which is visible to anyone with "script.read.[x]" or "scripts.read").
If you do not want this script to be publicly accessible, you can ignore the "public_token" field, or remove these permissions with
curl -b $COOKIE -XDELETE http://127.0.0.1:8080/permission -d '{"username": "#script.public.[x]", "permission": "script.execute.[x]"}'
curl -b $COOKIE -XDELETE http://127.0.0.1:8080/permission -d '{"username": "#script.public.[x]", "permission": "script.read.[x]"}'
If you run telekinesis with the default options, user scripts will be able to run anything that the user who starts the program can. This means they can do things like delete your home directory, or add a keylogger to your bashrc.
If you keep "script.update" and "script.create" private, then you're safe. Otherwise, you should consider using one of the two available isolation methods to prevent user scripts from doing evil things.
If "run_as_user" and "run_as_password" are set in a config file, telekinesis will change to that user before executing commands. You can take advantage of this to create an unprivileged user, who will not be able to damage the local machine.
To create an unprivileged user "telekinesis", run
sudo useradd telekinesis
sudo passwd telekinesis
Make sure the "other" system permissions are set to prevent access to private files
# Remove read permission from other users
chmod o-r my_file
# Remove write permission from other users
chmod o-w my_file
Which will prevent those files from being read or changed by a telekinesis script.
You can tell telekinesis to SSH into another machine before executing any scripts. This can be used to run commands on a local container or a remote machine where malicious users can do no harm, or to a different user on the local machine.
Any arguments you specify in the "ssh" parameter will be appended to
ssh -T
and run to generate a shell. You should use an identity file to enable passwordless login, and should also consider adding the host to your ssh config.
An example SSH config might contain:
host telekinesis_executor
HostName 192.168.0.110
port 22
User telekinesis
IdentityFile ~/.ssh/my_ssh_.key
And the remote host should contain the public key in its "~/.ssh/authorized_keys" file.
With this setup, specifying
{
...
"ssh": "telekinesis_executor"
}
would be sufficient to trigger commands on the remote machine.