Fix for openssh 10.13 breaking principals wildcard in SSH certificates#513
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates OPKSSH’s SSH certificate issuance/verification behavior to remain compatible with OpenSSH >= 10.3, which no longer treats empty certificate principals as a wildcard.
Changes:
- Issue user SSH certificates with a non-empty “sentinel” principal instead of an empty principals list.
- Update
verify(AuthorizedKeysCommand output) to emit anauthorized_keysline that includes aprincipals="..."option derived from the certificate principals. - Adjust the
verifyunit test to expect the newprincipals="..."output format.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
commands/verify.go |
Adds principals handling in AuthorizedKeysCommand output to support the sentinel-principal approach. |
commands/verify_test.go |
Updates expectation to include principals="guest,dev" in the returned authorized_keys line. |
commands/login.go |
Changes issued cert principals from empty to a sentinel value (opkssh-wildcard). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
renovate Bot
added a commit
to sdwilsh/ansible-playbooks
that referenced
this pull request
Apr 28, 2026
##### [\`v0.14.0\`](https://github.com/openpubkey/opkssh/releases/tag/v0.14.0) Adds support for sshing into windows servers. Openssh 10.13 makes a breaking, non-backwards compatible change to how ssh certificates work, this breaks opkssh older than this release. This release creates a fix for this breaking change. ##### Changes - feat: update to openpubkey 0.23.0 [@ianroberts](https://github.com/ianroberts) ([#510](openpubkey/opkssh#510)) - fix(ci): use `go run .` instead of `go run main.go` in gha workflow [@fdcastel](https://github.com/fdcastel) ([#506](openpubkey/opkssh#506)) - \[3/3] Add Windows SSH server support [@fdcastel](https://github.com/fdcastel) ([#480](openpubkey/opkssh#480)) - refactor: unify MockUserLookup into shared test helper package. Closes [#439](openpubkey/opkssh#439). [@fdcastel](https://github.com/fdcastel) ([#495](openpubkey/opkssh#495)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#500](openpubkey/opkssh#500)) - feat: add --inspect-cert and --verbose flags to login command. Closes [#353](openpubkey/opkssh#353). [@fdcastel](https://github.com/fdcastel) ([#497](openpubkey/opkssh#497)) - docs: Add GitHub Actions integration guide. Closes [#481](openpubkey/opkssh#481) [@fdcastel](https://github.com/fdcastel) ([#492](openpubkey/opkssh#492)) - test: cover full printed output of opkssh inspect. Closes [#356](openpubkey/opkssh#356) [@fdcastel](https://github.com/fdcastel) ([#493](openpubkey/opkssh#493)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#498](openpubkey/opkssh#498)) - Add `logout` command to remove opkssh-generated SSH keys. Closes [#317](openpubkey/opkssh#317). [@fdcastel](https://github.com/fdcastel) ([#496](openpubkey/opkssh#496)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#490](openpubkey/opkssh#490)) - \[2/3] Add permissions command [@fdcastel](https://github.com/fdcastel) ([#479](openpubkey/opkssh#479)) - bug: ensure provider arg doesn't skip remote-redirect-uri [@EthanHeilman](https://github.com/EthanHeilman) ([#471](openpubkey/opkssh#471)) - \[1/3] Update GitHub Actions workflows and .gitignore [@fdcastel](https://github.com/fdcastel) ([#478](openpubkey/opkssh#478)) - docs: Add AWS EC2 setup guide for opkssh [@Rishang](https://github.com/Rishang) ([#467](openpubkey/opkssh#467)) ##### 🐛 Bug Fixes - fix(deps): Update docker/build-push-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#512](openpubkey/opkssh#512)) - Fix for openssh 10.13 breaking principals wildcard in SSH certificates [@EthanHeilman](https://github.com/EthanHeilman) ([#513](openpubkey/opkssh#513)) - fix(deps): Update zizmorcore/zizmor-action action to v0.5.2 @[renovate\[bot\]](https://github.com/apps/renovate) ([#488](openpubkey/opkssh#488)) - fix(deps): Update dependency golangci/golangci-lint to v2.11.2 @[renovate\[bot\]](https://github.com/apps/renovate) ([#486](openpubkey/opkssh#486)) - fix(deps): Update goreleaser/goreleaser-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#484](openpubkey/opkssh#484)) - fix(deps): Update goreleaser/goreleaser-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#477](openpubkey/opkssh#477)) - fix(deps): Update actions/setup-go action to v6.3.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#482](openpubkey/opkssh#482)) - fix(deps): Update zizmorcore/zizmor-action action to v0.5.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#451](openpubkey/opkssh#451)) - fix(deps): Update Docker @[renovate\[bot\]](https://github.com/apps/renovate) ([#464](openpubkey/opkssh#464)) ##### 🧰 Maintenance - Improve install script to make linter happy, fix typo [@EthanHeilman](https://github.com/EthanHeilman) ([#514](openpubkey/opkssh#514))
sdwilsh
pushed a commit
to sdwilsh/ansible-playbooks
that referenced
this pull request
Apr 30, 2026
##### [\`v0.14.0\`](https://github.com/openpubkey/opkssh/releases/tag/v0.14.0) Adds support for sshing into windows servers. Openssh 10.13 makes a breaking, non-backwards compatible change to how ssh certificates work, this breaks opkssh older than this release. This release creates a fix for this breaking change. ##### Changes - feat: update to openpubkey 0.23.0 [@ianroberts](https://github.com/ianroberts) ([#510](openpubkey/opkssh#510)) - fix(ci): use `go run .` instead of `go run main.go` in gha workflow [@fdcastel](https://github.com/fdcastel) ([#506](openpubkey/opkssh#506)) - \[3/3] Add Windows SSH server support [@fdcastel](https://github.com/fdcastel) ([#480](openpubkey/opkssh#480)) - refactor: unify MockUserLookup into shared test helper package. Closes [#439](openpubkey/opkssh#439). [@fdcastel](https://github.com/fdcastel) ([#495](openpubkey/opkssh#495)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#500](openpubkey/opkssh#500)) - feat: add --inspect-cert and --verbose flags to login command. Closes [#353](openpubkey/opkssh#353). [@fdcastel](https://github.com/fdcastel) ([#497](openpubkey/opkssh#497)) - docs: Add GitHub Actions integration guide. Closes [#481](openpubkey/opkssh#481) [@fdcastel](https://github.com/fdcastel) ([#492](openpubkey/opkssh#492)) - test: cover full printed output of opkssh inspect. Closes [#356](openpubkey/opkssh#356) [@fdcastel](https://github.com/fdcastel) ([#493](openpubkey/opkssh#493)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#498](openpubkey/opkssh#498)) - Add `logout` command to remove opkssh-generated SSH keys. Closes [#317](openpubkey/opkssh#317). [@fdcastel](https://github.com/fdcastel) ([#496](openpubkey/opkssh#496)) - Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#490](openpubkey/opkssh#490)) - \[2/3] Add permissions command [@fdcastel](https://github.com/fdcastel) ([#479](openpubkey/opkssh#479)) - bug: ensure provider arg doesn't skip remote-redirect-uri [@EthanHeilman](https://github.com/EthanHeilman) ([#471](openpubkey/opkssh#471)) - \[1/3] Update GitHub Actions workflows and .gitignore [@fdcastel](https://github.com/fdcastel) ([#478](openpubkey/opkssh#478)) - docs: Add AWS EC2 setup guide for opkssh [@Rishang](https://github.com/Rishang) ([#467](openpubkey/opkssh#467)) ##### 🐛 Bug Fixes - fix(deps): Update docker/build-push-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#512](openpubkey/opkssh#512)) - Fix for openssh 10.13 breaking principals wildcard in SSH certificates [@EthanHeilman](https://github.com/EthanHeilman) ([#513](openpubkey/opkssh#513)) - fix(deps): Update zizmorcore/zizmor-action action to v0.5.2 @[renovate\[bot\]](https://github.com/apps/renovate) ([#488](openpubkey/opkssh#488)) - fix(deps): Update dependency golangci/golangci-lint to v2.11.2 @[renovate\[bot\]](https://github.com/apps/renovate) ([#486](openpubkey/opkssh#486)) - fix(deps): Update goreleaser/goreleaser-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#484](openpubkey/opkssh#484)) - fix(deps): Update goreleaser/goreleaser-action action to v7 @[renovate\[bot\]](https://github.com/apps/renovate) ([#477](openpubkey/opkssh#477)) - fix(deps): Update actions/setup-go action to v6.3.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#482](openpubkey/opkssh#482)) - fix(deps): Update zizmorcore/zizmor-action action to v0.5.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#451](openpubkey/opkssh#451)) - fix(deps): Update Docker @[renovate\[bot\]](https://github.com/apps/renovate) ([#464](openpubkey/opkssh#464)) ##### 🧰 Maintenance - Improve install script to make linter happy, fix typo [@EthanHeilman](https://github.com/EthanHeilman) ([#514](openpubkey/opkssh#514))
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OpenSSH 10.3/10.3p1 made a backwards compatibility breaking change that may be causing OPKSSH certificates to fail.
https://www.spinics.net/lists/openssh-unix-dev/msg10392.html
This breaks OPKSSH, because OPKSSH relies on the wildcard behavior of the empty principal in user SSH certificates.
OPKSSH:
Because we don't know the desired principal at ssh certificate issuance time and the user may use the certificate for multiple principals, we must rely on the principal flag being empty as a wildcard.
The fix
Gemini 3 pro proposed the following fix.
opkssh-wildcard, rather than leave it empty. This prevents newer versions of OpenSSH from automatically failing the SSH cert for having an empty principal.opkssh verifyreturncert-authority,principals="opkssh-wildcard" <ca-key>instead ofcert-authority <ca-key>. Setting principals in the response short circuits sshd's check that principal matches the linux username the user is attempt to assume. The reason you can put principals in the response is that AuthorizedKeysCommand output is treated as an AuthorizedKeys file and AuthorizedKeys files have this behavior.This fix allows SSH certificates to function as a wildcard again. Very clever Gemini.