Storing secure information

We often hear from users, that they want to store “secure information” like password, keys, which should not be shown plain text on the UI. Even on the database, they should not be stored as plain text.

For Katello we already have Content Credentials: https://github.com/Katello/katello/blob/master/app/models/katello/content_credential.rb

This can store GPG Keys and SSH Keys - but no passwords or other “secure information” which can be re-used in foreman.

For cloning roles from VCS in foreman_ansible (Fixes #36971 - GUI to allow cloning of Ansible roles from VCS by Thorben-D · Pull Request #676 · theforeman/foreman_ansible · GitHub) it would also be very nice to have authentication available, which would be ssh-key or username/password.

What do you think about
a) moving Content Credentials from Katello to Foreman, extend the functionality so that it can store username/password or other “secure information” and make it therefore available for all foreman plugins
b) implement something completely new so that it can store secure information

Any ideas are highly appreciated.

2 Likes

Maybe they could be encrypted with the system /etc/foreman/encryption_key.rb that is used to store passwords encrypted in the database today.

2 Likes

In Katello we’re in planning stages to remove all our pages that use AngularJS, and redesign and/or rewrite them in React and modern Patternfly. Content Credentials is one of them, so this update could be in tandem with that.

So now there are two questions:

  1. Should Content Credentials be extended, or should a new entity be created that deals only with secrets?
  2. Where should the code live? Should it stay in Katello or move to Foreman?

For #2 I think it’s clear that the new capabilities should live in Foreman, since that way any plugin will be able to benefit. Assuming the code is in Foreman, I’m slightly leaning toward making a new entity, since that seems cleaner to me. But would be good to get some more inputs and opinions.

Give as a final go for Foreman and we will start with it pretty soonish as we need it for the foreman_ansible git story. :grin:

I’m proposing option c) and use the existing solution that @nixfu already hinted at.

For values in the DB, this is the way to go. We have EncryptValue for a low level implementation (used in Setting where only certain settings are encrypted) and the more generic Encryptable if you always want to encrypt a column (like the account_password field on AuthSourceLdap).

Fascinatingly, ContentCredentials are not using this encryption while other parts in Katello are. I think this is a bug.

Given ContentCredentials store public keys, there is nothing to encrypt there.

1 Like

Ah yes, fair point. The name credential implies it has a credential, but it’s only to verify credentials.

It stores ssh key as well.

The idea behind this is, to have a storage in foreman which can store ‘somehow sensible data’. Ok, in case of gpg public keys this is not really sensible…

If there is a way to store username/password, ssh keys in general, other plugins can just use this functionality.

But I would also be happy to use a solution which encrypts the data so that it gets never shown plain text in logs, UI, etc.

The first idea was to add a new functionality in foreman which is able to store “sensitive” data - like passwords, keys, etc. Everything a user may want to be stored encryped in the DB. It’s something like a key:value storage.

This kind of data can then be used in host parameters, ansible variable, provisioning templates or by certain plugins. Instead of defining username/password for each Katello repository, it may be nice to select a foreman sensitive data entitiy which provides username/password. In case you want to change the credentials, you would do this in one central place.

This new entitiy could then be used by e.g. Fixes #36971 - GUI to allow cloning of Ansible roles from VCS by Thorben-D · Pull Request #676 · theforeman/foreman_ansible · GitHub to store the username/password or ssh key for the communication to the git server.

Does this make sense? If you think, this is nonsense - I’m happy to receive such a feedback. Then we need to find a better solution for the foreman_ansible git extension to have authentication. Just let me know other possibilities.

I don’t think this makes sense. We already have a mechanism to store columns encrypted. Why complicate it further by introducing a centralized model?

Can you give an example where this would be reused and it’s easier than to implement a specialized model?

In Katello the SSH credentials are irrelevant, so you would have to write code to filter it out again. For completeness, this is how Katello makes sure the repository credentials are encrypted:

In the API it is not presented, but instead a special field is shown whether it exists:

2 Likes

I think the Encryptable module we have in core is a good one, but also very low level. I guess having a model you can ask for a secret by name would be a nice dev’s syntax sugar that could use Encryptable under the hood.

What I like in particular on it is, that the encryption key is stored outside of the DB, where the encrypted data lives. The entire system would have to be compromised to decrypt those secrets. What I don’t like about that approach is, it’s not reusable in external systems, e.g. when the secret needs to be passed to dynflow or smart proxy (e.g. ssh key passphrase for scheduled remote execution job). For that, some external system may be more useful, but I’d love to avoid adding more complexity to our stack unless necessary.

Something like Hashicorp Vault might be a solution for those use cases, but as you say, it comes with a non-trivial added complexity. This is why we’ve traditionally relies on someone (AKA, the admin) provisioning the Smart Proxy with secrets if it needs to. For REX the SSH key lives on the Smart Proxy. It could be reused for VCS cloning. That probably wouldn’t work for username/password so it’d need a different solution.

I was more after passphrase for those keys. That was an example of something that we need to store securely for until the execution happens. Vault/OpenBao was the first thing that came to my mind, but I think it’s too heavy for our current needs.

We can revive GitHub - theforeman/smart_proxy_vault: Hashicorp Vault plugin for Smart Proxy if there’s a need for it.