{"id":15971389,"url":"https://github.com/dolph/ussher","last_synced_at":"2026-05-16T03:47:26.752Z","repository":{"id":57965592,"uuid":"384274608","full_name":"dolph/ussher","owner":"dolph","description":"Remotely source SSH authorized_keys","archived":false,"fork":false,"pushed_at":"2023-04-30T18:00:20.000Z","size":62,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T15:52:54.208Z","etag":null,"topics":["ssh","sshd","sshd-config"],"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/dolph.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.go","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-08T23:53:07.000Z","updated_at":"2024-03-03T18:39:31.000Z","dependencies_parsed_at":"2024-06-21T17:54:13.833Z","dependency_job_id":null,"html_url":"https://github.com/dolph/ussher","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dolph/ussher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolph%2Fussher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolph%2Fussher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolph%2Fussher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolph%2Fussher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dolph","download_url":"https://codeload.github.com/dolph/ussher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolph%2Fussher/sbom","scorecard":{"id":350169,"data":{"date":"2025-08-11","repo":{"name":"github.com/dolph/ussher","commit":"68af9c744eab88b1337f9cf4c9b218a99d051816"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":10,"reason":"SAST tool detected: CodeQL","details":["Info: SAST configuration detected: CodeQL","Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/go.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/go.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/dolph/ussher/go.yml/main?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yml:17","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yml:18","Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/go.yml:17","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/go.yml:18","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v1.0.2 not signed: https://api.github.com/repos/dolph/ussher/releases/101415282","Warn: release artifact v1.0.1 not signed: https://api.github.com/repos/dolph/ussher/releases/101373449","Warn: release artifact v1.0.0 not signed: https://api.github.com/repos/dolph/ussher/releases/101172915","Warn: release artifact v1.0.2 does not have provenance: https://api.github.com/repos/dolph/ussher/releases/101415282","Warn: release artifact v1.0.1 does not have provenance: https://api.github.com/repos/dolph/ussher/releases/101373449","Warn: release artifact v1.0.0 does not have provenance: https://api.github.com/repos/dolph/ussher/releases/101172915"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T08:08:40.650Z","repository_id":57965592,"created_at":"2025-08-18T08:08:40.650Z","updated_at":"2025-08-18T08:08:40.650Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273317739,"owners_count":25084033,"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","status":"online","status_checked_at":"2025-09-02T02:00:09.530Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ssh","sshd","sshd-config"],"created_at":"2024-10-07T20:21:22.700Z","updated_at":"2026-05-16T03:47:26.741Z","avatar_url":"https://github.com/dolph.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `ussher`\n\n`ussher` aims to provide a backend for `sshd`'s [`AuthorizedKeysCommand` option](https://man.openbsd.org/sshd_config.5#AuthorizedKeysCommand), by remotely sourcing SSH `authorized_keys`. In short:\n\n\u003e `AuthorizedKeysCommand`: Specifies a program to be used to look up the user's public keys. The program must be owned by root, not writable by group or others and specified by an absolute path.\n\u003e\n\u003e The program should produce on standard output zero or more lines of authorized_keys output. `AuthorizedKeysCommand` is tried after the usual `AuthorizedKeysFile` files and will not be executed if a matching key is found there. By default, no `AuthorizedKeysCommand` is run.\n\nWhen `~/.ssh/authorized_keys` does not contain the keys required to authenticate a user, `sshd` invokes `ussher` to provide additional, remotely-sourced keys, such as from Github or another identity and access management provider.\n\n## How it works\n\n`ussher` provides a fallback mechanism for statically-defined `authorized_keys` files, such as when `authorized_keys` needs to be frequently updated, composed from a large number of sources, or simply defined at the moment of authorization.\n\n1. When you `ssh $USER@$HOSTNAME`, `sshd` first reads something like `/home/$USER/.ssh/authorized_keys` to authenticate incoming SSH connections. If `authorized_keys` contains a public key that matches the incoming connection, then the connection attempt proceeds normally.\n\n1. If that file does not exist or does not contain a public key for the incoming connection, `sshd` will invoke `AuthorizedKeysCommand` as `AuthorizedKeysCommandUser`. The `AuthorizedKeysCommand` (`ussher`, in this case), is responsible for returning a list of authorized public keys, which `sshd` then uses to validate the incoming connection.\n\n1. When invoked, `ussher` sources authorized keys from any number of remote sources, such as a static text file or more commonly something like `https://github.com/{username}.keys`. `ussher` then returns a single set of authorized keys to `sshd` which are used to validate the incoming connection.\n\n## Recommended installation \u0026 usage\n\n1. Download the latest release of `ussher` from [github.com/dolph/ussher](https://github.com/dolph/ussher/releases/latest), along with its `sha256` checksum, and verify the binary before installing:\n\n   ```bash\n   curl -fLO https://github.com/dolph/ussher/releases/latest/download/ussher\n   curl -fLO https://github.com/dolph/ussher/releases/latest/download/ussher.sha256\n   sha256sum -c ussher.sha256\n   ```\n\n   `sha256sum -c` exits non-zero if the binary doesn't match the published checksum. Don't proceed past this step on a mismatch.\n\n2. Create a dedicated user and group to run `ussher`, named `ussher`:\n\n   ```bash\n   sudo adduser --system --user-group ussher\n   ```\n\n3. Install the `ussher` binary: to `/usr/local/bin`.\n\n   ```bash\n   sudo install -o root -g ussher -m 0750 ussher /usr/local/bin/ussher\n   ```\n\n4. Create a configuration directory.\n\n   ```bash\n   sudo mkdir --parents /etc/ussher\n   ```\n\n5. Create a directory for caching remotely-sourced data.\n\n   ```bash\n   sudo mkdir --parents /var/cache\n   sudo mkdir --parents --mode=0700 /var/cache/ussher\n   sudo chown ussher:ussher /var/cache/ussher\n   ```\n\n6. Create a directory for logging.\n\n   ```bash\n   sudo mkdir --parents --mode=0700 /var/log/ussher\n   sudo chown ussher:ussher /var/log/ussher\n   ```\n\n7. Configure `sshd` to invoke `ussher`. Add the following lines to\n   `/etc/ssh/sshd_config`:\n\n   ```\n   AuthorizedKeysCommand /usr/local/bin/ussher\n   AuthorizedKeysCommandUser ussher\n   ```\n\n   You can script this with:\n\n   ```bash\n   sudo sed -i -E \"s~^#?AuthorizedKeysCommand .*~AuthorizedKeysCommand /usr/local/bin/ussher~\" /etc/ssh/sshd_config\n   sudo sed -i -E \"s~^#?AuthorizedKeysCommandUser .*~AuthorizedKeysCommandUser ussher~\" /etc/ssh/sshd_config\n   ```\n\n   Validate sshd's new configuration and restart `sshd`, for example:\n\n   ```bash\n   sudo sshd -t\n   sudo systemctl restart sshd\n   ```\n\n## Configuration\n\n`/etc/ussher` contains configuration files for each user it supports. For example, to allow @dolph to SSH to your host as root (but, you know, _don't_), you would configure `/etc/ussher/root.yml` using:\n\n```yaml\nsources:\n- url: https://github.com/dolph.keys\n```\n\n### `cache_ttl`\n\nResponses from each source URL are cached on disk under `/var/cache/ussher` so that frequent SSH attempts don't hammer the upstream. Cached entries expire after `cache_ttl`; once expired, the next login refetches the source. After `cache_ttl` elapses, key revocations on the upstream propagate to this host. Smaller values mean revocations take effect sooner and add upstream load; larger values reduce upstream load and lengthen the window during which a revoked key could still authenticate.\n\n`cache_ttl` accepts any duration string understood by Go's [`time.ParseDuration`](https://pkg.go.dev/time#ParseDuration) — for example `30s`, `5m`, `1h`. The default when unset is `5m`.\n\n```yaml\ncache_ttl: 5m\nsources:\n- url: https://github.com/dolph.keys\n```\n\n### `http_timeout`\n\n`http_timeout` caps how long a single upstream fetch (connect + headers + body read) can take before `ussher` gives up on it. A hung or stalled source — DNS that resolves but never returns, a TLS handshake that hangs, an HTTP server that accepts the connection but never responds — would otherwise block `sshd`'s authentication path until the OS-default timeout fires (often 2+ minutes per attempt). With `http_timeout`, `ussher` abandons the source quickly, treats the failure exactly like any other (logs and contributes zero keys from that source), and the rest of the configured sources continue to be served.\n\n`http_timeout` accepts any duration string understood by [`time.ParseDuration`](https://pkg.go.dev/time#ParseDuration) — for example `500ms`, `10s`, `30s`. The default when unset is `10s`. Tighter values trade a higher rate of \"slow but healthy upstream gave up\" denials for tighter login latency under partial outages; looser values do the opposite.\n\n```yaml\nhttp_timeout: 10s\nsources:\n- url: https://github.com/dolph.keys\n```\n\n## Troubleshooting\n\n### `Refusing to run unnecessarily writable binary`\n\nPer the `sshd` man page:\n\n\u003e The program must be owned by root, not writable by group or others and specified by an absolute path.\n\n`ussher` checks to ensure it's own binary is not unnecessarily writable at startup. If it is, a malicious user could remove this check or return any set of keys to sshd, which may be difficult to detect.\n\nEnsure the file mode is similar to:\n\n```\n$ ls -l /usr/local/bin/ussher\n-rwxr-x---. 1 root ussher 7823184 Apr 27 11:10 /usr/local/bin/ussher*\n```\n\nFor example:\n\n```bash\nsudo chmod g-w /usr/local/bin/ussher\nsudo chmod o-w /usr/local/bin/ussher\n```\n\n... but the binary may have been tainted. Verify it's checksum.\n\n### `Refusing to run as root`\n\n`ussher` checks to ensure it's not unnecessarily _running_ as root.\n\nEnsure `sshd_config` specifies a non-root user:\n\n```\nAuthorizedKeysCommandUser ussher\n```\n\n### `Failed to write to /var/log/ussher`\n\n`ussher` tries to ensure it can produce file-based logging output for auditing purposes. It's first preference is for `/var/log/ussher` which requires:\n\n```bash\nsudo mkdir --parents --mode=0700 /var/log/ussher\nsudo chown ussher:ussher /var/log/ussher\n```\n\n### `Refusing to run without being able to log to /var/log/ussher/ or current working directory`\n\n`ussher` tries to ensure it can produce file-based logging output for auditing purposes, and will fallback to the current working directory if `/var/log/ussher` is not writable. The best solution is to ensure `/var/log/ussher` is writable (see previous troubleshooting issue).\n\n### `Refusing to run due to permissions issue on the ussher executable`\n\n`ussher` tries to ensure that its own binary is not susceptible to manipulation by unauthorized users. This error may be accompanied by a more specific error in stdout.\n\nPossible solutions include:\n\n```bash\nsudo chmod g-w /usr/local/bin/ussher\nsudo chmod o-w /usr/local/bin/ussher\n```\n\n### `usage: ussher \u003cusername\u003e`\n\nPer the `sshd_config` man page:\n\n\u003e Arguments to AuthorizedKeysCommand accept the tokens described in the TOKENS section. If no arguments are specified then the username of the target user is used.\n\n`ussher` only expects the default configuration from sshd (the username of the target user).\n\nEnsure `sshd_config` only specifies the absolute path to `ussher`, without any additional arguments:\n\n```\nAuthorizedKeysCommand /usr/local/bin/ussher\n```\n\n### `User not found`\n\nThe user specified to `ussher` is either not a valid Linux username or not an existing user on the host. Double check the username specified to `ussher` as well as the `AuthorizedKeysCommand` value in `/etc/ssh/sshd_config`.\n\n## Changelog\n\nSee [`CHANGELOG.md`](./CHANGELOG.md) for the per-release history. The project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and adheres to [Semantic Versioning](https://semver.org/).\n\n## License\n\nApache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdolph%2Fussher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdolph%2Fussher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdolph%2Fussher/lists"}