{"id":15096019,"url":"https://github.com/theskyinflames/sshexecutor","last_synced_at":"2025-04-14T22:12:16.184Z","repository":{"id":46274051,"uuid":"193016628","full_name":"theskyinflames/sshexecutor","owner":"theskyinflames","description":"A SSH client (sudo capable)  as a REST service to execute remote recipes (sequence of commands) by SSH, included SUDO commands. It also returns the stdout and stderr filled for these commands executed in the target server. This service does not require any kind of \"agent\" installed in the target servers","archived":false,"fork":false,"pushed_at":"2023-12-19T00:17:51.000Z","size":68,"stargazers_count":16,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-22T05:33:02.839Z","etag":null,"topics":["alpine-linux","concurrency","devops","devops-tools","docker","docker-compose","gin-gonic","go","go-modules","golang","recipes","remote-admin-tool","remote-execution","remote-shell","ssh","ssh-client","ssh-sudo","sudo","theskyinflames"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/theskyinflames.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-21T02:28:33.000Z","updated_at":"2024-08-12T19:50:17.000Z","dependencies_parsed_at":"2024-06-19T02:58:02.019Z","dependency_job_id":"dbf75834-9c3e-4d5f-9f87-b17471030186","html_url":"https://github.com/theskyinflames/sshexecutor","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Fsshexecutor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Fsshexecutor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Fsshexecutor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theskyinflames%2Fsshexecutor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theskyinflames","download_url":"https://codeload.github.com/theskyinflames/sshexecutor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248968916,"owners_count":21191162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpine-linux","concurrency","devops","devops-tools","docker","docker-compose","gin-gonic","go","go-modules","golang","recipes","remote-admin-tool","remote-execution","remote-shell","ssh","ssh-client","ssh-sudo","sudo","theskyinflames"],"created_at":"2024-09-25T15:44:54.586Z","updated_at":"2025-04-14T22:12:16.142Z","avatar_url":"https://github.com/theskyinflames.png","language":"Go","readme":"[![Go Report Card](https://goreportcard.com/badge/github.com/theskyinflames/sshexecutor)](https://goreportcard.com/report/github.com/theskyinflames/sshexecutor)\n\n# SSH Executor\nThis is a service to execute receipts (sequence of shell commands)  to remote servers by ssh. **Included sudo commands !!!** In addition, it returns in its response the standard-output, as well as the standard-error for each executed command. \nEvery call to the service can launch so many commands as it's required.\n\nTo make it work, **you don't need to install any agents in the target servers**. The only you have to do is create a user account in target servers. In addition, if the recipes you want to execute in these servers include sudo commands, this user account must have sudo privileges. Basically, Sudo privileges are required only if you want to execute a recipe that includes sudo commands. Done that, the service will use this user account to connect by SSH to the remote server, It also will be used to make the remote sudo if the executing command requires it.\n\n## Security aspects\nBy using SSH to make the recipes remotely, you have all security context SSH provides. To make a remote server able to be operated by this service, it must to have the user account the SSH Executor service uses to connect. In addition, if the recipes to be executed in this server include sudo commands, the user account has to be suoder.\n\nOn another hand, future versions of this service will allow the use of key exchange as password method replacement. It's pending to be coded.\n\nSaying that still is necessary to fill the SSH user password as an environment variable for the service. You should inject it into the container when it starts in a safe way.\n\n## Not supported commands\nIt's not supported the shell commands with 'su', like 'sudo su *another user*'. It's because the 'su' command starts a new shell process for the new user. When that occurs, these new shell has its own stdout,stdin and stderr. Which can't be captured by the ssh client. From there execution flux is lost and the recipe hangs.\n\n## Configuration\nThere are six environment variables which must be set to make the service run:\n* *SSH_EXECUTOR_API_HOST*: Service API host\n* *SSH_EXECUTOR_API_PORT*: Service API port\n* *SSH_EXECUTOR_API_DEFAULT_SSH_TIMEOUT*: SSH connection timeout in seconds\n* *SSH_EXECUTOR_USER*: Login used for connect by ssh to the remote server\n* *SSH_EXECUTOR_PASSWORD*: Password used for ssh connection, also to provide the sudo password\n\n## End points\nThis service published two endpoints:\n* *[host:port]/check* to allow service status checking (GET)\n* *[host:port]/runreceipt* to execute a recipe (a list of commands) in a remote server by SSH (POST)\n\n## Rq message\nThe rq message is a JSON message with these fields:\n* *host*: Target server\n* *port*: SSH port for the target server\n* *recipe*: List of commands to be executed in the target server\n\n## Rs message\nThe rq message is a JSON message with these fields:\n* *response*: The list os the stdout content for each executed command of the recipe\n* *responseErr*: If some of the commands has written by the stderr, it will in this field\n* *error*: If someone has gone wrong when trying to execute the recipe. For exemple, login fails\n\n## Example without sudo\nRq:\n```json\n{\n  \"host\":\"myhost.mydomain.com\",\n  \"port\":22,\n  \"recipe\":[\n  \t  \"date\",\n  \t  \"uname -a\",\n  \t  \"df -h \u003e myfile.txt\",\n  \t  \"cat myfile.txt\"\n    ]\n}\n```\nRs:\n```json\n{\n    \"response\": [\n        \"dv jun 21 03:50:55 CEST 2019\\r\\n\",\n        \"Linux mx 4.19.0-5-amd64 #1 SMP Debian 4.19.37-2~mx17+1 (2019-05-15) x86_64 GNU/Linux\\r\\n\",\n        \"\",\n        \"S. fitxers          Mida En ús Lliure  %Ús Muntat a\\r\\nudev                3,8G     0   3,8G   0% /dev\\r\\ntmpfs               777M  1,4M   776M   1% /run\\r\\n/dev/mapper/rootfs  108G  7,3G    95G   8% /\\r\\ntmpfs               5,0M  4,0K   5,0M   1% /run/lock\\r\\ntmpfs               1,6G   58M   1,5G   4% /run/shm\\r\\n/dev/sda1           487M   82M   376M  18% /boot\\r\\ncgroup               12K     0    12K   0% /sys/fs/cgroup\\r\\ntmpfs               777M  4,0K   777M   1% /run/user/115\\r\\ntmpfs               777M   24K   777M   1% /run/user/1000\\r\\n\"\n    ],\n    \"responseErr\": \"\",\n    \"error\": \"\"\n}\n```\n\n## Example with sudo recipe\nRq:\n```json\n{\n  \"host\":\"192.168.1.39\",\n  \"port\":22,\n  \"recipe\":[\n  \t  \"sudo ls -lart /root/.bashrc\",\n  \t  \"sudo date \u003e myfile.txt\",\n  \t  \"sudo cat myfile.txt\"\n    ]\n}\n```\n\nRs:\n```json\n{\n    \"response\": [\n        \"-rw-r--r-- 1 root root 570 gen 31  2010 /root/.bashrc\\r\\n\",\n        \"\",\n        \"dv jun 21 04:04:40 CEST 2019\\r\\n\"\n    ],\n    \"responseErr\": \"\",\n    \"error\": \"\"\n}\n```\n\n## Running it !\nThe service is dockerized. So if you start it as a Docker container, only need to do:\n```sh\n    make docker-build\n    docker-compose up\n```\n\nAlternatively, you also can run as a local service. In this case, you must do:\n```sh\n    make build\n    cmd\n```\n\n## Architecture\nThis service has been coded using [gin-gonic](https://gin-gonic.com/) to build the REST API, and the [ssh Go package](https://godoc.org/golang.org/x/crypto/ssh) to build the SSH logic.\n\nI've also used [Alpine Linux](https://alpinelinux.org) to build the Docker images, achieving really light ones:\n```sh\n❯ docker image list\nREPOSITORY                TAG                 IMAGE ID            CREATED             SIZE\nsshexecutor               latest              de80807f2fc3        18 hours ago        23.8MB\n```\n\n### Packages\nThese are the packages that conforms the service:\n* *cmd*: Is the main package\n* *config*: Service configuration taken from environment variables\n* *http*: REST api. It incudes router and controller\n* *model*: Domain models. In this case, the recipe to be executed\n* *service*: The application service. It takes care on execute the recipe using the SSH adapter, take the response and return it to the controller\n* *shared*: This package provides interfaces which are shared between several packages. On this way I avoid to duplicate interfaces definition\n* *ssh*: SSH (sudo enabled) adapter\n\n### Go version\nThe Go version employed has been go1.12.6 with modules enabled\n\n## Do you think this is useful? back me up\nThink and build this tool, has taken part of my time and effort. If you find it useful, and you think I deserve it, you can invite me a coffee :-)\n\n\u003ca href=\"https://www.buymeacoffee.com/jaumearus\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"41\" width=\"174\"\u003e\u003c/a\u003e\n","funding_links":["https://www.buymeacoffee.com/jaumearus"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheskyinflames%2Fsshexecutor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheskyinflames%2Fsshexecutor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheskyinflames%2Fsshexecutor/lists"}