diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3d1e3d8..69878ac 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -165,6 +165,10 @@ jobs: if: always() run: tests/config-reloader/test.sh + - name: Execute GPG tests + if: always() + run: tests/gpg/test.sh + - name: Cleanup if: always() run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9808a..e88a87a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ for the list of changes in SaltStack. **3005.1_2** +- Add support for GPG keys. - Ensure `salt-minion` is not installed. - Remove `GitPython` documentation, since it has some [using warnings](https://docs.saltproject.io/en/latest/topics/tutorials/gitfs.html#id2). diff --git a/Dockerfile b/Dockerfile index a159875..db17460 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,7 @@ WORKDIR ${SALT_BUILD_DIR} # hadolint ignore=DL3008 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install --yes --quiet --no-install-recommends \ - sudo ca-certificates openssl apt-transport-https wget locales openssh-client \ + sudo ca-certificates openssl apt-transport-https wget locales openssh-client gpg \ python3 python3-dev libpython3-dev \ python3-pip python3-setuptools python3-wheel \ supervisor logrotate git gettext-base tzdata inotify-tools psmisc \ diff --git a/README.md b/README.md index 289d64b..5a59080 100644 --- a/README.md +++ b/README.md @@ -426,6 +426,56 @@ Alternately, you may create a new RSA key with SHA2 hashing like so: ssh-keygen -t rsa-sha2-512 -b 4096 -f gitfs_ssh -C 'gitfs_rsa4096@example.com' ``` +### GPG keys for renderers + +Salt can use GPG keys to decrypt pillar data. This image is ready to import your GPG keys from the `gpgkeys` directory +inside the `keys` directory. + +The private key must be named `private.key` and the public key `pubkey.gpg`. + +If you want to provide these keys via secrets, you can set `SALT_GPG_PRIVATE_KEY_FILE` and `SALT_GPG_PUBLIC_KEY_FILE` +env variables to specify the path to the files inside the container. + +For example: + +```yml +SALT_GPG_PRIVATE_KEY_FILE: /run/secrets/private.key +SALT_GPG_PUBLIC_KEY_FILE: /run/secrets/pubkey.gpg +``` + +In this case, keys will be symlinked to the `gpgkeys` directory. + +It is important that the private key doesn't have passphrase in order to be imported by salt. + +To generate a GPG key and export the private/public pair you can use the following commands: + +```sh +# Generate key - REMEMBER: Leave empty the passphrase! +gpg --gen-key + +# Check GPG keys +gpg --list-secret-keys +gpg: checking the trustdb +gpg: marginals needed: 3 completes needed: 1 trust model: pgp +gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u +gpg: next trustdb check due at 2024-11-09 +/tmp/gpgkeys/pubring.kbx +-------------------- +sec rsa3072 2022-11-10 [SC] [expires: 2024-11-09] + CB032BA54F21722945FDDE399CE3DB8AE37D28B7 +uid [ultimate] Carlos Alvaro +ssb rsa3072 2022-11-10 [E] [expires: 2024-11-09] + +# Export public and private keys +mkdir -p keys/gpgkeys +KEY_ID=github@cdalvaro.io +gpg --armor --export "${KEY_ID}" > keys/gpgkeys/pubkey.gpg +gpg --export-secret-keys --export-options export-backup -o keys/gpgkeys/private.key "${KEY_ID}" +``` + +More information about this feature is available at the +[official documentation](https://docs.saltproject.io/en/latest/ref/renderers/all/salt.renderers.gpg.html). + ### 3rd Party Formulas You can add third party formulas to your configuration simply by adding them to your `gitfs_remotes`: @@ -623,6 +673,8 @@ installation. | [`SALT_MASTER_PUBKEY_SIGNATURE`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-pubkey-signature) | The name of the file in the master's pki-directory that holds the pre-calculated signature of the master's public-key. Default: `master_pubkey_signature`. | | `SALT_MASTER_PUBKEY_SIGNATURE_FILE` | The path of the salt-master public key file with the pre-calculated signature. It will be copied inside the pki directory if a file with name `SALT_MASTER_PUBKEY_SIGNATURE` doesn't exist. Useful to load the password from secrets. _Unset_ by default. | | `SALT_MASTER_ROOT_USER` | Forces `salt-master` to be run as `root` instead of `salt`. Default: `False`. | +| `SALT_GPG_PRIVATE_KEY_FILE` | The path to the GPG private key for GPG renderers. Useful to load the key from secrets. _Unset_ by default. | +| `SALT_GPG_PUBLIC_KEY_FILE` | The path to the GPG public key for GPG renderers. Useful to load the key from secrets. _Unset_ by default. | | [`SALT_REACTOR_WORKER_THREADS`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#reactor-worker-threads) | The number of workers for the runner/wheel in the reactor. Default: `10`. | | [`SALT_WORKER_THREADS`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#worker-threads) | The number of threads to start for receiving commands and replies from minions. Default: `5`. | | [`SALT_BASE_DIR`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#file-roots) | The `base` path in `file_roots` to look for `salt` and `pillar` directories. Default: `/home/salt/data/srv`. | diff --git a/assets/runtime/env-defaults.sh b/assets/runtime/env-defaults.sh index d1bc77d..200ca9a 100755 --- a/assets/runtime/env-defaults.sh +++ b/assets/runtime/env-defaults.sh @@ -29,3 +29,6 @@ SALT_MASTER_SIGN_PUBKEY=${SALT_MASTER_SIGN_PUBKEY:-False} SALT_MASTER_USE_PUBKEY_SIGNATURE=${SALT_MASTER_USE_PUBKEY_SIGNATURE:-False} SALT_MASTER_SIGN_KEY_NAME=${SALT_MASTER_SIGN_KEY_NAME:-master_sign} SALT_MASTER_PUBKEY_SIGNATURE=${SALT_MASTER_PUBKEY_SIGNATURE:-master_pubkey_signature} + +# Directory where GPG keys will be looking for +SALT_KEYS_GPGKEYS_DIR="${SALT_KEYS_DIR}/gpgkeys" diff --git a/assets/runtime/functions.sh b/assets/runtime/functions.sh index 7c75a84..68460a4 100755 --- a/assets/runtime/functions.sh +++ b/assets/runtime/functions.sh @@ -73,14 +73,14 @@ function map_uidgid() groupmod -o -g "${PGID}" "${SALT_USER}" sed -i -e "s|:${ORIG_PUID}:${PGID}:|:${PUID}:${PGID}:|" /etc/passwd find "${SALT_HOME}" \ - -not -path "${SALT_CONFS_DIR}*" \ - -not -path "${SALT_KEYS_DIR}*" \ - -not -path "${SALT_BASE_DIR}*" \ - -not -path "${SALT_LOGS_DIR}*" \ - -not -path "${SALT_FORMULAS_DIR}*" \ - -path "${SALT_DATA_DIR}/*" \ - \( ! -uid "${ORIG_PUID}" -o ! -gid "${ORIG_PGID}" \) \ - -print0 | xargs -0 chown -h "${SALT_USER}": "${SALT_HOME}" + -not -path "${SALT_CONFS_DIR}*" \ + -not -path "${SALT_KEYS_DIR}*" \ + -not -path "${SALT_BASE_DIR}*" \ + -not -path "${SALT_LOGS_DIR}*" \ + -not -path "${SALT_FORMULAS_DIR}*" \ + -path "${SALT_DATA_DIR}/*" \ + \( ! -uid "${ORIG_PUID}" -o ! -gid "${ORIG_PGID}" \) \ + -print0 | xargs -0 chown -h "${SALT_USER}": "${SALT_HOME}" fi } @@ -186,8 +186,8 @@ function _setup_master_keys() else if [ -n "${SALT_MASTER_KEY_FILE}" ]; then # If a master key is provided via SALT_MASTER_KEY_FILE, check it is the same as the one in the keys directory - if ! cmp -s "${SALT_MASTER_KEY_FILE}.pem" "${SALT_KEYS_DIR}/master.pem" \ - || ! cmp -s "${SALT_MASTER_KEY_FILE}.pub" "${SALT_KEYS_DIR}/master.pub"; then + if ! cmp -s "${SALT_MASTER_KEY_FILE}.pem" "${SALT_KEYS_DIR}/master.pem" || + ! cmp -s "${SALT_MASTER_KEY_FILE}.pub" "${SALT_KEYS_DIR}/master.pub"; then log_error "SALT_MASTER_KEY_FILE is set to '${SALT_MASTER_KEY_FILE}' but keys don't match the master keys inside '${SALT_KEYS_DIR}'." return 1 fi @@ -224,8 +224,8 @@ function _setup_master_sign_keys() else if [ -n "${SALT_MASTER_SIGN_KEY_FILE}" ]; then # If a master_sign key-pair is provided via SALT_MASTER_SIGN_KEY_FILE, check it is the same as the one in the keys directory - if ! cmp -s "${SALT_MASTER_SIGN_KEY_FILE}.pem" "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pem" \ - || ! cmp -s "${SALT_MASTER_SIGN_KEY_FILE}.pub" "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pub"; then + if ! cmp -s "${SALT_MASTER_SIGN_KEY_FILE}.pem" "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pem" || + ! cmp -s "${SALT_MASTER_SIGN_KEY_FILE}.pub" "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pub"; then log_error "SALT_MASTER_SIGN_KEY_FILE is set to '${SALT_MASTER_SIGN_KEY_FILE}' but keys don't match the master_sign keys inside '${SALT_KEYS_DIR}'." return 1 fi @@ -251,15 +251,85 @@ function _setup_master_sign_keys() fi } +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: _check_and_link_gpgkey +# DESCRIPTION: Check and link a gpgkey if env variable is set. +# ARGUMENTS: +# - 1: The name of the GPG env variable +# - 2: The target gpg file +#---------------------------------------------------------------------------------------------------------------------- +function _check_and_link_gpgkey() { + local GPGKEY_VARIABLE_NAME="$1" + local TARGET_GPGKEY="$2" + local SOURCE_GPGKEY="${!GPGKEY_VARIABLE_NAME}" + + [ -n "${SOURCE_GPGKEY}" ] || return 0 + + if [[ ! -f "${SOURCE_GPGKEY}" ]]; then + log_warn "'${GPGKEY_VARIABLE_NAME}' (=${SOURCE_GPGKEY}) is set, but file does not exist." + return 0 + fi + + if [[ -f "${TARGET_GPGKEY}" ]] && ! cmp -s "${SOURCE_GPGKEY}" "${TARGET_GPGKEY}"; then + log_error "'${GPGKEY_VARIABLE_NAME}' (=${SOURCE_GPGKEY}) is set and ${TARGET_GPGKEY} exists, but they dont match." \ + " Please, unset '${GPGKEY_VARIABLE_NAME}' or remove '${TARGET_GPGKEY}'." + return 1 + fi + + log_info "Linking '${SOURCE_GPGKEY}' to '${TARGET_GPGKEY}' ..." + ln -sfn "${SOURCE_GPGKEY}" "${TARGET_GPGKEY}" +} + +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: _setup_gpgkeys +# DESCRIPTION: Setup GPG keys. +#---------------------------------------------------------------------------------------------------------------------- +function _setup_gpgkeys() +{ + [[ -d "${SALT_KEYS_GPGKEYS_DIR}" && -n "$(ls -A "${SALT_KEYS_GPGKEYS_DIR}")" ]] || return 0 + + log_info " ==> Setting up GPG keys ..." + local private_key="${SALT_KEYS_GPGKEYS_DIR}/private.key" + local public_key="${SALT_KEYS_GPGKEYS_DIR}/pubkey.gpg" + + _check_and_link_gpgkey 'SALT_GPG_PRIVATE_KEY_FILE' "${private_key}" + _check_and_link_gpgkey 'SALT_GPG_PUBLIC_KEY_FILE' "${public_key}" + + if [[ ! -f "${private_key}" || ! -f "${public_key}" ]]; then + log_error "GPG keys are not valid. Please, check the documentation for more information:" + log_error " - https://github.com/cdalvaro/docker-salt-master#gpg-keys-for-renderers" + [ -f "${private_key}" ] || log_error "GPG private key: '${private_key##*/}' doesn't exist" + [ -f "${public_key}" ] || log_error "GPG public key: '${public_key##*/}' doesn't exist" + return 1 + fi + + log_info "Importing GPG keys ..." + + local SALT_GPGKEYS_DIR="${SALT_ROOT_DIR}"/gpgkeys + mkdir -p "${SALT_GPGKEYS_DIR}" + chown "${SALT_USER}:${SALT_USER}" "${SALT_GPGKEYS_DIR}" + chmod 700 "${SALT_GPGKEYS_DIR}" + + local GPG_COMMON_OPTS=(--no-tty --homedir="${SALT_GPGKEYS_DIR}") + + exec_as_salt gpg "${GPG_COMMON_OPTS[@]}" --import "${private_key}" + exec_as_salt gpg "${GPG_COMMON_OPTS[@]}" --import "${public_key}" + + log_info "Setting trust level to ultimate ..." + local key_id="$(exec_as_salt gpg "${GPG_COMMON_OPTS[@]}" --list-packets "${private_key}" | awk '/keyid:/{ print $2 }' | head -1)" + (echo trust & echo 5 & echo y & echo quit) | exec_as_salt gpg "${GPG_COMMON_OPTS[@]}" --command-fd 0 --edit-key "${key_id}" +} + #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: setup_salt_keys -# DESCRIPTION: Repair keys permissions and creates keys if neaded. +# DESCRIPTION: Repair keys permissions and creates keys if needed. #---------------------------------------------------------------------------------------------------------------------- function setup_salt_keys() { log_info "Setting up salt keys ..." _setup_master_keys [ "${SALT_MASTER_SIGN_PUBKEY}" == True ] && _setup_master_sign_keys + _setup_gpgkeys log_info "Setting up salt keys permissions ..." while IFS= read -r -d '' pub_key diff --git a/tests/gpg/README.md b/tests/gpg/README.md new file mode 100644 index 0000000..b217972 --- /dev/null +++ b/tests/gpg/README.md @@ -0,0 +1,5 @@ +# Salt GPG Renderer Tests + +Checks: + + - get gpg encrypted pillar. diff --git a/tests/gpg/keys/gpgkeys/private.key b/tests/gpg/keys/gpgkeys/private.key new file mode 100644 index 0000000..829aa9c Binary files /dev/null and b/tests/gpg/keys/gpgkeys/private.key differ diff --git a/tests/gpg/keys/gpgkeys/pubkey.gpg b/tests/gpg/keys/gpgkeys/pubkey.gpg new file mode 100644 index 0000000..eac9692 --- /dev/null +++ b/tests/gpg/keys/gpgkeys/pubkey.gpg @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +mP8k9p9/7T7TO8HZj4hphvFeD1OmhVnCZeg= +=IEUc +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpg/roots/pillar/foo.sls b/tests/gpg/roots/pillar/foo.sls new file mode 100644 index 0000000..bd6c548 --- /dev/null +++ b/tests/gpg/roots/pillar/foo.sls @@ -0,0 +1,19 @@ +#!yaml|gpg + +foo: + decrypted: Hello, test.minion! + encrypted: | + -----BEGIN PGP MESSAGE----- + + hQGMA8cPgeDyHMJ1AQv+JMGpcorefcMTMZDrVutzFeg6E9TjHHYbLdwNtKQWSJv9 + fZ4MuSTpl7tWhOLbEWW/pm/7/sy3noFCTB46pPExSvR9cL6YxbNV/vFpmIjtH1UF + /VMzF0HqJye858hFBcULjf+jxs249aqCT0AScobN/gt6fEFX3EHmvnItLFXtHNlI + WfRUm2ywycu6GAzhe5/KwI9+tB+OlZ/XsXkQSxJDohxrHIgkrgWW1WK/KAX4RNtX + F2K+khycbfg0XqK1sqjz/J+YZsW4Yqeoia4pjQNyRamJRL9eHA000XyF4tuCgXOL + KTMSRFh9+uKAd2EO1SiuVjNB5cvj7z+QbKfcrv4zVCnQ+BT5RnGMt4NC+aToG5eA + OYmrpjdN7litiehaJJQ5aB7kYEZ2mH7Jdq94hf/eD7RIOpaxEgUJ02uxnpQA89y8 + 8PHmEWVxIjYVEFc5DknMtBOmZNxH34rVh/gP8kx6uDgDGXPDKBelI1C+tn4GvPc/ + ZEhElALoDcXrXbAAFwNe0k4B1WHovPS5xIQkteJJpdxlzJ3NJSSSsoL3wEZ9hfeD + cCNwo7189XI/6lkp6ihEBMK/KZvb1VjmAAK4sBNAsVTq/Rf/y0HJ+5qaRDmIQBY= + =31EY + -----END PGP MESSAGE----- diff --git a/tests/gpg/roots/pillar/top.sls b/tests/gpg/roots/pillar/top.sls new file mode 100644 index 0000000..8e7a78c --- /dev/null +++ b/tests/gpg/roots/pillar/top.sls @@ -0,0 +1,3 @@ +base: + '*': + - foo diff --git a/tests/gpg/test.sh b/tests/gpg/test.sh new file mode 100755 index 0000000..d224302 --- /dev/null +++ b/tests/gpg/test.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +echo "🧪 Running gpg tests ..." + +# https://stackoverflow.com/a/4774063/3398062 +# shellcheck disable=SC2164 +SCRIPT_PATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +# shellcheck source=assets/build/functions.sh +COMMON_FILE="${SCRIPT_PATH}/../lib/common.sh" +source "${COMMON_FILE}" +trap cleanup EXIT + +# Run test instance +echo "==> Starting docker-salt-master (${PLATFORM}) config ..." +start_container_and_wait \ + --volume "${SCRIPT_PATH}/roots/":/home/salt/data/srv/:ro \ + --volume "${SCRIPT_PATH}/keys/":/home/salt/data/keys/ \ +|| error "container started" +ok "container started" + +setup_and_start_salt_minion || error "salt-minion started" +ok "salt-minion started" + +# Test foo pillar +echo "==> Getting gpg encrypted pillar.foo.encrypted from minion ..." +PILLAR_FOO="$( salt "${TEST_MINION_ID}" pillar.get 'foo:encrypted' || error "Unable to get pillar 'foo:encrypted'" )" +echo "${PILLAR_FOO}" +echo -n "${PILLAR_FOO}" | grep -q 'Hello, test.minion!' || error "gpg encrypted pillar.foo.encrypted" +ok "gpg encrypted pillar.foo.encrypted"