Sitelet https://github.com/kubernetes/kops/pull/18697
Skip to content

digitalocean: delete SSH keys when deleting a cluster - #18697

Merged
kubernetes-prow[bot] merged 1 commit into
kubernetes:masterfrom
rifelpet:do-delete-sshkeys
Aug 16, 2026
Merged

kubernetes-prow[bot] merged 1 commit into
kubernetes:masterfrom
rifelpet:do-delete-sshkeys

Conversation

@rifelpet

Copy link
Copy Markdown
Member

kops uploads an SSH key to the DigitalOcean account for every cluster (dotasks/sshkey.go createKeypair → KeysService().Create), naming it kubernetes.<cluster name>-<fingerprint> per pkg/model/names.go. But pkg/resources/digitalocean/resources.go only deletes droplet, volume, dns-record, loadbalancer and vpc — the SSH key is never removed.

AWS already cleans up its key pairs (pkg/resources/aws/aws.go DeleteKeypair, wired in at ListKeypairs), and OpenStack has pkg/resources/openstack/sshkey.go. DigitalOcean was the gap.

Why it hasn't bitten yet

Every DO CI job supplies the same SSH key through the preset-do-ssh prow preset, so the fingerprint — and therefore the key name — is identical on every run. SSHKey.Find matches the existing key and reuses it, and nothing accumulates.

That stops being true as soon as a cluster is created with a per-cluster key. It leaks one key per cluster, and because DigitalOcean scopes SSH keys to the account rather than to a cluster, they pile up with nothing identifying what they belonged to.

This is a prerequisite for kubernetes/test-infra#37690, which switches the DO e2e jobs to the ephemeral keys kubetest2-kops now generates (#18686). That PR is on hold until this ships.

Matching

Keys are selected on the kubernetes.<cluster name>- prefix. Two properties matter, and both are covered by tests:

  • The trailing hyphen is required. Without it, foo.k8s.local would also match keys belonging to foo.k8s.local.example.com. The concrete case in CI is e2e-kops-do-dns-none and e2e-kops-do-dns-none-ha, which run against the same account.
  • A cluster setting spec.sshKeyName is left alone. That key keeps a name kops did not choose, so it does not match the prefix — consistent with Find in dotasks/sshkey.go, which adopts such a key rather than creating one. Deleting a user's pre-existing key would be considerably worse than leaking one.

Deletion tolerates a 404 so a retried teardown is idempotent.

Testing

  • TestFilterClusterSSHKeys covers seven cases: the normal match, several stale keys from repeated runs of one cluster, a longer cluster name that must not match, the -ha sibling, an unrelated cluster, a user-named key, and the bare cluster name with no fingerprint.
  • go build ./..., go vet, and go test ./pkg/resources/... ./upup/pkg/fi/cloudup/do/... ./upup/pkg/fi/cloudup/dotasks/... all pass.

The listing follows the existing GetAllVPCs pagination pattern, and the DOCloud mock gains the matching no-op.

🤖 Generated with Claude Code

kops uploads an SSH key to the DigitalOcean account for every cluster
(dotasks/sshkey.go createKeypair) and names it after the cluster and the
key fingerprint, but the resource deleter only knows about droplets,
volumes, DNS records, load balancers and VPCs. The keys are never
removed.

This has gone unnoticed because the CI jobs all supply the same SSH key,
so the fingerprint -- and therefore the key name -- is identical on every
run and the existing key is found and reused. A cluster created with any
other key leaks one key per cluster into the account, and DigitalOcean
scopes SSH keys to the account rather than the cluster, so they
accumulate with nothing to attribute them to.

AWS already deletes its ephemeral EC2 key pairs
(pkg/resources/aws/aws.go DeleteKeypair) and so does OpenStack; this
brings DigitalOcean in line.

Keys are matched on the "kubernetes.<cluster name>-" prefix that
pkg/model/names.go gives them. The trailing hyphen is required so that
"foo.k8s.local" does not also match keys belonging to
"foo.k8s.local.example.com", and a cluster using spec.sshKeyName keeps a
name kops did not choose, so its pre-existing key is left alone.
@kubernetes-prow

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@kubernetes-prow kubernetes-prow Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 15, 2026
@kubernetes-prow
kubernetes-prow Bot requested review from hakman and olemarkus August 15, 2026 21:03
@kubernetes-prow kubernetes-prow Bot added area/provider/digitalocean Issues or PRs related to digitalocean provider cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 15, 2026
@rifelpet

Copy link
Copy Markdown
Member Author

/test pull-kops-do-dns-none

@rifelpet

Copy link
Copy Markdown
Member Author

This job exercised the DO ssh key creation and deletion successfully, so the PR is ready for review: https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kops/18697/pull-kops-do-dns-none/2088748301577883648

@rifelpet
rifelpet marked this pull request as ready for review August 15, 2026 23:12
@kubernetes-prow kubernetes-prow Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 15, 2026
@kubernetes-prow kubernetes-prow Bot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 15, 2026
@kubernetes-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: hakman

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubernetes-prow kubernetes-prow Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 15, 2026
@kubernetes-prow
kubernetes-prow Bot merged commit 09f1844 into kubernetes:master Aug 16, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/provider/digitalocean Issues or PRs related to digitalocean provider cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants