API key in the config

I was implementing some improved LDAP stuff and one thing led to another… So short question, do any of the official integrations every read the API key in the config.xml? @canton7 @Nutomic @kozec @AudriusButkevicius @Catfriend1 @xor-gate

The reason I’m asking is that I ended up having to implement encrypting secrets in the config (because we would be storing a sensitive LDAP bind password). This should then naturally also cover the API key.

The key would still be available through the GUI and API, just not by eyeballing the config.xml…

I’m hoping the integrations do it the other way and set their own API key via the environment before startup… (Or have the user enter it manually, which would work equally well after this change as the user can still see it in the GUI.)

Not me - I set my own in the environment.

1 Like

I need to check the wrapper code, from my mind syncthing Android sets the gui user and password to syncthing/api_key and fetches the api key on first app start to set the password from config.xml . So yes, this has to be adjusted then.

Syncthing-GTK reads api key from config. Changing it so it uses environment variable is not a problem, but it will not be able to work with syncthing that was started independently (for example as part of session startup) anymore.

Yeah… I think the two reasonable “modes” are “manager by the wrapper” in which case you decide the API key, and “not managed by the wrapper” in which case the user needs to enter the API key. The latter is somewhat of a regression user experience wise I guess.

We can also decide that we don’t want to do this if the convenience of having an unencrypted API available outweighs the alternatives. But in the long run I’d even want the API key to be a hash, so I think reading it should probably become deprecated behavior anyway. Even if we don’t make it impossible to do so right now…

Please bear in mind that the following comes from a pretty naive standpoint security wise - so more in the lines of “help me understand” than critique.

How do I access the REST api when not starting Syncthing with an env var?
I am asking because I have an alias that grabs the API key from the config such that I only need to type the actual query url and can omit all the other necessary curl flags. I guess it’s also relevant for headless systems that are controlled through rest.

And a completely naive question: How does this add security? I’d expect anyone that has access to my ~/.config to also have access to all the data that user has access to. I also store secrets in ~/.ssh'/~/.gnupg/~/.credentialsin plaintext (with0700` perms), which I picked up from security affine instructions (at least I’d expect that for anything related to pgp).

Also if I understand the PR correctly the key is ~/config/syncthing/key.pem - how is that more save than the config itself?

Yeah the keypair is exactly as safe as the config, and the API key isn’t useful outside of its context, which is why it hasn’t been a huge deal up to this point. What makes the config somewhat less secure than the keypair is that it’s a reasonable debugging step to ask to see the config, it might get sent in email in order to help bootstrap another device, etc. In these cases leaking the API key may be a problem. Leaking things like an internal LDAP password would be a problem.

So I’m not 100% insistent that we do this for the API key. It was just a natural conclusion from implementing the encryption anyway, and from the general principle that passwords in plaintext are bad, and the API key is essentially a password.

You get the API key from somewhere else, such as the user. In the same way that you give anything else an API key (that doesn’t do the oauth dance).

The typical flow on web sites is that you generate a key, give it a name so you know what it was for, and you get to see it exactly once. The site treats it like a password and saves the hash, and from that moment on you can just see that the key exists, when it was generated, and what the name you gave was. That’s what I would like to do in Syncthing as well, I just haven’t been arsed to do the UI for it.

Thanks for the explanation!

What’s the reason to use encrypted config elements instead of separating secret from public stuff in the config, e.g. have a file named api-key or something containing the api key? I guess the LDAP password might even be used by other tools as well, so there may already be such a file containing the password, so Syncthing needn’t be concerned with how to store it at all in this case.

Putting it in the config just came from the fact that it’s already in the config so it’s the easiest place. :slight_smile: I guess we could have a binary blob syncthing-secrets.dat or something, that’d actually be easier in some respects, and there are platform specific secrets stuff, like Keychain on macOS, but interacting with all of those doesn’t sound like fun.

My Syncthing Tray works in the “not managed by the wrapper” way because that is the way I prefer. But it reads the key only for convenience so that should not be a problem. Only the Dolphin integration would need to be extended so the user can enter the key manually.

1 Like

On startup of the macOS wrapper we sync the config.xml secret to the application settings see https://github.com/syncthing/syncthing-macos/blob/48a909c6cb0d5660df3756ca6517eb8f7ba67b9b/syncthing/STApplication.m#L83

And we support API (and remote URL) given by the user. We need to find a way to make it really drag-and-drop without user not even knowing on macOS the GUI is split from the daemon.

MacOS case can typically use the api key in the environment I think. That said, my proposed change for this is on hold so there’s no rush.