Merge pull request #174 from cdalvaro/gpg_support

Add GPG support
This commit is contained in:
Carlos D. Álvaro
2022-11-10 14:25:09 +01:00
committed by GitHub
22 changed files with 515 additions and 106 deletions

View File

@@ -26,7 +26,7 @@ The full log with the outputted error.
**Version report (please complete the following information):**
- Host OS: [e.g. `uname -a`]
- Docker: [e.g. `docker --version`]
- Image tag: [e.g. `3005.1`]
- Image tag: [e.g. `3005.1_2`]
**Additional context**
Add any other context about the problem here.

View File

@@ -15,7 +15,7 @@ on:
env:
IMAGE_NAME: localhost:5000/cdalvaro/docker-salt-master:${{ github.sha }}
REGISTRY_PATH: ${{ github.workspace }}/registry
CACHE_PATH: /tmp/.buildx-cache
CACHE_PATH: ${{ github.workspace }}/.buildx-cache
jobs:
build:
@@ -40,6 +40,7 @@ jobs:
--name registry registry:2
- name: Cache Docker layers
id: cache-docker-layers
uses: actions/cache@v3
with:
path: ${{ env.CACHE_PATH }}
@@ -47,6 +48,17 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-
- name: Cache hit
continue-on-error: true
env:
CACHE_HIT: ${{ steps.cache-docker-layers.outputs.cache-hit }}
run: |
if [[ "${CACHE_HIT}" != 'true' ]]; then
echo "No cache hit" >&2
exit 1
fi
echo "Cache contents available at: ${CACHE_PATH}"
- name: Build docker-salt-master image
uses: docker/build-push-action@v3.2.0
with:
@@ -57,6 +69,7 @@ jobs:
type=local,src=${{ env.CACHE_PATH }}
ghcr.io/cdalvaro/docker-salt-master:latest
cache-to: type=local,dest=${{ env.CACHE_PATH }}
pull: true
push: true
tags: ${{ env.IMAGE_NAME }}
@@ -117,13 +130,25 @@ jobs:
with:
python-version: '3.10'
- name: Install and configure salt-minion
run: |
# Install salt-minion from salt repos
curl -o bootstrap-salt.sh -L https://bootstrap.saltproject.io
chmod +x bootstrap-salt.sh
sudo ./bootstrap-salt.sh -dXP stable $(cat VERSION)
sudo systemctl stop salt-minion
sudo systemctl disable salt-minion
- name: Execute basic tests
if: always()
run: tests/basic/test.sh
- name: Execute salt-api tests
if: always()
run: tests/salt-api/test.sh
- name: Execute gitfs tests
if: always()
env:
GITFS_KEYS_DIR: tests/gitfs/data/keys/gitfs
SSH_PRIVATE_KEY: ${{ secrets.TESTS_REPO_PRIVATE_KEY }}
@@ -137,8 +162,14 @@ jobs:
tests/gitfs/test.sh
- name: Execute config-reloader tests
if: always()
run: tests/config-reloader/test.sh
- name: Execute GPG tests
if: always()
run: tests/gpg/test.sh
- name: Cleanup
if: always()
run: |
docker stop registry
docker rm --force registry

View File

@@ -4,6 +4,19 @@ This file only reflects the changes that are made in this image.
Please refer to the [Salt 3005.1 Release Notes](https://docs.saltstack.com/en/latest/topics/releases/3005.1.html)
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).
- Add _Development_ section to [README.md](README.md).
- CI(tests): Install `salt-minion` for integration tests.
- CI(tests): Improve log support.
- CI(tests): Always run tests.
- CI: Always perform cleanup tasks.
- CI: Improve build times.
**3005.1_1**
- If `SALT_LEVEL_LOGFILE` is not defined, then fallback to `SALT_LOG_LEVEL`.

View File

@@ -5,7 +5,7 @@ ARG VCS_REF
# https://github.com/saltstack/salt/releases
ENV SALT_VERSION="3005.1"
ENV IMAGE_VERSION="${SALT_VERSION}_1"
ENV IMAGE_VERSION="${SALT_VERSION}_2"
ENV SALT_DOCKER_DIR="/etc/docker-salt" \
SALT_ROOT_DIR="/etc/salt" \
@@ -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 \

View File

@@ -18,7 +18,7 @@ build:
release: build
@docker tag cdalvaro/docker-salt-master:latest \
cdalvaro/docker-salt-master:$(shell cat VERSION)_1
cdalvaro/docker-salt-master:$(shell cat VERSION)_2
quickstart:
@echo "Starting docker-salt-master container..."

133
README.md
View File

@@ -24,7 +24,7 @@ Automated builds of the image are available on
the recommended method of installation.
```sh
docker pull ghcr.io/cdalvaro/docker-salt-master:3005.1
docker pull ghcr.io/cdalvaro/docker-salt-master:3005.1_2
```
You can also pull the latest tag which is built from the repository `HEAD`
@@ -389,8 +389,7 @@ docker run --name salt_stack -it --rm \
### Git Fileserver
This image uses [GitPython](https://github.com/gitpython-developers/GitPython) and [PyGit2](https://www.pygit2.org) as
gitfs backends to allow Salt to serve files from git repositories.
This image uses [PyGit2](https://www.pygit2.org) as gitfs backend to allow Salt to serve files from git repositories.
It can be enabled by adding `gitfs` to
the [`fileserver_backend`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#std:conf_master-fileserver_backend)
@@ -398,13 +397,6 @@ list (see [Available Configuration Parameters](#available-configuration-paramete
repositories
in [`gitfs_remotes`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#std:conf_master-gitfs_remotes).
#### GitPython
The default name for the ssh key is `gitfs_ssh` but it can be changed with the env
variables `SALT_GITFS_SSH_PRIVATE_KEY` and `SALT_GITFS_SSH_PUBLIC_KEY`.
This keys must be placed inside `/home/salt/data/keys` directory.
#### PyGit2
You can create an ssh key for pygit2 with the following command:
@@ -434,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 <github@cdalvaro.io>
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`:
@@ -607,36 +649,36 @@ use docker-compose.
Below you can find a list with the available options that can be used to customize your `docker-salt-master`
installation.
| Parameter | Description |
|:--------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DEBUG` | Set this to `True` to enable entrypoint debugging. |
| `TIMEZONE` / `TZ` | Set the container timezone. Defaults to `UTC`. Values are expected to be in Canonical format. Example: `Europe/Madrid`. See the list of [acceptable values](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). |
| `PUID` | Sets the uid for user `salt` to the specified uid. Default: `1000`. |
| `PGID` | Sets the gid for user `salt` to the specified gid. Default: `1000`. |
| `SALT_RESTART_MASTER_ON_CONFIG_CHANGE` | Set this to `True` to restart `salt-master` service when configuration files change. Default: `False`. |
| [`SALT_LOG_LEVEL`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#log-level) | The level of messages to send to the console. One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. Default: `warning`. |
| `SALT_LOG_ROTATE_FREQUENCY` | Logrotate frequency for salt logs. Available options are 'daily', 'weekly', 'monthly', and 'yearly'. Default: `weekly`. |
| `SALT_LOG_ROTATE_RETENTION` | Keep x files before deleting old log files. Defaults: `52`. |
| [`SALT_LEVEL_LOGFILE`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#log-level-logfile) | The level of messages to send to the log file. One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. Default: `SALT_LOG_LEVEL`. |
| `SALT_MASTER_KEY_FILE` | The path to the master-key-pair {pem,pub} files without suffixes. Keys will be copied into the pki directory. Useful to load the password from secrets. _Unset_ by default. |
| [`SALT_API_SERVICE_ENABLED`](https://docs.saltproject.io/en/latest/ref/cli/salt-api.html) | Enable `salt-api` service. Default: `False`. |
| `SALT_API_USER` | Set username for `salt-api` service. Default: `salt_api`. |
| `SALT_API_USER_PASS_FILE` | `SALT_API_USER` password file path. Use this variable to set the path of a file containing the password for the `SALT_API_USER`. Useful to load the password from secrets. Has priority over `SALT_API_USER_PASS`. _Unset_ by default. |
| `SALT_API_USER_PASS` | `SALT_API_USER` password. Required if `SALT_API_SERVICE_ENBALED` is `True`, `SALT_API_USER` is not empty and `SALT_API_USER_PASS_FILE` is unset. _Unset_ by default. |
| `SALT_API_CERT_CN` | Common name in the request. Default: `localhost`. |
| [`SALT_MASTER_SIGN_PUBKEY`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-sign-pubkey) | Sign the master auth-replies with a cryptographic signature of the master's public key. Possible values: 'True' or 'False'. Default: `False`. |
| [`SALT_MASTER_USE_PUBKEY_SIGNATURE`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-use-pubkey-signature) | Instead of computing the signature for each auth-reply, use a pre-calculated signature. This option requires `SALT_MASTER_SIGN_PUBKEY` set to 'True'. Possible values: 'True' or 'False'. Default: `True`. |
| [`SALT_MASTER_SIGN_KEY_NAME`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-sign-key-name) | The customizable name of the signing-key-pair without suffix. Default: `master_sign`. |
| `SALT_MASTER_SIGN_KEY_FILE` | The path to the signing-key-pair {pem,pub} without suffixes. The pair will be copied into the pki directory if they don't exists previously. Useful to load the password from secrets. _Unset_ by default. |
| [`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_GITFS_SSH_PRIVATE_KEY` | The name of the ssh private key for gitfs. Default: `gitfs_ssh`. |
| `SALT_GITFS_SSH_PUBLIC_KEY` | The name of the ssh public key for gitfs. Default: `gitfs_ssh`.pub`. |
| [`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`. |
| [`SALT_CONFS_DIR`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#std-conf_master-default_include) | The master will automatically include all config files from this directory. Default: `/home/salt/data/config`. |
| Parameter | Description |
|:--------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DEBUG` | Set this to `True` to enable entrypoint debugging. |
| `TIMEZONE` / `TZ` | Set the container timezone. Defaults to `UTC`. Values are expected to be in Canonical format. Example: `Europe/Madrid`. See the list of [acceptable values](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). |
| `PUID` | Sets the uid for user `salt` to the specified uid. Default: `1000`. |
| `PGID` | Sets the gid for user `salt` to the specified gid. Default: `1000`. |
| `SALT_RESTART_MASTER_ON_CONFIG_CHANGE` | Set this to `True` to restart `salt-master` service when configuration files change. Default: `False`. |
| [`SALT_LOG_LEVEL`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#log-level) | The level of messages to send to the console. One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. Default: `warning`. |
| `SALT_LOG_ROTATE_FREQUENCY` | Logrotate frequency for salt logs. Available options are 'daily', 'weekly', 'monthly', and 'yearly'. Default: `weekly`. |
| `SALT_LOG_ROTATE_RETENTION` | Keep x files before deleting old log files. Defaults: `52`. |
| [`SALT_LEVEL_LOGFILE`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#log-level-logfile) | The level of messages to send to the log file. One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. Default: `SALT_LOG_LEVEL`. |
| `SALT_MASTER_KEY_FILE` | The path to the master-key-pair {pem,pub} files without suffixes. Keys will be copied into the pki directory. Useful to load the password from secrets. _Unset_ by default. |
| [`SALT_API_SERVICE_ENABLED`](https://docs.saltproject.io/en/latest/ref/cli/salt-api.html) | Enable `salt-api` service. Default: `False`. |
| `SALT_API_USER` | Set username for `salt-api` service. Default: `salt_api`. |
| `SALT_API_USER_PASS_FILE` | `SALT_API_USER` password file path. Use this variable to set the path of a file containing the password for the `SALT_API_USER`. Useful to load the password from secrets. Has priority over `SALT_API_USER_PASS`. _Unset_ by default. |
| `SALT_API_USER_PASS` | `SALT_API_USER` password. Required if `SALT_API_SERVICE_ENBALED` is `True`, `SALT_API_USER` is not empty and `SALT_API_USER_PASS_FILE` is unset. _Unset_ by default. |
| `SALT_API_CERT_CN` | Common name in the request. Default: `localhost`. |
| [`SALT_MASTER_SIGN_PUBKEY`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-sign-pubkey) | Sign the master auth-replies with a cryptographic signature of the master's public key. Possible values: 'True' or 'False'. Default: `False`. |
| [`SALT_MASTER_USE_PUBKEY_SIGNATURE`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-use-pubkey-signature) | Instead of computing the signature for each auth-reply, use a pre-calculated signature. This option requires `SALT_MASTER_SIGN_PUBKEY` set to 'True'. Possible values: 'True' or 'False'. Default: `True`. |
| [`SALT_MASTER_SIGN_KEY_NAME`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#master-sign-key-name) | The customizable name of the signing-key-pair without suffix. Default: `master_sign`. |
| `SALT_MASTER_SIGN_KEY_FILE` | The path to the signing-key-pair {pem,pub} without suffixes. The pair will be copied into the pki directory if they don't exists previously. Useful to load the password from secrets. _Unset_ by default. |
| [`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`. |
| [`SALT_CONFS_DIR`](https://docs.saltproject.io/en/latest/ref/configuration/master.html#std-conf_master-default_include) | The master will automatically include all config files from this directory. Default: `/home/salt/data/config`. |
Any parameter not listed in the above table and available in the
following [link](https://docs.saltproject.io/en/latest/ref/configuration/examples.html#configuration-examples-master),
@@ -691,7 +733,16 @@ You can restart containers services by running the following command:
docker exec -it salt_master entrypoint.sh app:restart [salt-service]
```
Where `salt-service` is one of: `salt-master` os `salt-api` (if `SALT_API_SERVICE_ENABLED` is set to `True`)
Where `salt-service` is one of: `salt-master` os `salt-api` (if `SALT_API_SERVICE_ENABLED` is set to `True`).
## 🔨 Development
Everyone is wellcome to contribute to this project, and I really appreciate your support. So don't be shy!
Before you start making changes, read carefully the following notes in order to avoid issues.
- ⚠️ Some tests start and stop a _**non-isolated**_ `salt-minion` instance. So don't run tests locally.
Tests are automatically executed on GitHub when you push commits to your PR.
## 👏 Credits

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
set -o errexit
set -o pipefail
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: log_debug

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
set -o errexit
set -o pipefail
export DEBIAN_FRONTEND=noninteractive
@@ -47,7 +48,7 @@ download "${BOOTSTRAP_URL}" "${BOOTSTRAP_FILE}"
check_sha256 "${BOOTSTRAP_FILE}" "${BOOTSTRAP_SHA256}"
# Bootstrap script options:
# https://docs.saltstack.com/en/latest/topics/tutorials/salt_bootstrap.html#command-line-options
# https://docs.saltproject.io/salt/install-guide/en/latest/topics/bootstrap.html
## -M: install Salt Master by default
## -N: Do not install salt-minion
## -X: Do not start daemons after installation
@@ -64,6 +65,13 @@ log_debug "Options: ${SALT_BOOTSTRAP_OPTS[@]}"
sh "${BOOTSTRAP_FILE}" ${SALT_BOOTSTRAP_OPTS[@]} git "v${SALT_VERSION}"
chown -R "${SALT_USER}": "${SALT_ROOT_DIR}"
# Patch to remove salt-minion
SALT_MINION="$(command -v salt-minion)"
if [[ -n "${SALT_MINION}" ]]; then
log_warn "Removing salt-minion ..."
rm -f "${SALT_MINION}"
fi
# Configure ssh
log_info "Configuring ssh ..."
sed -i -e "s|^[# ]*StrictHostKeyChecking.*$| StrictHostKeyChecking no|" /etc/ssh/ssh_config

View File

@@ -30,6 +30,5 @@ 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}
##### SSH settings #####
SALT_GITFS_SSH_PRIVATE_KEY=${SALT_GITFS_SSH_PRIVATE_KEY:-gitfs_ssh}
SALT_GITFS_SSH_PUBLIC_KEY=${SALT_GITFS_SSH_PUBLIC_KEY:-gitfs_ssh.pub}
# Directory where GPG keys will be looking for
SALT_KEYS_GPGKEYS_DIR="${SALT_KEYS_DIR}/gpgkeys"

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
set -o errexit
set -o pipefail
# shellcheck source=assets/runtime/env-defaults.sh
ENV_DEFAULTS_FILE="${SALT_RUNTIME_DIR}/env-defaults.sh"
@@ -72,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
}
@@ -185,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
@@ -223,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
@@ -250,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

View File

@@ -7,7 +7,7 @@ set -o pipefail
FUNCTIONS_FILE="${SALT_RUNTIME_DIR}/functions.sh"
source "${FUNCTIONS_FILE}"
[[ "${DEBUG,,}" == true ]] && set -x
[[ "${DEBUG,,}" == true ]] && set -o xtrace
case "${1}" in
app:start|app:gen-signed-keys)
@@ -35,7 +35,7 @@ case "${1}" in
exec supervisorctl restart "${1}"
;;
*)
log_error "Unable to restart ${1} serice. Service is unknown"
log_error "Unable to restart ${1} service. Service is unknown"
exit 1
;;
esac

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
set -e
[ "${DEBUG,,}" == true ] && set -vx
echo "🧪 Running basic 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
@@ -28,3 +26,19 @@ ok "salt-master version"
echo "==> Executing healthcheck ..."
docker-exec /usr/local/sbin/healthcheck | grep -i true || error "healthcheck"
ok "healthcheck"
# Check salt-minion is not installed
# shellcheck disable=SC2016
docker-exec bash -c 'test -z "$(command -v salt-minion)"' || error "salt-minion is installed inside the container"
ok "salt-minion is not installed inside the container"
# shellcheck disable=SC2016
docker-exec bash -c 'test -z "$(ps aux | grep salt-minion | grep -v grep)"' || error "salt-minion is running inside the container"
ok "salt-minion is not running inside the container"
# Test minion connection
setup_and_start_salt_minion || error "salt-minion started"
ok "salt-minion started"
salt "${TEST_MINION_ID}" test.ping || error "${TEST_MINION_ID} ping"
ok "${TEST_MINION_ID} ping"

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
set -e
[ "${DEBUG,,}" == true ] && set -vx
echo "🧪 Running config-reloader 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
@@ -17,7 +15,6 @@ trap cleanup EXIT
echo "==> Starting docker-salt-master (${PLATFORM}) ..."
start_container_and_wait \
--env SALT_RESTART_MASTER_ON_CONFIG_CHANGE=True \
--volume "${SCRIPT_PATH}/config":/home/salt/data/config:ro \
|| error "container started"
ok "container started"

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
set -e
[ "${DEBUG,,}" == true ] && set -vx
echo "🧪 Running gitfs 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
@@ -25,7 +23,6 @@ ok "gitfs keys"
# Run test instance
echo "==> Starting docker-salt-master (${PLATFORM}) with ed25519 ssh key ..."
start_container_and_wait \
--volume "${SCRIPT_PATH}/config":/home/salt/data/config:ro \
--volume "$(pwd)/${GITFS_KEYS_DIR%%/gitfs}":/home/salt/data/keys \
|| error "container started"
ok "container started"
@@ -37,9 +34,26 @@ UPDATE_REPOS="$( salt-run fileserver.update )"
echo "${UPDATE_REPOS}" | grep -qi true || error "update gitfs"
ok "update gitfs"
# Check pillars
# Check gitfs files
echo "==> Checking gitfs files ..."
FILE_LIST=$( salt-run fileserver.file_list )
echo "${FILE_LIST}"
[[ "${FILE_LIST}" == *test.txt* ]] || error "gitfs files"
ok "gitfs files"
# Test minion connection
setup_and_start_salt_minion || error "salt-minion started"
ok "salt-minion started"
# Test pillar
echo "==> Checking gitfs pillar docker-salt-master-test:email content from minion ..."
PILLAR_CONTENT="$( salt "${TEST_MINION_ID}" pillar.get 'docker-salt-master-test:email' || error "Unable to get pillar 'docker-salt-master-test:email'" )"
echo "${PILLAR_CONTENT}"
echo -n "${PILLAR_CONTENT}" | grep -q 'github@cdalvaro.io' || error "Check gitfs pillar 'docker-salt-master-test:email'"
ok "Check gitfs pillar 'docker-salt-master-test:email'"
# Test gitfs deploy
echo "==> Checking gitfs top.sls (state.apply) ..."
salt "${TEST_MINION_ID}" state.apply
[ -f /tmp/my_file.txt ] || error "Check gitfs top.sls applied"
ok "Check gitfs top.sls applied"

5
tests/gpg/README.md Normal file
View File

@@ -0,0 +1,5 @@
# Salt GPG Renderer Tests
Checks:
- get gpg encrypted pillar.

Binary file not shown.

View File

@@ -0,0 +1,41 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
mP8k9p9/7T7TO8HZj4hphvFeD1OmhVnCZeg=
=IEUc
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -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-----

View File

@@ -0,0 +1,3 @@
base:
'*':
- foo

30
tests/gpg/test.sh Executable file
View File

@@ -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"

View File

@@ -1,5 +1,13 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
if [[ "${DEBUG,,}" == true ]]; then
set -o verbose
set -o xtrace
fi
#--- ENV VARIABLE ---------------------------------------------------------------------------------------------------
# NAME: IMAGE_NAME
# DESCRIPTION: The name and tag of the Docker image. Default: 'cdalvaro/docker-salt-master:latest'.
@@ -12,6 +20,12 @@ export IMAGE_NAME=${IMAGE_NAME:-'cdalvaro/docker-salt-master:latest'}
#----------------------------------------------------------------------------------------------------------------------
export CONTAINER_NAME=salt-master
#--- ENV VARIABLE ---------------------------------------------------------------------------------------------------
# NAME: TEST_MINION_ID
# DESCRIPTION: The id of the salt-minion for testing. Default: 'test.minion'.
#----------------------------------------------------------------------------------------------------------------------
export TEST_MINION_ID=test.minion
#--- ENV VARIABLE ---------------------------------------------------------------------------------------------------
# NAME: PLATFORM
# DESCRIPTION: The platform to run the tests on. Default: the current platform.
@@ -30,8 +44,21 @@ export BOOTUP_WAIT_SECONDS=${BOOTUP_WAIT_SECONDS:-60}
#----------------------------------------------------------------------------------------------------------------------
function cleanup()
{
echo "🧹 Removing ${CONTAINER_NAME} ..."
docker container rm --force "${CONTAINER_NAME}"
echo "🧹 Running cleanup tasks ..."
local salt_master_container="$(docker container ls --filter NAME="${CONTAINER_NAME}" --quiet)"
if [ -n "${salt_master_container}" ]; then
echo " - Removing ${CONTAINER_NAME} docker container ..."
docker container rm --force --volumes "${salt_master_container}" > /dev/null
fi
if [ -n "$(pgrep -f salt-minion)" ]; then
echo " - Stopping salt-minion ..."
sudo killall salt-minion
sudo rm -f /var/log/salt/minion
fi
echo "🧹 All cleanup tasks done!"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
@@ -70,13 +97,53 @@ function salt-call()
docker-exec salt-call "$@"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: salt
# DESCRIPTION: Execute the salt command inside the container.
#----------------------------------------------------------------------------------------------------------------------
function salt()
{
docker-exec salt "$@"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: container_log
# DESCRIPTION: Print container log.
#----------------------------------------------------------------------------------------------------------------------
function container_log()
{
local CONTAINER_ID="$(docker container ls --all --filter NAME="${CONTAINER_NAME}" --quiet)"
[ -n "${CONTAINER_ID}" ] || return 0
echo "📝 container log (${CONTAINER_NAME})"
docker logs -t "${CONTAINER_ID}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: master_log
# DESCRIPTION: Print salt-master log.
#----------------------------------------------------------------------------------------------------------------------
function master_log()
{
docker-exec cat data/logs/salt/master
local LOGS_DIR="${SCRIPT_PATH}/logs"
local SALT_MASTER_LOG="${LOGS_DIR}/salt/master"
[ -f "${SALT_MASTER_LOG}" ] || return 0
echo "📝 salt-master log (${SALT_MASTER_LOG})"
sudo cat "${SALT_MASTER_LOG}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: minion_log
# DESCRIPTION: Print salt-minion log.
#----------------------------------------------------------------------------------------------------------------------
function minion_log()
{
local SALT_MINION_LOG='/var/log/salt/minion'
[ -f "${SALT_MINION_LOG}" ] || return 0
echo "📝 salt-minion log (${SALT_MINION_LOG})"
sudo cat "${SALT_MINION_LOG}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
@@ -87,20 +154,64 @@ function start_container_and_wait()
{
# shellcheck disable=SC2206
local DOCKER_ARGS=( $@ )
local LOGS_DIR="${SCRIPT_PATH}/logs"
mkdir -p "${LOGS_DIR}"
docker run --rm --detach --name "${CONTAINER_NAME}" \
# Common config
mkdir -p "${SCRIPT_PATH}/config/autosign_grains"
cat > "${SCRIPT_PATH}"/config/autosign_grains.conf <<EOF
autosign_grains_dir: /home/salt/data/config/autosign_grains
EOF
cat > "${SCRIPT_PATH}"/config/autosign_grains/id <<EOF
${TEST_MINION_ID}
EOF
docker run --detach --name "${CONTAINER_NAME}" \
--publish 4505:4505 --publish 4506:4506 \
--env PUID="$(id -u)" --env PGID="$(id -g)" \
--env SALT_LOG_LEVEL='info' \
--platform "${PLATFORM}" ${DOCKER_ARGS[@]} \
--volume "${LOGS_DIR}/":/home/salt/data/logs/ \
--volume "${SCRIPT_PATH}/config/":/home/salt/data/config/:ro \
"${IMAGE_NAME}" || return 1
echo "==> Waiting ${BOOTUP_WAIT_SECONDS} seconds for the container to be ready ..."
sleep "${BOOTUP_WAIT_SECONDS}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: setup_and_start_salt_minion
# DESCRIPTION: Setup and start salt-minion.
#----------------------------------------------------------------------------------------------------------------------
function setup_and_start_salt_minion()
{
local SALT_MINION_CONF_DIR=/etc/salt/minion.d
sudo rm -rf '/etc/salt'
sudo mkdir -p "${SALT_MINION_CONF_DIR}"
sudo tee "${SALT_MINION_CONF_DIR}/minion.conf" > /dev/null <<EOF
id: ${TEST_MINION_ID}
master: localhost
verify_master_pubkey_sign: False
master_alive_interval: 10
retry_dns: 5
retry_dns_count: 4
autosign_grains:
- uuid
- id
EOF
echo "==> Starting salt-minion ..."
sudo salt-minion --log-file-level=info --daemon &
sleep 40
test -n "$(pgrep -f salt-minion)"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: ok
# DESCRIPTION: Print a successfull message.
# DESCRIPTION: Print a success message.
#----------------------------------------------------------------------------------------------------------------------
function ok()
{
@@ -113,8 +224,10 @@ function ok()
#----------------------------------------------------------------------------------------------------------------------
function error()
{
echo "🔥 $*"
master_log
echo "🔥 $*" >&2
container_log >&2
master_log >&2
minion_log >&2
return 1
}

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
set -e
[ "${DEBUG,,}" == true ] && set -vx
echo "🧪 Running salt-api 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
@@ -17,12 +15,11 @@ export SALTAPI_URL="https://localhost:8000/"
export SALTAPI_USER=salt_api
export SALTAPI_PASS=4wesome-Pass0rd
export SALTAPI_EAUTH=pam
export SALTAPI_TMP_DIR=${SALTAPI_TMP_DIR:-/tmp/salt-api}
# Create configuration files
echo "==> Creating salt-api configuration file ..."
mkdir -p "${SALTAPI_TMP_DIR}/config/"
cat > "${SALTAPI_TMP_DIR}/config/salt-api.conf" <<EOF
mkdir -p "${SCRIPT_PATH}/config"
cat > "${SCRIPT_PATH}/config/salt-api.conf" <<EOF
external_auth:
${SALTAPI_EAUTH}:
${SALTAPI_USER}:
@@ -39,7 +36,6 @@ start_container_and_wait \
--publish 8000:8000 \
--env SALT_API_SERVICE_ENABLED=True \
--env SALT_API_USER_PASS="${SALTAPI_PASS}" \
--volume "${SALTAPI_TMP_DIR}/config":/home/salt/data/config:ro \
|| error "container started"
ok "container started"
@@ -64,16 +60,6 @@ curl -sSk "${SALTAPI_URL}" \
| grep -i true || error "curl command"
ok "curl command"
# Install salt-pepper
echo "==> Installing salt-pepper ..."
pip3 install salt-pepper || error "pepper installed"
ok "pepper installed"
# Test salt-pepper
echo "==> Testing salt-pepper ..."
pepper --client runner test.stream || error "pepper test.stream"
ok "pepper test.stream"
# Stop and start with salt-api pass via file
echo "==> Stopping previous container ..."
cleanup
@@ -85,7 +71,6 @@ start_container_and_wait \
--publish 8000:8000 \
--env SALT_API_SERVICE_ENABLED=True \
--env SALT_API_USER_PASS_FILE="/run/secrets/${SALT_API_USER_PASS_FILE}" \
--volume "${SALTAPI_TMP_DIR}/config":/home/salt/data/config:ro \
--volume "$(pwd)/${SALT_API_USER_PASS_FILE}":/run/secrets/${SALT_API_USER_PASS_FILE}:ro \
|| error "container started"
ok "container started"
@@ -110,3 +95,17 @@ curl -sSk "${SALTAPI_URL}" \
-d fun=test.stream \
| grep -i true || error "curl command"
ok "curl command"
# Install salt-pepper
echo "==> Installing salt-pepper ..."
pip3 install salt-pepper || error "pepper installed"
ok "pepper installed"
# Test minion connection
setup_and_start_salt_minion || error "salt-minion started"
ok "salt-minion started"
# Test pepper with salt-minion
echo "==> Testing pepper with salt-minion (test.ping) ..."
pepper "${TEST_MINION_ID}" test.ping || error "pepper test.ping"
ok "pepper test.ping"