Blog
This is a quick guide on how to turn SSH commands into a REST API service. The use-case may be remote administration of devices or equipment that does not offer a REST interface or making sure that access to SSH commands is restricted to selected external REST-based API clients only.
The first thing needed is code of the service that will connect to SSH servers. Below is a service doing just that - it receives name of the command to execute and host to run in on, translating stdout and stderr of SSH commands into response documents which Zato in turn serializes to JSON.
# -*- coding: utf-8 -*-
# stdlib
from traceback import format_exc
# Zato
from zato.server.service import Service
class SSHInvoker(Service):
""" Accepts an SSH command to run on a remote host and returns its output to caller.
"""
# A list of elements that we expect on input
input = 'host', 'command'
# A list of elements that our responses will contain
output = 'is_ok', 'cid', '-stdout', '-stderr'
def handle(self):
# Local aliases
host = self.request.input.host
command = self.request.input.command
# Correlation ID is always returned
self.response.payload.cid = self.cid
try:
# Build the full command
full_command = f'ssh {host} {command}'
# Run the command and collect output
output = self.commands.invoke(full_command)
# Assign both stdout and stderr to response
self.response.payload.stdout = output.stdout
self.response.payload.stderr = output.stderr
except Exception:
# Catch any exception and log it
self.logger.warn('Exception caught (%s), e:`%s', self.cid, format_exc())
# Indicate an error
self.response.payload.is_ok = False
else:
# Everything went fine
self.response.payload.is_ok = True
In the Zato Dashboard, let's go ahead and create an HTTP Basic Auth definition that a remote API client will authenticate against:
Now, the SSH service can be mounted on a newly created REST channel - note the security definition used and that data format is set to JSON. We can skip all the other details such as caching or rate limiting, for illustration purposes, this is not needed.
At this point, everything is ready to use. We could make it accessible to external API clients but, for testing purposes, let's simply invoke our SSH API gateway service from the command line:
$ curl "api:password@localhost:11223/api/ssh" -d \
'{"host":"localhost", "command":"uptime"}'
{
"is_ok": true,
"cid": "27406f29c66c2ab6296bc0c0",
"stdout": " 09:45:42 up 37 min, 1 user, load average: 0.14, 0.27, 0.18\n"}
$
And this completes it - the service is deployed and made accessible via a REST channel that can be invoked using JSON. Any command can be sent to any host and their output will be returned to API callers in JSON responses.