{"id":13528864,"url":"https://github.com/ml-tooling/ssh-proxy","last_synced_at":"2025-04-24T16:30:47.871Z","repository":{"id":45699309,"uuid":"192536423","full_name":"ml-tooling/ssh-proxy","owner":"ml-tooling","description":"🐳 Dockerized SSH bastion to proxy SSH connections to arbitrary containers.","archived":false,"fork":false,"pushed_at":"2020-08-04T09:53:28.000Z","size":124,"stargazers_count":82,"open_issues_count":1,"forks_count":16,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-03T07:21:53.811Z","etag":null,"topics":["bastion","docker","gateway","jumpserver","kubernetes","ssh-bastion","ssh-server","ssh-tunnel"],"latest_commit_sha":null,"homepage":"","language":"Python","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/ml-tooling.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-18T12:33:43.000Z","updated_at":"2025-03-12T04:11:31.000Z","dependencies_parsed_at":"2022-09-19T08:00:29.319Z","dependency_job_id":null,"html_url":"https://github.com/ml-tooling/ssh-proxy","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ml-tooling%2Fssh-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ml-tooling%2Fssh-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ml-tooling%2Fssh-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ml-tooling%2Fssh-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ml-tooling","download_url":"https://codeload.github.com/ml-tooling/ssh-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250663544,"owners_count":21467366,"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":["bastion","docker","gateway","jumpserver","kubernetes","ssh-bastion","ssh-server","ssh-tunnel"],"created_at":"2024-08-01T07:00:26.582Z","updated_at":"2025-04-24T16:30:47.553Z","avatar_url":"https://github.com/ml-tooling.png","language":"Python","funding_links":[],"categories":["Python","Apps","docker"],"sub_categories":["Servers"],"readme":"\u003ch1 align=\"center\"\u003e\n    SSH Proxy\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cstrong\u003eDockerized SSH bastion to proxy SSH connections to arbitrary containers.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://hub.docker.com/r/mltooling/ssh-proxy\" title=\"Docker Image Version\"\u003e\u003cimg src=\"https://images.microbadger.com/badges/version/mltooling/ssh-proxy.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://hub.docker.com/r/mltooling/ssh-proxy\" title=\"Docker Pulls\"\u003e\u003cimg src=\"https://img.shields.io/docker/pulls/mltooling/ssh-proxy.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://hub.docker.com/r/mltooling/ssh-proxy\" title=\"Docker Image Metadata\"\u003e\u003cimg src=\"https://images.microbadger.com/badges/image/mltooling/ssh-proxy.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/ml-tooling/ssh-proxy/blob/develop/LICENSE\" title=\"SSH Proxy License\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache%202.0-green.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://gitter.im/ml-tooling/community\" title=\"Chat on Gitter\"\u003e\u003cimg src=\"https://badges.gitter.im/ml-tooling/community.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://twitter.com/mltooling\" title=\"ML Tooling on Twitter\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/mltooling.svg?style=social\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e •\n  \u003ca href=\"#highlights\"\u003eHighlights\u003c/a\u003e •\n  \u003ca href=\"#support\"\u003eSupport\u003c/a\u003e •\n  \u003ca href=\"https://github.com/ml-tooling/ssh-proxy/issues/new?labels=bug\u0026template=01_bug-report.md\"\u003eReport a Bug\u003c/a\u003e •\n  \u003ca href=\"#contribution\"\u003eContribution\u003c/a\u003e\n\u003c/p\u003e\n\nThis SSH proxy can be deployed as a standalone docker container that allows to proxy any user SSH connection to arbitrary unexposed containers. This enables users to securely access any container via SSH within a cluster only via a single exposed port and provides full SSH compatibility (e.g. port tunneling, scp, sftp, rsync, sshfs, X11). This proxy has a few security features built-in to make sure that users can only access target containers that they are allowed to.\n\n## Highlights\n\n- 🛡 SSH access to behind-firewall clusters via a single port.\n- 🔐 Restrict target containers based on port and DNS pattern.\n- 🛠 Full SSH compatibility (port tunneling, scp, sftp, rsync, sshfs).\n- 📄 Basic access logging based on user logins.\n- 🐳 Easy to deploy via Docker and Kubernetes.\n- 🏗 Use it as a base image in your own Docker image to bring the ssh functionality into it (checkout the [ml-hub Dockerfile](https://github.com/ml-tooling/ml-hub/blob/1ab1c6b1b4b4b8a6fd2f321ccfb9c8f6f0e0c6eb/Dockerfile#L1) as an example)\n\n## Getting Started\n\n### Prerequisites\n\nThe target containers must run an SSH server and provide a valid public key. The ssh-proxy container will try to get a key from a target container via a `/publickey` endpoint (e.g. `http://\u003ccontainername or podid\u003e:8080/publickey`, whereby the port 8080 can be configured via an [environment variable]($SSH_TARGET_PUBLICKEY_API_PORT)); if this does not exist, the ssh-proxy tries to exec into the target container and search for the publickey under `$SSH_TARGET_KEY_PATH` (default: `~/.ssh/id_ed25519.pub`).\n\n\u003e ℹ️ _The SSH proxy accepts an incoming key, if it belongs to one of the targets key, in other words the proxy/bastion server authorizes all target public keys. It is still not possible to login to the proxy directly. The authorization happens only for creating and tunneling the final connection._\n\nPort and hostname of target containers that users are allowed to access can be restricted via environment variables (see [configuration section](#configuration)), but the restrictions can be applied only accross all targets. In Kubernetes mode, the SSH proxy and the SSH targets must be in the same namespace.\n\nWe recommend to offer the public key via the `/publickey` endpoint, as the `kubectl exec` command can be slow for big clusters. You can also completely avoid those requirements by setting `$MANUAL_AUTH_FILE=true` and maintaing the proxy's `/etc/ssh/authorized_keys_cache` file yourself (e.g. by mounting a file at the same location). In this case, you don't have to mount the Docker socket / Kubernetes config into the container. The `authorized_keys_cache` file has the same format as the standard ssh authorized_keys file.\n\n### Start SSH Proxy\n\n#### Docker\n\n```bash\ndocker run -d \\\n    -p 8091:22 \\\n    -v /var/run/docker.sock:/var/run/docker.sock \\\n    mltooling/ssh-proxy\n```\n\n#### Kubernetes\n\nIf you make a kube config available to the container, either via incluster config (Python code: `kubernetes.config.load_incluster_config()`) or by mounting it to `/root/.kube/config`, ssh-proxy also works for tunneling requests in Kubernetes.\n\n### Connect to Target\n\n```bash\nssh \\\n    -o \"ProxyCommand=ssh -W %h:%p -p 8091 -i ~/.ssh/\u003ctarget-key\u003e limited-user@\u003cssh-proxy-host\u003e\" \\\n    -p \u003ctarget-port\u003e \\\n    -i ~/.ssh/\u003ctarget-key\u003e \\\n    root@\u003ctarget-host\u003e\n```\n\nDoing this way, the connection from client to target is end-to-end encrypted.\n\n\u003e ℹ️ _The \"\\\u003ctarget-host\\\u003e\" host can be the Docker container name or Kubernetes service name. In that case, the bastion has to be in the same Docker network or the connection must be allowed in case of existing Networkpolicies in Kubernetes, respectively._\n\n### Configuration\n\nThe container can be configured with the following environment variables (`--env`):\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003eVariable\u003c/th\u003e\n        \u003cth\u003eDescription\u003c/th\u003e\n        \u003cth\u003eDefault\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eSSH_PERMIT_TARGET_HOST\u003c/td\u003e\n        \u003ctd\u003eDefines which other containers can be ssh targets. The container names must start with the prefix. The ssh connection to the target can only be made for targets where the name matches the given target host. The '*' character can be used as wildcards, e.g. 'workspace-*' would allow connecting to target containers/services which names start with 'workspace-'.\n        \u003c/td\u003e\n        \u003ctd\u003e*\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eSSH_PERMIT_TARGET_PORT\u003c/td\u003e\n        \u003ctd\u003eDefines on which port the other containers can be reached via ssh. The ssh connection to the target can only be made via this port then. The default value '*' permits any port.\u003c/td\u003e\n        \u003ctd\u003e*\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eSSH_TARGET_LABELS\u003c/td\u003e\n        \u003ctd\u003eSpecify which containers are targeted. Filters containers / pods via these labels. Must be in the form of \"label1=value1,label2=value2,label3=value3\". Default is empty string which disables filtering.\u003c/td\u003e\n        \u003ctd\u003e\"\"\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eSSH_TARGET_PUBLICKEY_API_PORT\u003c/td\u003e\n        \u003ctd\u003ePort where the target container exposes the /publickey endpoint (if used).\u003c/td\u003e\n        \u003ctd\u003e8080\u003c/td\u003e\n    \u003c/tr\u003e \n    \u003ctr\u003e\n        \u003ctd\u003eSSH_TARGET_KEY_PATH\u003c/td\u003e\n        \u003ctd\u003eThe path inside the target containers where the manager looks for a valid public key.\n        Consider that `~` will be resolved to the target container's home. Only used when the target container does not return a public key via the /publickey endpoint.\u003c/td\u003e\n        \u003ctd\u003e~/.ssh/id_ed25519.pub\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eMANUAL_AUTH_FILE\u003c/td\u003e\n        \u003ctd\u003eDisables the bastion's public key fetching method and you have to maintain the /etc/ssh/authorized_keys_cache file yourself (e.g. by mounting a respective file there). Only used when the target container does not return a public key via the /publickey endpoint.\u003c/td\u003e\n        \u003ctd\u003efalse\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n## Features\n\n### Access Logging\n\nLogins are logged at `/etc/ssh/access.log`\n\n## Support\n\nThe SSH Proxy project is maintained by [@raethlein](https://twitter.com/raethlein) and [@LukasMasuch](https://twitter.com/LukasMasuch). Please understand that we won't be able\nto provide individual support via email. We also believe that help is much more\nvaluable if it's shared publicly so that more people can benefit from it.\n\n| Type                     | Channel                                              |\n| ------------------------ | ------------------------------------------------------ |\n| 🚨 **Bug Reports**       | \u003ca href=\"https://github.com/ml-tooling/ssh-proxy/issues?utf8=%E2%9C%93\u0026q=is%3Aopen+is%3Aissue+label%3Abug+sort%3Areactions-%2B1-desc+\" title=\"Open Bug Report\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/ml-tooling/ssh-proxy/bug.svg\"\u003e\u003c/a\u003e                                 |\n| 🎁 **Feature Requests**  | \u003ca href=\"https://github.com/ml-tooling/ssh-proxy/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc\" title=\"Open Feature Request\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/ml-tooling/ssh-proxy/feature-request.svg?label=feature%20requests\"\u003e\u003c/a\u003e                                 |\n| 👩‍💻 **Usage Questions**   |  \u003ca href=\"https://stackoverflow.com/questions/tagged/ml-tooling\" title=\"Open Question on Stackoverflow\"\u003e\u003cimg src=\"https://img.shields.io/badge/stackoverflow-ml--tooling-orange.svg\"\u003e\u003c/a\u003e \u003ca href=\"https://gitter.im/ml-tooling/community\" title=\"Chat on Gitter\"\u003e\u003cimg src=\"https://badges.gitter.im/ml-tooling/community.svg\"\u003e\u003c/a\u003e |\n| 🗯 **General Discussion** | \u003ca href=\"https://gitter.im/ml-tooling/community\" title=\"Chat on Gitter\"\u003e\u003cimg src=\"https://badges.gitter.im/ml-tooling/community.svg\"\u003e\u003c/a\u003e  \u003ca href=\"https://twitter.com/mltooling\" title=\"ML Tooling on Twitter\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/mltooling.svg?style=social\"\u003e\u003c/a\u003e                  |\n\n## Contribution\n\n- Pull requests are encouraged and always welcome. Read [`CONTRIBUTING.md`](https://github.com/ml-tooling/ssh-proxy/tree/master/CONTRIBUTING.md) and check out [help-wanted](https://github.com/ml-tooling/ssh-proxy/issues?utf8=%E2%9C%93\u0026q=is%3Aopen+is%3Aissue+label%3A\"help+wanted\"+sort%3Areactions-%2B1-desc+) issues.\n- Submit github issues for any [feature enhancements](https://github.com/ml-tooling/ssh-proxy/issues/new?assignees=\u0026labels=feature-request\u0026template=02_feature-request.md\u0026title=), [bugs](https://github.com/ml-tooling/ssh-proxy/issues/new?assignees=\u0026labels=bug\u0026template=01_bug-report.md\u0026title=), or [documentation](https://github.com/ml-tooling/ssh-proxy/issues/new?assignees=\u0026labels=enhancement%2C+docs\u0026template=03_documentation.md\u0026title=) problems.\n- By participating in this project you agree to abide by its [Code of Conduct](https://github.com/ml-tooling/ssh-proxy/tree/master/CODE_OF_CONDUCT.md).\n\n---\n\nLicensed **Apache 2.0**. Created and maintained with ❤️ by developers from SAP in Berlin. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fml-tooling%2Fssh-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fml-tooling%2Fssh-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fml-tooling%2Fssh-proxy/lists"}