On rotation keys...

... and PDS implementations.

AngryDutchmanOct 22, 2026

So, part of the series I guess I'll be starting, with the first post here - the recap: For a SaaS deployment, the reference PDS has issues. Tranquil has issues. Everything has issues. Aiming to fix that by adding yet another PDS implementation to the Atmosphere designed from the ground up to be suitable for SaaS style deployments.

To get it out of the way right here: the design was different a few hours ago, but has since changed to what will be described further down - mostly because the problem I was initially trying to solve wasn't getting solved by it's solution, and was by and large trying to work around the limitations that exist today (but more on that also, below).

A little on architecture...

My PDS implementation (currently dubbed "Shiftwind") isn't like any other (he said, while being a lot like every other). The normal situation is: 1 PDS binary/app/executable serves, well, 1 PDS. Shiftwind is different in that the executable serves many PDSes all at once. Referred to as a "PDS instance" - a PDS instance doesn't actually physically exist, it's a collection of database rows. But for all intents and purposes, it exposes the proper XRPC endpoints on it's own domain(s), and acts like any other PDS does.

Why? Because this lets me scale it horizontally. Meaning that if queries get slow? Add more hardware and replicated DB readers. If it can't handle the number of requests coming in? Run more copies of the executable.

The added benefit is that it lets me offer a single-user PDS that will cost next to nothing to run because it takes up next to no memory - no overhead of an entire node/typescript runtime, for example. Ergo, cheap!

So the tl:dr; a PDS instance doesn't exist as a separate thing, it's just a collection of data in a database with some strict and opinionated code in front of it that isolates everything so a user on instance Bob can't actually do anything with instance Alice since well, that user doesn't "exist" there.

Rotation keys

Rotation keys are still a hot topic; mostly because the number of people who have "added their own" is still in the single-digit percentage - if not actually below 1%. Why is this important? Well, a rotation key can sign PLC operations - meaning, it can alter your identity document. This is what happens when you migrate to another PDS - as part of the migration process, your "old" PDS signs the operation data that makes your identity point to the new PDS - and coincidentally removes the old PDS' rotation keys and adds the new PDS' keys to the list of keys that are allowed to sign PLC operations, and your new PDS submits it.

All fine and dandy, but suppose your old PDS is gone? Either you fat-fingered and deleted it, or whoever owned it decided to boogie, or some catastrophic disk failure ate the whole thing? Well, then you're screwed because you can't migrate. There is no old PDS to sign things for you. Unless... you have added your own - often referred to as a recovery key. But this process is, well, if you're in IT or work in an IT adjacent field, you can do it - Joe Q Average User? Heh, good luck with that.

The rotation key surface problem

So. The reference PDS (the one Bluesky uses) has a single rotation key configured, by it's operator. This means the operator has the private part of the public/private pair - because well, they generated it. This rotation key (or rather the public part of it) is what goes in your identity document. Now, the problem is that every user on that PDS receives the same rotation key. Granted, the PDS itself needs to be able to sign operations for migrations, but the operator has it as well.

And while 99.999999% of them are undoubtedly well intentioned, maybe one day an operator decides fuck it, and uses that key to sign a bunch of PLC operations to literally yoink your identity away from you.

And that is, again, where having "your own" rotation (recovery) key comes in - if you have your own rotation key (and you did it right in that it appears earlier in the list than the PDS' key), you have 72 hours to use that key to un-do any changes.

Shiftwind's difference

It generates a private/public keypair for you when an account is first created on a PDS instance - it's just for you, and different from any others on a PDS instance. The PDS instance operator? They can't see it. Or retrieve it. Neither can whoever operates Shiftwind, and neither can the user.

This is a departure from my initial design, which would allow a user to expose the private part of the key that was generated for them; this has changed, mostly due to Emelia making some very on-point comments. The rationale for this initial design was more to do with the idea that most users don't add a recovery key, or have any idea what it is or does, and that in the end, a single PDS instance owner who decides to moonwalk away shouldn't leave their users holding the bag of kaka. But, the points were very on-point, so the design changed!

What the user can do now, is that either they use a PDS migration tool that offers them the option to add a recovery key (PDS Moover does this), or, if they chose not to, Shiftwind allows them to add one via it's own user UI - using WebCrypto, so the private key only ever gets downloaded to the users' device while the public part is made part of the PLC document. Okay, granted, there'll be external tools that can do it too but they too will be using the same mechanism and just tell Shiftwind about the new public key part that needs to be horked into the DID doc.

For entirely new accounts, the XRPC call already provides the option to pass in a recovery key during creation, but this would require that whatever is creating the account actually passes a valid key along. So while it will be used when given, it's not mandatory. Yet. Maybe.

As to why nobody can see the key, or should see it

Because if a user has a recovery key, there is no need to actually see whatever key Shiftwind is using to "do the thing(tm)". As a user, you can always use your recovery key to sign a PLC operation and re-claim/un-fuck your identity. And with the rotation key surface being a whole lot smaller? Chances are you won't need to, not unless whoever owns the PDS instance on Shiftwind has decided to just run away and point their domains elsewhere, at which point, well, not much we can do about that - and that's where the recovery key comes in.

Granted the initial design did allow for that "expose the key" bit so even in that event a user could migrate away, buuut... how does the user know to go to Shiftwind (or peedee.es for that matter) to get it? So that solution wasn't solving anything, it just created "yet another problem".

Closing remarks

With the changed design, strictly speaking only the software (Shiftwind) knows a key, and the user still holds all the aces up all the sleeves with their recovery key - the only drawback with that being that if a PDS operator walks away from their Shiftwind PDS instance and points their domains elsewhere, we can do Jacques Sheet about it to assist the user if they have not created a recovery key.

The reference PDS using the same rotation key for all of it's accounts, it's a choice. Not the best choice, in my opinion, due to the trust required in a PDS operator to not go all Evil McEvilson. And of course the whole "if it's leaked it's not a single user but many" bit.

Striking a balance between giving a user freedom and security and operational needs (or wants) is tricky; especially on account of that security should never (from the user standpoint) be a burden or a painful experience - the second you sacrifice convenience for security, users will bail. Or hand-wave it. Or just phone it in - but sometimes from the security end of things you haven't got much choice. So finding that balance is important, even though it'll probably lead to it not being "the most ideal" solution out there.



Never miss a post

Get new writing sent to your inbox.

Subscribe

2