Why do we use write_only fields?

I remember before RBAC we used write_only fields because we had to (we had no RBAC). Now with RBAC it doesn’t make sense why we would continue doing that. It’s much less useful for users. Here’s my argument in favor of discontinuing that practice.

If a user is authorized to read all attributes of an object (RBAC enabled) and the connection is TLS wrapped (the default) why shouldn’t they read all attributes?

There are two concerns driving this:

  • We need to make Pulp as simple as possible.
  • A user who isn’t sure if the password is set correctly can’t even check it.

This design aspect is coming up now because now we’d need to make a “generalized” version of that for this PR.

I can try to make an argument for write_only fields, but I’m not sure I’m the right person to do so.

Basically pulp stores a lot of important credentials. The same credentials that are used for pulling content from galaxy.ansible.com or quay could also be used to perform a supply chain attack if they were stolen. Exposing these credentials on the API opens us up the possibility of a pulp admin getting their account stolen (through password reuse, phishing, or whatever) and having all these sensitive credentials get stolen because the thief can just download them from the remotes API. By encrypting them and not exposing them on the API, the thief would have to get access to the pulp server and steal the DB credentials and decryption key, which is a lot harder to do.

Exposing credentials also makes other mistakes a lot more punishing. If an admin misconfigures RBAC, there’s a much higher chance of a serious data breach if users can pull all the remote credentials from the API.

On the flip side, I don’t see a solid benefit to returning credentials on the API other than simplicity. Pulp isn’t a password manager. If you need to remember a password, you should have a separate tool for that.

I may also add: If you are allowed to see and use a remote, this does not imply you are entitled to know the credentials. Instead, I think it is very handy that you can configure a remote with higher privileges and allow someone with less privileges to use it for synching.
One may now think that we could protect sensible credentials by moving them into another separately protected entity. But really, the username/password/client-cert must be kept with the server address (and therefore on the same remote model) to prevent someone redirecting the sensible information to his fake server.
From the REST perspective, having write-only fields is a rather clear no-no to using PUT operations, but that is not so much of an issue, imho.

One thing we might be discussing: Do we want to show the protected fields only in case a user has the permission to write them?
This may lead to polymorphic serializers, and i do not yet know, how all the client libraries react to that.

@x9c4 https://github.com/pulp/pulpcore/issues/2825

We’re working on serializer fields to communicate when write only fields are set.

The choice between usability and security is clear here. I am seeing several folks arguing for the importance of the write_only feature set, and without users making usability arguments against that I’m inclined to accept and continue the practice of write_only.

+1 to the PR https://github.com/pulp/pulpcore/issues/2825

+1 to figuring out how to make the data stored from this feature. It seems to be a requirement then.

Thank you for the discussion.

1 Like

One thing we might be discussing: Do we want to show the protected fields only in case a user has the permission to write them?

If you have permission to update, say, a Remote, you can break it whether you can read a password or not. I can, for example, update the URL to be Bad, and the remote stops working. So if you have update-access, you’re a security-risk - but in a way that is noticeable. “Hey, why did my syncs stop working” is a DoS, that can be observed and fixed.

The advantage of not-displaying sensitive fields, even to people who could change them, is someone who gets Adam-Admin’s access to the Pulp API can break Adam’s remotes, but cannot steal Adam’s secrets without anyone knowing.

So my security-hat says no - if we’re concerned about this scenario, then we can’t let sensitive fields be visible from the API, no matter who asks.

(NB: if you have acquired shell-access to the Pulp instance, with an account that’s allowed to see config-files, talk to postgres, and/or run pulpcore-manager, then we’re done - but that’s a reality we can’t do much about)

1 Like

I agree with your “no”. Just for completeness, i think if you can manage to redirect the url of a remote to a malicious server, you can make it give you the password, or you can at least pose as a man in the middle. But at least that needs a lot more work than “Oh, look that’s their password…”.

It just occurred to me that if you can update a remote you can still steal all the credentials on that remote by updating the URL to a custom server that logs the credentials for you. For example with pulp ansible I could create a service that logs the headers to steal a user’s token. I guess this really only protects credentials from users who may accidentally get read access (while also making it more difficult for users with write access to steal credentials).

Yes having write permissions does mean you can steal credentials by having Pulp submit them to an untrusted server, but it’s an unavoidable aspect due to Pulp submitting them, which it has to do. The value proposition of write_only is still pretty thin to me because it’s only useful if a user doesn’t have write perms, which is a small number of cases (I think).