RFE: Add support for secrets in Remote Execution

Currently there is no good way to pass secrets to a Remote Execution job. All the information that is passed as an input, or even rendered directly by the template can be read from Foreman’s UI.

Add a new type for inputs to indicate that the input is a secret.
Values for those inputs would be encrypted before it’s stored.
They will be transferred to the Smart Proxy as encrypted and decrypted there.
The decrypted value would be injected as an ENV variable for both Ansible and Script job types.
Ideally the values would be encrypted with the relevant Smart Proxy public key, so only the proxy would be able to decrypt those values.

@Bernhard_Suttner Would be interesting to hear if this strategy (injecting ENV variables) will also work for Salt-based job types.

Very good idea. thank you very much.

Its possible to read salt environments: salt.modules.environ

The discussion has a slightly different target but there are some important notes: Storing secure information

  • like, how to store them - using encrypted with the system /etc/foreman/encryption_key.rb
  • use Encryptable module we have in core

It would be a bit more complicated than using the encrypted column, since we need to decrypt the value in the proxy (as opposed to decrypting it in the Foreman server process). Of course we can pass the decryption key to the proxy as a method parameter, but I find it less secure and prone to key exposure.

Would we? In my mind

  • the inputs would be encrypted using Encryptable
  • once proxy is selected, the inputs would be decrypted and then encrypted again for that single particular proxy

We cannot really encrypt them for a specific proxy before the job starts running because we don’t know in advance which proxy will be used for the job

Well in this case it would be actually both:

  1. encrypt them for storage (using Encryptable)
  2. Encrypt them for transport (proxy).

For 1 I suppose we will need to encrypt only parameters of a certain type, meaning Encryptable won’t fit, unless we extend it with a conditional option (which is not a bad thing).
As for transport - that would be yet another can of worms.

We already connect to proxies using HTTPS. In theory you could figure out the public key from the proxy, but that feels redundant.

Are env vars really a good idea? They often get dumped in process traces. https://www.redhat.com/sysadmin/ansible-playbooks-secrets describes passing them in an encrypted store. Not sure how much sense that makes, but it I’d lean to that.

Another aspect where I don’t know Ansible well enough, but in Puppet you have Sensitive as a type that shows up in logs as [redacted] and file diffs aren’t shown (because they can contain sensitive data). How does Ansible handle this?

Ansible’s concept is a bit different here as it does not protect the data itself but instead it protects the output of commands where possible the data are showing up (in the end it should be more or less the same for our use cases):

If you would want to protect the data Ansible Vault would be the way to go as shown in the link you provided, but here is also the link to the official docs:

From my understanding Ansible Vault meant to store variables on disk in a secure manner.
Here the problem is different - we are trying to protect the values from being stored in Foreman as plain text and then treated as non-secure data (being logged e.t.c.). I think the no-log directive is closer concept in the Ansible world.

Another problem that will need solving is non-ansible executors like Salt and Bash. We will need a generic way to pass secrets to all three executors. In my opinion ENV is a good compromise here, since it’s ubiquitous for all executors.

Is it the only way we can connect to a proxy? If it is, it makes our lives much easier and we can pass the secrets as parameters to the smart proxy call (as long as we don’t log it of course). If we still have a way to define HTTP proxies, we will need to make sure we do pass a secret somehow to the proxy.

Technically Foreman supports plain text HTTP, but I think it’s rare that it’s deployed that way. We should consider the Foreman ↔ Foreman Proxy as a trusted channel. Our threat model doesn’t account for it being compromised.

Great, then let’s go with parameters for the Foreman ↔ Proxy part.