{"id":13416415,"url":"https://github.com/tianon/gosu","last_synced_at":"2025-09-09T21:08:59.636Z","repository":{"id":16946859,"uuid":"19708981","full_name":"tianon/gosu","owner":"tianon","description":"Simple Go-based setuid+setgid+setgroups+exec","archived":false,"fork":false,"pushed_at":"2025-03-17T21:21:13.000Z","size":135,"stargazers_count":4797,"open_issues_count":7,"forks_count":328,"subscribers_count":88,"default_branch":"master","last_synced_at":"2025-05-07T07:03:57.577Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","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/tianon.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-05-12T17:50:47.000Z","updated_at":"2025-05-06T00:08:48.000Z","dependencies_parsed_at":"2023-01-13T19:05:38.658Z","dependency_job_id":"a357994c-70ab-4d61-a700-102138f68116","html_url":"https://github.com/tianon/gosu","commit_stats":{"total_commits":174,"total_committers":14,"mean_commits":"12.428571428571429","dds":"0.10919540229885061","last_synced_commit":"a094511005799318adac840b6974852075a81153"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tianon%2Fgosu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tianon%2Fgosu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tianon%2Fgosu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tianon%2Fgosu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tianon","download_url":"https://codeload.github.com/tianon/gosu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254101579,"owners_count":22014904,"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":[],"created_at":"2024-07-30T21:00:58.501Z","updated_at":"2025-05-14T08:02:03.528Z","avatar_url":"https://github.com/tianon.png","language":"Shell","funding_links":[],"categories":["Docker Images","Shell","Go","开源类库","Open source library","Dev Tools","Go (531)","In-Container Tooling","others"],"sub_categories":["Base Tools","命令行","Command Line","Wrappers"],"readme":"# gosu\n\nThis is a simple tool grown out of the simple fact that `su` and `sudo` have very strange and often annoying TTY and signal-forwarding behavior.  They're also somewhat complex to setup and use (especially in the case of `sudo`), which allows for a great deal of expressivity, but falls flat if all you need is \"run this specific application as this specific user and get out of the pipeline\".\n\nThe core of how `gosu` works is stolen directly from how Docker/libcontainer itself starts an application inside a container (and in fact, is using the `/etc/passwd` processing code directly from libcontainer's codebase).\n\n```console\n$ gosu\nUsage: ./gosu user-spec command [args]\n   eg: ./gosu tianon bash\n       ./gosu nobody:root bash -c 'whoami \u0026\u0026 id'\n       ./gosu 1000:1 id\n\n./gosu version: 1.1 (go1.3.1 on linux/amd64; gc)\n```\n\nOnce the user/group is processed, we switch to that user, then we `exec` the specified process and `gosu` itself is no longer resident or involved in the process lifecycle at all.  This avoids all the issues of signal passing and TTY, and punts them to the process invoking `gosu` and the process being invoked by `gosu`, where they belong.\n\n## Warning\n\nThe core use case for `gosu` is to step _down_ from `root` to a non-privileged user during container startup (specifically in the `ENTRYPOINT`, usually).\n\nUses of `gosu` beyond that could very well suffer from vulnerabilities such as CVE-2016-2779 (from which the Docker use case naturally shields us); see [`tianon/gosu#37`](https://github.com/tianon/gosu/issues/37) for some discussion around this point.\n\n## Installation\n\nHigh-level steps:\n\n1. download `gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }')` as `gosu`\n2. download `gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }').asc` as `gosu.asc`\n3. fetch my public key (to verify your download): `gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4`\n4. `gpg --batch --verify gosu.asc gosu`\n5. `chmod +x gosu`\n\nFor explicit `Dockerfile` instructions, see [`INSTALL.md`](INSTALL.md).\n\n## Why?\n\n```console\n$ docker run -it --rm ubuntu:trusty su -c 'exec ps aux'\nUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND\nroot         1  0.0  0.0  46636  2688 ?        Ss+  02:22   0:00 su -c exec ps a\nroot         6  0.0  0.0  15576  2220 ?        Rs   02:22   0:00 ps aux\n$ docker run -it --rm ubuntu:trusty sudo ps aux\nUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND\nroot         1  3.0  0.0  46020  3144 ?        Ss+  02:22   0:00 sudo ps aux\nroot         7  0.0  0.0  15576  2172 ?        R+   02:22   0:00 ps aux\n$ docker run -it --rm -v $PWD/gosu-amd64:/usr/local/bin/gosu:ro ubuntu:trusty gosu root ps aux\nUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND\nroot         1  0.0  0.0   7140   768 ?        Rs+  02:22   0:00 ps aux\n```\n\nAdditionally, due to the fact that `gosu` is using Docker's own code for processing these `user:group`, it has exact 1:1 parity with Docker's own `--user` flag.\n\nIf you're curious about the edge cases that `gosu` handles, see [`Dockerfile.test-alpine`](Dockerfile.test-alpine) for the \"test suite\" (and the associated [`test.sh`](test.sh) script that wraps this up for testing arbitrary binaries).\n\n(Note that `sudo` has different goals from this project, and it is *not* intended to be a `sudo` replacement; for example, see [this Stack Overflow answer](https://stackoverflow.com/a/48105623/433558) for a short explanation of why `sudo` does `fork`+`exec` instead of just `exec`.)\n\n## Alternatives\n\n### `setpriv`\n\nAvailable in newer `util-linux` (`\u003e= 2.32.1-0.2`, in Debian; https://manpages.debian.org/buster/util-linux/setpriv.1.en.html):\n\n```console\n$ docker run -it --rm buildpack-deps:buster-scm setpriv --reuid=nobody --regid=nogroup --init-groups ps faux\nUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND\nnobody       1  5.0  0.0   9592  1252 pts/0    RNs+ 23:21   0:00 ps faux\n```\n\n### `chroot`\n\nWith the `--userspec` flag, `chroot` can provide similar benefits/behavior:\n\n```console\n$ docker run -it --rm ubuntu:trusty chroot --userspec=nobody / ps aux\nUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND\nnobody       1  5.0  0.0   7136   756 ?        Rs+  17:04   0:00 ps aux\n```\n\n### `su-exec`\n\nIn the Alpine Linux ecosystem, [`su-exec`](https://github.com/ncopa/su-exec) is a minimal re-write of `gosu` in C, making for a much smaller binary, and is available in the `main` Alpine package repository.  However, as of version 0.2 it has [a pretty severe parser bug](https://github.com/ncopa/su-exec/pull/26) that hasn't been in a release for many years (and which the buggy behavior is that typos lead to running code as root unexpectedly 😬).\n\n### Others\n\nI'm not terribly familiar with them, but a few other alternatives I'm aware of include:\n\n- `chpst` (part of `runit`)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftianon%2Fgosu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftianon%2Fgosu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftianon%2Fgosu/lists"}