Compile a set of best practices for storing secrets #58

Open
opened 2021-11-20 11:25:17 +00:00 by ungleich-gitea · 4 comments

As has been discussed in #cdist:ungleich.ch last week I open a ticket to compile a set of best practises to be added to the manual on how to handle secrets in cdist.

Generally I think it's safe to say that for any possible solution:

  1. Secrets should be stored in encrypted or hashed (if possible) form.
  2. Secrets should be decrypted as late a possible.
  3. Plain-text secrets should not be permanently stored on both the config and target host (unless at their final location.)
As has been discussed in #cdist:ungleich.ch last week I open a ticket to compile a set of best practises to be added to the manual on how to handle secrets in cdist. Generally I think it's safe to say that for any possible solution: 1. Secrets should be stored in encrypted or hashed (if possible) form. 2. Secrets should be decrypted as late a possible. 3. Plain-text secrets should not be permanently stored on both the config and target host (unless at their final location.)
Author
Owner

mentioned in merge request cdist-contrib!19

mentioned in merge request cdist-contrib!19
Author
Owner

@fancsali The current situation is unsatisfactory for multiple reasons.

As far as the locations are concerned:

  • /var/lib/cdist on target
    The password will be left there on the target. The directory is only accessible to root, though.
    So given that the password is likely going to be readable by root anyway, I (personally) can live with that.
  • $TMPDIR on config host
    Does cdist clean up after itself? If not, it should.
  • tmp on target
    I don't think any other directory other than /var/lib/cdist (--remote-out-dir) is used on the target.
  • ~/.cdist/cache on config host
    Frankly, I don't know what this cache is used for. Couldn't it be disabled?

On a general note: cdist could do a better job cleaning up after itself.
This would reduce the life time of secrets being available on the file system.
RAM-Disks could be used wherever possible to make sure that nothing is left on the disk at any time.

All of this would be good style and should be considered, but I personally store my secrets GnuPG-encrypted because I want to be able to commit them to Git.
This is what bothers me: secrets being persistently stored on one server.
Temporary copies should be limited as much as possible, but:

  • if someone is root on the server → game over.
  • if someone can read (and possibly modify) files on "my" config host → pretty much game over, too.
    Who tells me that he won't modify any of the code to be executed on the target.
    Moreover, if he can run commands he has root permissions on the target, too.
@fancsali The current situation is unsatisfactory for multiple reasons. As far as the locations are concerned: - `/var/lib/cdist` on target The password will be left there on the target. The directory is only accessible to `root`, though. So given that the password is likely going to be readable by root anyway, I (personally) can live with that. - `$TMPDIR` on config host Does cdist clean up after itself? If not, it should. - `tmp` on target I don't think any other directory other than `/var/lib/cdist` (`--remote-out-dir`) is used on the target. - `~/.cdist/cache` on config host Frankly, I don't know what this cache is used for. Couldn't it be disabled? **On a general note:** cdist could do a better job cleaning up after itself. This would reduce the life time of secrets being available on the file system. RAM-Disks could be used wherever possible to make sure that nothing is left on the disk at any time. All of this would be good style and should be considered, but I personally store my secrets GnuPG-encrypted because I want to be able to commit them to Git. This is what bothers me: secrets being persistently stored on one server. Temporary copies should be limited as much as possible, but: - if someone is root on the server → game over. - if someone can read (and possibly modify) files on "my" config host → pretty much game over, too. Who tells me that he won't modify any of the code to be executed on the target. Moreover, if he can run commands he has root permissions on the target, too.
Author
Owner

I've been thinking about this and I reckon, we leave the keys in a few places after a run:

  • /var/lib/cdist
  • Some tmp location on the local machine
  • Perhaps some tmp on the server
  • And the local cache

... or is my understanding actually a misunderstanding?

I've been thinking about this and I reckon, we leave the keys in a few places after a run: * `/var/lib/cdist` * Some `tmp` location on the local machine * Perhaps some `tmp` on the server * And the local cache ... or is my understanding actually a misunderstanding?
Author
Owner

I handle secrets as follows:
In my .cdist I created a folder secret which represents a pass repository (PASSWORD_STORE_DIR=~/.cdist/secret pass init ...).

I have a shell function defined in manifest/init to retrieve passwords:

secret() (
	# Fetches and decrypts a secret from the secret store.
	# If no host is given the __target_host is used.
	# Usage:
	#  - secret foo
	#  - secret foo/bar
	#  - secret foo/bar myhost.example.com

	secret_name=${1:?'missing secret name'}
	host=${2:-${__target_host}}

	path="${__cdist_repo:?}/secret/${host}/${secret_name}.gpg"
	test -f "${path}" && gpg -q -d "${path}"
)

In cases where the password is stored in plaintext on the target, using a password is as simple as:

__type ... --password "$(secret mysecret)"

(This will temporarily copy the password to the target's /var/lib/cdist. This is not optimal but since the secret is stored in plain text anyway, I personally don't consider this too much of an issue.)

If the application on the target allows for encrypted or hashed storage of the secret (e.g. user passwords), another shell function can be used on the config host to transform the secret into the format required for the target application:

__user joe --password "$(secret joes_passwd | crypt_3 -f sha512 -s 'DFIKuYy/HjaL33r8')"
I handle secrets as follows: In my `.cdist` I created a folder `secret` which represents a [pass](https://www.passwordstore.org) repository (`PASSWORD_STORE_DIR=~/.cdist/secret pass init ...`). I have a shell function defined in `manifest/init` to retrieve passwords: ```sh secret() ( # Fetches and decrypts a secret from the secret store. # If no host is given the __target_host is used. # Usage: # - secret foo # - secret foo/bar # - secret foo/bar myhost.example.com secret_name=${1:?'missing secret name'} host=${2:-${__target_host}} path="${__cdist_repo:?}/secret/${host}/${secret_name}.gpg" test -f "${path}" && gpg -q -d "${path}" ) ``` In cases where the password is stored in plaintext on the target, using a password is as simple as: ```sh __type ... --password "$(secret mysecret)" ``` (This will temporarily copy the password to the target's `/var/lib/cdist`. This is not optimal but since the secret is stored in plain text anyway, I personally don't consider this too much of an issue.) If the application on the target allows for encrypted or hashed storage of the secret (e.g. user passwords), another shell function can be used on the config host to transform the secret into the format required for the target application: ```sh __user joe --password "$(secret joes_passwd | crypt_3 -f sha512 -s 'DFIKuYy/HjaL33r8')" ```
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: ungleich-public/cdist#58
No description provided.