Skip to content

Add logout command to remove opkssh-generated SSH keys. Closes #317.#496

Merged
EthanHeilman merged 3 commits into
openpubkey:mainfrom
fdcastel:fix-317
Mar 26, 2026
Merged

Add logout command to remove opkssh-generated SSH keys. Closes #317.#496
EthanHeilman merged 3 commits into
openpubkey:mainfrom
fdcastel:fix-317

Conversation

@fdcastel
Copy link
Copy Markdown
Contributor

Adds a new opkssh logout command that finds and removes SSH keys and certificates previously generated by opkssh login. This addresses the feature request for an explicit way to "log out" / destroy SSH credentials.

Closes #317. Related: #311.

What it does

The logout command searches for opkssh-generated keys in two locations:

  1. Default SSH directory (~/.ssh/) — checks id_ecdsa, id_ecdsa_sk, id_ed25519, id_ed25519_sk and their -cert.pub counterparts. Only removes keys whose cert comment starts with openpubkey.
  2. opkssh identity directory (~/.ssh/opkssh/) — removes all opkssh-managed key pairs and cleans up the corresponding IdentityFile entries from ~/.ssh/opkssh/config.

A -i flag allows targeting a specific key pair by private key path.

Usage

# Remove all opkssh-generated keys
opkssh logout

# Remove a specific key pair
opkssh logout -i ~/.ssh/id_ecdsa

Safety

  • Keys not generated by opkssh (identified by the absence of an openpubkey comment prefix) are never touched.
  • If no opkssh keys are found, a message is printed and no error is returned.

Files changed

File Description
commands/logout.go New LogoutCmd struct and logic
commands/logout_test.go Tests covering default keys, opkssh dir keys, specific key removal, non-opkssh key safety, and multi-key scenarios
main.go Registers the logout cobra command

Adds a new 'opkssh logout' command that finds and removes SSH keys and
certificates generated by opkssh. This addresses the user request in openpubkey#317
for the ability to log out and destroy SSH certs.

The logout command:
- Scans ~/.ssh/ for default key files (id_ecdsa, id_ecdsa_sk,
  id_ed25519, id_ed25519_sk) and removes those with an 'openpubkey'
  comment
- Scans ~/.ssh/opkssh/ for opkssh-managed keys and removes them,
  cleaning up the config file entries
- Supports -i flag to target a specific key pair
- Safely skips keys not generated by opkssh

Closes openpubkey#317
Comment thread commands/logout.go

// LogoutCmd represents the logout command that removes opkssh-generated SSH keys and certificates.
type LogoutCmd struct {
Fs afero.Fs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any issues with Windows support here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ask me again after this PR goes in and I’ve rebased the Windows PR 😄

Comment thread commands/logout.go
Comment thread commands/logout.go
Comment thread commands/logout.go
Comment thread commands/logout.go Outdated
Comment thread commands/logout.go Outdated
Comment thread commands/logout.go
Changes based on review by @EthanHeilman:

- Validate cert matches secret key before deleting: verifyKeyPairMatch()
  compares the public key in the certificate against the secret key to
  prevent accidentally deleting a secret key when the public key has been
  overwritten with a different cert. On mismatch, prints warning to stderr
  and skips the key pair.

- Remove secret key first, then certificate: reversed deletion order so
  if an error occurs mid-way, the secret key won't be left orphaned on
  disk (the cert can still be used to find it).

- Share key file names with login: extracted DefaultSSHKeyFileNames map
  in login.go, used by both login and logout so adding a new key type
  to login automatically includes it in logout.

- Handle Windows line endings: removeFromOpkSSHConfig now normalizes
  \r\n to \n before splitting lines.

- Add verbose flag: -v/--verbose prints skip reasons to stderr for
  debugging (e.g. 'not generated by opkssh', 'could not read cert').

- Use 0o600 permission for config file writes (already correct, now
  documented in context).
Copy link
Copy Markdown
Member

@EthanHeilman EthanHeilman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@EthanHeilman EthanHeilman merged commit 472c6dd into openpubkey:main Mar 26, 2026
17 checks passed
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))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Request: Add ability to "log out"

2 participants