Merge pull request #24 from cdalvaro/issue-23/add-salt-api-support

Add salt-api support
This commit is contained in:
Carlos D. Álvaro
2020-05-17 14:34:27 +02:00
committed by GitHub
13 changed files with 373 additions and 108 deletions

23
.shellcheckrc Normal file
View File

@@ -0,0 +1,23 @@
# Check shellcheck wiki at:
# https://github.com/koalaman/shellcheck/wiki/SCXXXX
# Redirections are performed by the current shell before sudo is started.
disable=SC2024
# foo appears unused. Verify it or export it.
disable=SC2034
# Double quote array expansions to avoid re-splitting elements.
disable=SC2068
# Argument mixes string and array.
disable=SC2145
# Declare and assign separately to avoid masking return values.
disable=SC2155
# This redirection doesn't have a command.
disable=SC2188
# This is a file redirection.
disable=SC2210

View File

@@ -3,6 +3,13 @@
This file only reflects the changes that are made in this image.
Please refer to the SaltStack [Release Notes](https://docs.saltstack.com/en/latest/topics/releases/3000.3.html) for the list of changes in SaltStack.
**3000.3_1**
- Add support for `salt-api` service
- Add entrypoint support to restart services
- Use previous image as Docker cache
- Add `build-arg` to Makefile
**3000.3**
- Upgrade SaltStack Master to `3000.3`

View File

@@ -57,7 +57,7 @@ COPY entrypoint.sh /sbin/entrypoint.sh
RUN chmod +x /sbin/entrypoint.sh
# Shared resources
EXPOSE 4505/tcp 4506/tcp
EXPOSE 4505 4506 8000
RUN mkdir -p ${SALT_DATA_DIR} ${SALT_BASE_DIR} ${SALT_KEYS_DIR} ${SALT_CONFS_DIR} ${SALT_LOGS_DIR}
VOLUME [ "${SALT_BASE_DIR}" "${SALT_KEYS_DIR}" "${SALT_CONFS_DIR}" "${SALT_LOGS_DIR}" ]

View File

@@ -11,10 +11,14 @@ help:
@echo " 5. make logs - view logs"
build:
@docker build --tag=cdalvaro/saltstack-master .
@docker build --tag=cdalvaro/saltstack-master . \
--build-arg=BUILD_DATE="$(shell date +"%Y-%m-%d %H:%M:%S%:z")" \
--build-arg=VCS_REF="$(shell git rev-parse --short HEAD)" \
release: build
@docker build --tag=cdalvaro/saltstack-master:$(shell cat VERSION) .
@docker build --tag=cdalvaro/saltstack-master:$(shell cat VERSION) . \
--build-arg=BUILD_DATE="$(shell date +"%Y-%m-%d %H:%M:%S%:z")" \
--build-arg=VCS_REF="$(shell git rev-parse --short HEAD)" \
quickstart:
@echo "Starting saltstack-master container..."

157
README.md
View File

@@ -1,4 +1,9 @@
# SaltStack Master v3000.3
[![SaltStack][saltstack_badge]][saltstack_release_notes]
[![Ubuntu Image][ubuntu_badge]][ubuntu_hub_docker]
[![Docker Build Status][docker_build_badge]][docker_hub]
[![CodeFactor][codefactor_badge]][codefactor_score]
# SaltStack Master v3000.3_1
Dockerfile to build a [SaltStack](https://www.saltstack.com) Master image for the Docker opensource container platform.
@@ -15,6 +20,8 @@ For other methods to install SaltStack please refer to the [Official SaltStack I
- [Custom Recipes](#custom-recipes)
- [Minion Keys](#minion-keys)
- [Master Signed Keys](#master-signed-keys)
- [Salt API](#salt-api)
- [Salt Pepper](#salt-pepper)
- [Host Mapping](#host-mapping)
- [Git Fileserver](#git-fileserver)
- [GitPython](#gitpython)
@@ -23,6 +30,7 @@ For other methods to install SaltStack please refer to the [Official SaltStack I
- [Available Configuration Parameters](#available-configuration-parameters)
- [Usage](#usage)
- [Shell Access](#shell-access)
- [Restart Services](#restart-services)
- [References](#references)
## Installation
@@ -30,7 +38,7 @@ For other methods to install SaltStack please refer to the [Official SaltStack I
Automated builds of the image are available on [Dockerhub](https://hub.docker.com/r/cdalvaro/saltstack-master/) and is the recommended method of installation.
```sh
docker pull cdalvaro/saltstack-master:3000.3
docker pull cdalvaro/saltstack-master:3000.3_1
```
You can also pull the latest tag which is built from the repository `HEAD`
@@ -69,63 +77,149 @@ Alternatively, you can manually launch the `saltstack-master` container:
```sh
docker run --name salt_master --detach \
--publish 4505:4505/tcp --publish 4506:4506/tcp \
--publish 4505:4505 --publish 4506:4506 \
--env 'SALT_LOG_LEVEL=info' \
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
## Configuration
### Custom Recipes
In order to provide salt with your custom recipes you must mount the volume `/home/salt/data/srv/` with your `roots` directory.
In order to provide salt with your custom recipes you must mount the volume `/home/salt/data/srv/`
with your `roots` directory.
### Minion Keys
Minion keys can be added automatically on startup to SaltStack master by mounting the volume `/home/salt/data/keys` and copying the minion keys inside `keys/minions/` directory.
Minion keys can be added automatically on startup to SaltStack master by mounting the volume
`/home/salt/data/keys` and copying the minion keys inside `keys/minions/` directory.
It is also important to know that, in order to keep your keys after removing the container, the keys directory must be mounted.
It is also important to know that, in order to keep your keys after removing the container,
the keys directory must be mounted.
```sh
mkdir -p keys/minions
rsync root@minion1:/etc/salt/pki/minion/minion.pub keys/minions/minion1
docker run --name salt_master -d \
--publish 4505:4505/tcp --publish 4506:4506/tcp \
--publish 4505:4505 --publish 4506:4506 \
--env 'SALT_LOG_LEVEL=info' \
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
### Master Signed Keys
It is possible to use signed master keys by establishing the environment variable `SALT_MASTER_SIGN_PUBKEY` to `True`.
It is possible to use signed master keys by establishing the environment variable
`SALT_MASTER_SIGN_PUBKEY` to `True`.
```sh
docker run --name salt_stack --detach \
--publish 4505:4505/tcp --publish 4506:4506/tcp \
--publish 4505:4505 --publish 4506:4506 \
--env 'SALT_LOG_LEVEL=info' \
--env 'SALT_MASTER_SIGN_PUBKEY=True'
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
The container will create the `master_sign` key and its signature. More information about how to configure the minion service can be found [here](https://docs.saltstack.com/en/latest/topics/tutorials/multimaster_pki.html#prepping-the-minion-to-verify-received-public-keys).
The container will create the `master_sign` key and its signature.
More information about how to configure the minion service can be found
[here](https://docs.saltstack.com/en/latest/topics/tutorials/multimaster_pki.html#prepping-the-minion-to-verify-received-public-keys).
Additionally, you can generate new keys by executing the following command:
```sh
docker run --name salt_stack -it --rm \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3 app:gen-signed-keys other_master_sign
cdalvaro/saltstack-master:3000.3_1 app:gen-signed-keys other_master_sign
```
The newly created keys will appear inside `keys/generated/other_master_sign` directory.
### Salt API
You can enable `salt-api` service by setting env variable `SALT_API_SERVICE_ENABLED` to `true`.
A self-signed SSL certificate will be automatically generated and the following configuration
will be added to the master configuration file:
```yml
rest_cherrypy:
port: 8000
ssl_crt: /etc/pki/tls/certs/docker-salt-master.crt
ssl_key: /etc/pki/tls/certs/docker-salt-master.key
```
The container exposes port `8000` by default, although you can map this port to whatever port you like in
your `docker run` command or in your `docker-compose.yml` file.
```sh
docker run --name salt_stack --detach \
--publish 4505:4505 --publish 4506:4506 --publish 8000:8000 \
--env 'SALT_API_SERVICE_ENABLED=true' \
--env 'SALT_API_USER_PASS=SuperCool/Password10'
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3_1
```
By default, user `salt_api` is created and you can set its password by setting the environment variable
`SALT_API_USER_PASS`.
You can also change the salt-api _username_ by setting `SALT_API_USER`.
It is possible to disable this user by explicitly setting this variable to an empty string: `SALT_API_USER=''` if you are going to use an `LDAP` server.
As a security measure, if `SALT_API_USER_PASS` is set to `true` and you don't disable `SALT_API_USER`,
you'll be required to set `SALT_API_USER_PASS`. Otherwise initialization will fail and your Docker image won't work.
With all that set, you'll be able to provide your _salt-api_ custom configuration by creating the `salt-api.conf`
file inside your `conf` directory:
```yml
external_auth:
pam:
salt_api:
- .*
```
More information is available in the following link: [External Authentication System (eAuth)](https://docs.saltstack.com/en/latest/topics/eauth/index.html#acl-eauth).
Now you have your saltstack-master docker image ready to accept external authentications and to connect external tools such as [`saltstack/pepper`](https://github.com/saltstack/pepper).
#### Salt Pepper
The pepper CLI script allows users to execute Salt commands from computers that are external to computers running the salt-master or salt-minion daemons as though they were running Salt locally
##### Installation:
```sh
pip3 install salt-pepper
```
##### Configuration
Then configure pepper by filling your `~/.pepperrc` file with your salt-api credentials:
```conf
[main]
SALTAPI_URL=https://your.salt-master.hostname:8000/
SALTAPI_USER=salt_api
SALTAPI_PASS=SuperCool/Password10
SALTAPI_EAUTH=pam
```
##### Usage
Beging executing salt recipes with `pepper`:
```sh
pepper '*' test.ping
```
### Host Mapping
Per default the container is configured to run `salt-master` as user and group `salt` with `uid` and `gid` `1000`. From the host it appears as if the mounted data volumes are owned by the host's user/group `1000` and maybe leading to unfavorable effects.
@@ -137,7 +231,7 @@ docker run --name salt_stack -it --rm \
--env "USERMAP_UID=$(id -u)" --env "USERMAP_GID=$(id -g)" \
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
### Git Fileserver
@@ -188,12 +282,12 @@ Inside that directory you could find `supervisor/` logs and `salt/` logs:
```sh
docker run --name salt_master --detach \
--publish 4505:4505/tcp --publish 4506:4506/tcp \
--publish 4505:4505 --publish 4506:4506 \
--env 'SALT_LOG_LEVEL=info' \
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
--volume $(pwd)/logs/:/home/salt/data/logs/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
Check [Available Configuration Parameters](#available-configuration-parameters) section for configuring logrotate.
@@ -212,6 +306,9 @@ Below is the list of available options that can be used to customize your SaltSt
| `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` | The level of messages to send to the log file. One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. Default: `warning` |
| `SALT_API_SERVICE_ENABLED` | Enable `salt-api` service. Default: `false` |
| `SALT_API_USER` | Set username for `salt-api` service. Default: `salt_api` |
| `SALT_API_USER_PASS` | `SALT_API_USER` password. Required if `SALT_API_SERVICE_ENBALED` is `true` and `SALT_API_USER` is not empty. _Unset_ by default |
| `SALT_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` | 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` | The customizable name of the signing-key-pair without suffix. Default: `master_sign` |
@@ -234,12 +331,12 @@ ret_port: 3506
EOF
docker run --name salt_master -d \
--publish 3505:3505/tcp --publish 3506:3506/tcp \
--publish 3505:3505 --publish 3506:3506 \
--env 'SALT_LOG_LEVEL=info' \
--volume $(pwd)/roots/:/home/salt/data/srv/ \
--volume $(pwd)/keys/:/home/salt/data/keys/ \
--volume $(pwd)/config/:/home/salt/data/config/ \
cdalvaro/saltstack-master:3000.3
cdalvaro/saltstack-master:3000.3_1
```
## Usage
@@ -264,8 +361,30 @@ For debugging and maintenance purposes you may want access the container shell.
docker exec -it salt_master bash
```
## Restart Services
You can restart containers services by running the following command:
```sh
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`)
## References
- https://docs.saltstack.com/en/latest/topics/installation/index.html
- https://docs.saltstack.com/en/latest/topics/tutorials/salt_bootstrap.html
- https://github.com/saltstack/salt/releases
[saltstack_badge]: https://img.shields.io/badge/SaltStack-v3000.3-lightgrey.svg?style=flat-square&logo=Saltstack
[saltstack_release_notes]: https://docs.saltstack.com/en/latest/topics/releases/3000.3.html "SaltStack Release Notes"
[ubuntu_badge]: https://img.shields.io/badge/ubuntu-bionic--20200403-E95420.svg?style=flat-square&logo=Ubuntu
[ubuntu_hub_docker]: https://hub.docker.com/_/ubuntu/ "Ubuntu Image"
[docker_build_badge]: https://img.shields.io/docker/build/cdalvaro/saltstack-master?logo=docker&style=flat-square
[docker_hub]: https://hub.docker.com/r/cdalvaro/saltstack-master/builds
[codefactor_badge]: https://www.codefactor.io/repository/github/cdalvaro/saltstack-master/badge?style=flat-square
[codefactor_score]: https://www.codefactor.io/repository/github/cdalvaro/saltstack-master

View File

@@ -1 +1 @@
3000.3
3000.3_1

View File

@@ -5,9 +5,9 @@ set -e
# Execute a command as SALT_USER
function exec_as_salt()
{
if [[ $(whoami) == ${SALT_USER} ]]; then
if [[ $(whoami) == "${SALT_USER}" ]]; then
$@
else
sudo -HEu ${SALT_USER} "$@"
sudo -HEu "${SALT_USER}" "$@"
fi
}

View File

@@ -2,39 +2,41 @@
set -e
source ${SALT_BUILD_DIR}/functions.sh
source "${SALT_BUILD_DIR}/functions.sh"
# Install build dependencies
echo "Installing dependencies ..."
BUILD_DEPENDENCIES="cmake gcc g++ make \
libhttp-parser-dev libssl-dev zlib1g-dev \
libcurl4-openssl-dev libffi-dev swig"
BUILD_DEPENDENCIES=(
cmake gcc g++ make \
libhttp-parser-dev libssl-dev zlib1g-dev \
libcurl4-openssl-dev libffi-dev swig \
)
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install --yes --quiet --no-install-recommends ${BUILD_DEPENDENCIES}
DEBIAN_FRONTEND=noninteractive apt-get install --yes --quiet --no-install-recommends "${BUILD_DEPENDENCIES[@]}"
# Create salt user
echo "Creating ${SALT_USER} user ..."
useradd -d ${SALT_HOME} -ms /bin/bash -U -G root,sudo ${SALT_USER}
useradd -d "${SALT_HOME}" -ms /bin/bash -U -G root,sudo,shadow "${SALT_USER}"
# Set PATH
exec_as_salt cat >> ${SALT_HOME}/.profile <<EOF
exec_as_salt cat >> "${SALT_HOME}/.profile" <<EOF
PATH=/usr/local/sbin:/usr/local/bin:\$PATH
EOF
# Compile libssh2
echo "Building libssh2 v${LIBSSH2_VERSION} ..."
wget https://github.com/libssh2/libssh2/archive/libssh2-${LIBSSH2_VERSION}.tar.gz
tar xzf libssh2-${LIBSSH2_VERSION}.tar.gz
cd libssh2-libssh2-${LIBSSH2_VERSION}/
wget "https://github.com/libssh2/libssh2/archive/libssh2-${LIBSSH2_VERSION}.tar.gz"
tar xzf "libssh2-${LIBSSH2_VERSION}.tar.gz"
cd "libssh2-libssh2-${LIBSSH2_VERSION}/"
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DENABLE_ZLIB_COMPRESSION=ON .
cmake --build . --target install
# Compile libgit2
echo "Building libgit2 v${LIBGIT2_VERSION} ..."
wget https://github.com/libgit2/libgit2/archive/v${LIBGIT2_VERSION}.tar.gz
tar xzf v${LIBGIT2_VERSION}.tar.gz
cd libgit2-${LIBGIT2_VERSION}/
wget "https://github.com/libgit2/libgit2/archive/v${LIBGIT2_VERSION}.tar.gz"
tar xzf "v${LIBGIT2_VERSION}.tar.gz"
cd "libgit2-${LIBGIT2_VERSION}/"
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DBUILD_CLAR=OFF -DTHREADSAFE=ON .
cmake --build . --target install
@@ -42,7 +44,7 @@ cmake --build . --target install
echo "Installing python3 packages ..."
DEBIAN_FRONTEND=noninteractive apt-get install --yes --quiet --no-install-recommends \
python3-mako python3-pycryptodome python3-cherrypy3 python3-git python3-u-msgpack \
python3-redis python3-gnupg python3-mysqldb python3-dateutil python3-libnacl
python3-redis python3-gnupg python3-mysqldb python3-dateutil python3-libnacl python3-openssl
# Install pip3 python packages
echo "Installing pip3 python packages ..."
@@ -54,21 +56,26 @@ pip3 install "pygit2==v${PYGIT2_VERSION}" \
## -M: install Salt Master by default
## -N: Do not install salt-minion
## -X: Do not start daemons after installation
## -d: Disables checking if Salt services are enabled to start on system boot
## -P: Allow pip based installations
## -p: Extra-package to install
## -x: Changes the python version used to install a git version of salt
SALT_BOOTSTRAP_OPTS="-M -N -X -P -x python${PYTHON_VERSION}"
SALT_BOOTSTRAP_OPTS=( -M -N -X -d -P -p salt-api -x "python${PYTHON_VERSION}" )
echo "Installing saltstack ..."
echo "Option: ${SALT_BOOTSTRAP_OPTS[@]}"
wget -O bootstrap-salt.sh https://bootstrap.saltstack.com
sh bootstrap-salt.sh ${SALT_BOOTSTRAP_OPTS} git v${SALT_VERSION}
chown -R ${SALT_USER}: ${SALT_ROOT_DIR}
sh bootstrap-salt.sh ${SALT_BOOTSTRAP_OPTS[@]} git "v${SALT_VERSION}"
chown -R "${SALT_USER}": "${SALT_ROOT_DIR}"
# Configure ssh
echo "Configuring ssh ..."
sed -i -e "s|^[# ]*StrictHostKeyChecking.*$| StrictHostKeyChecking no|" /etc/ssh/ssh_config
echo " UserKnownHostsFile /dev/null" >> /etc/ssh/ssh_config
echo " LogLevel ERROR" >> /etc/ssh/ssh_config
echo "# IdentityFile salt_ssh_key" >> /etc/ssh/ssh_config
{
echo " UserKnownHostsFile /dev/null"
echo " LogLevel ERROR"
echo "# IdentityFile salt_ssh_key"
} >> /etc/ssh/ssh_config
# Configure logrotate
echo "Configuring logrotate ..."
@@ -89,7 +96,7 @@ priority=5
directory=${SALT_HOME}
environment=HOME=${SALT_HOME}
command=/usr/local/bin/salt-master
user=${SALT_USER}
user=root
autostart=true
autorestart=true
stopsignal=QUIT

View File

@@ -3,6 +3,9 @@
DEBUG=${DEBUG:-false}
TIMEZONE=${TIMEZONE:-UTC}
SALT_API_SERVICE_ENABLED=${SALT_API_SERVICE_ENABLED:-false}
SALT_API_USER=${SALT_API_USER:-salt_api}
SALT_LOG_ROTATE_FREQUENCY=${SALT_LOG_ROTATE_FREQUENCY:-weekly}
SALT_LOG_ROTATE_RETENTION=${SALT_LOG_ROTATE_RETENTION:-52}

View File

@@ -1,30 +1,36 @@
#!/usr/bin/env bash
set -e
source ${SALT_RUNTIME_DIR}/env-defaults.sh
source "${SALT_RUNTIME_DIR}/env-defaults.sh"
# Execute a command as SALT_USER
function exec_as_salt()
{
if [[ $(whoami) == ${SALT_USER} ]]; then
if [[ $(whoami) == "${SALT_USER}" ]]; then
$@
else
sudo -HEu ${SALT_USER} "$@"
sudo -HEu "${SALT_USER}" "$@"
fi
}
# Log error
function log_error()
{
(>2& echo "ERROR: $*")
}
# Map salt user with host user
function map_uidgid()
{
USERMAP_ORIG_UID=$(id -u ${SALT_USER})
USERMAP_ORIG_GID=$(id -g ${SALT_USER})
USERMAP_ORIG_UID=$(id -u "${SALT_USER}")
USERMAP_ORIG_GID=$(id -g "${SALT_USER}")
USERMAP_GID=${USERMAP_GID:-${USERMAP_UID:-$USERMAP_ORIG_GID}}
USERMAP_UID=${USERMAP_UID:-$USERMAP_ORIG_UID}
if [[ ${USERMAP_UID} != ${USERMAP_ORIG_UID} ]] || [[ ${USERMAP_GID} != ${USERMAP_ORIG_GID} ]]; then
if [[ "${USERMAP_UID}" != "${USERMAP_ORIG_UID}" ]] || [[ "${USERMAP_GID}" != "${USERMAP_ORIG_GID}" ]]; then
echo "Mapping UID and GID for ${SALT_USER}:${SALT_USER} to ${USERMAP_UID}:${USERMAP_GID} ..."
groupmod -o -g ${USERMAP_GID} ${SALT_USER}
groupmod -o -g "${USERMAP_GID}" "${SALT_USER}"
sed -i -e "s|:${USERMAP_ORIG_UID}:${USERMAP_GID}:|:${USERMAP_UID}:${USERMAP_GID}:|" /etc/passwd
find ${SALT_HOME} -path ${SALT_DATA_DIR}/\* \( ! -uid ${USERMAP_ORIG_UID} -o ! -gid ${USERMAP_ORIG_GID} \) -print0 | xargs -0 chown -h ${SALT_USER}: ${SALT_HOME}
find "${SALT_HOME}" -path "${SALT_DATA_DIR}/*" \( ! -uid "${USERMAP_ORIG_UID}" -o ! -gid "${USERMAP_ORIG_GID}" \) -print0 | xargs -0 chown -h "${SALT_USER}": "${SALT_HOME}"
fi
}
@@ -36,25 +42,25 @@ function update_template()
local FILE=${1?missing argument}
shift
[[ ! -f ${FILE} ]] && return 1
[[ ! -f "${FILE}" ]] && return 1
local VARIABLES=($@)
local USR=$(stat -c %U ${FILE})
local VARIABLES=( "$@" )
local USR=$(stat -c %U "${FILE}")
local tmp_file=$(mktemp)
cp -a "${FILE}" ${tmp_file}
cp -a "${FILE}" "${tmp_file}"
local variables
for variable in ${VARIABLES[@]}; do
sed -ri "s|[{}]{2}$variable[}]{2}|\${$variable}|g" ${tmp_file}
for variable in "${VARIABLES[@]}"; do
sed -ri "s|[{}]{2}${variable}[}]{2}|\${${variable}}|g" "${tmp_file}"
done
# Replace placeholders
(
export ${VARIABLES[@]}
local IFS=":"; sudo -HEu ${USR} envsubst "${VARIABLES[*]/#/$}" < ${tmp_file} > ${FILE}
export "${VARIABLES[@]}"
local IFS=":"; sudo -HEu "${USR}" envsubst "${VARIABLES[*]/#/$}" < "${tmp_file}" > "${FILE}"
)
rm -f ${tmp_file}
rm -f "${tmp_file}"
}
# This function configures containers timezone
@@ -63,14 +69,14 @@ function configure_timezone()
echo "Configuring container timezone ..."
# Perform sanity check of provided timezone value
if [ -e /usr/share/zoneinfo/${TIMEZONE} ]; then
if [ -e "/usr/share/zoneinfo/${TIMEZONE}" ]; then
echo "Setting TimeZone -> ${TIMEZONE} ..."
# Set localtime
ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime
ln -snf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime
# Set timezone
echo ${TIMEZONE} > /etc/timezone
echo "${TIMEZONE}" > /etc/timezone
else
echo "Timezone: '${TIMEZONE}' is not valid. Check available timezones at: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"
return 1
@@ -82,39 +88,40 @@ function gen_signed_keys()
{
local key_name=${1:-master}
mkdir -p ${SALT_KEYS_DIR}/generated/
GENERATED_KEYS_DIR=$(mktemp -d -p ${SALT_KEYS_DIR}/generated/ -t ${key_name}.XXXXX)
mkdir -p "${SALT_KEYS_DIR}/generated/"
GENERATED_KEYS_DIR=$(mktemp -d -p "${SALT_KEYS_DIR}/generated/" -t "${key_name}.XXXXX")
salt-key --gen-keys ${key_name} --gen-keys-dir ${GENERATED_KEYS_DIR} > /dev/null 2>&1
salt-key --gen-signature --auto-create --pub ${GENERATED_KEYS_DIR}/${key_name}.pub --signature-path ${GENERATED_KEYS_DIR} > /dev/null 2>&1
salt-key --gen-keys "${key_name}" --gen-keys-dir "${GENERATED_KEYS_DIR}" > /dev/null 2>&1
salt-key --gen-signature --auto-create --pub "${GENERATED_KEYS_DIR}/${key_name}.pub" --signature-path "${GENERATED_KEYS_DIR}" > /dev/null 2>&1
echo -n ${GENERATED_KEYS_DIR}
echo -n "${GENERATED_KEYS_DIR}"
}
# This function repairs keys permissions and creates keys if neaded
function setup_salt_keys()
{
echo "Setting up salt keys ..."
if [ ! -f ${SALT_KEYS_DIR}/master.pem ]; then
if [ ! -f "${SALT_KEYS_DIR}/master.pem" ]; then
echo "Generating keys ..."
salt-key --gen-keys master --gen-keys-dir ${SALT_KEYS_DIR}
salt-key --gen-keys master --gen-keys-dir "${SALT_KEYS_DIR}"
fi
if [ ! -f "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pem" ] && [ ${SALT_MASTER_SIGN_PUBKEY} == True ]; then
if [ ! -f "${SALT_KEYS_DIR}/${SALT_MASTER_SIGN_KEY_NAME}.pem" ] && [ "${SALT_MASTER_SIGN_PUBKEY}" == True ]; then
echo "Generating signed keys ..."
salt-key --gen-signature --auto-create --pub ${SALT_KEYS_DIR}/master.pub --signature-path ${SALT_KEYS_DIR}
salt-key --gen-signature --auto-create --pub "${SALT_KEYS_DIR}/master.pub" --signature-path "${SALT_KEYS_DIR}"
fi
for pub_key in $(find ${SALT_KEYS_DIR} -maxdepth 1 -type f); do
if [[ ${pub_key} =~ .*\.pem$ ]]; then
chmod 400 ${pub_key}
while IFS= read -r -d '' pub_key
do
if [[ "${pub_key}" =~ .*\.pem$ ]]; then
chmod 400 "${pub_key}"
else
chmod 644 ${pub_key}
chmod 644 "${pub_key}"
fi
done
done < <(find "${SALT_KEYS_DIR}" -maxdepth 1 -type f -print0)
find ${SALT_KEYS_DIR}/minions* -maxdepth 1 -type f -exec chmod 644 {} \;
find ${SALT_HOME} -path ${SALT_KEYS_DIR}/\* -prune -o -print0 | xargs -0 chown -h ${SALT_USER}:
find "${SALT_KEYS_DIR}/minions"* -maxdepth 1 -type f -exec chmod 644 {} \;
find "${SALT_HOME}" -path "${SALT_KEYS_DIR}/*" -prune -o -print0 | xargs -0 chown -h "${SALT_USER}":
}
# This function configures ssh keys
@@ -135,16 +142,16 @@ function setup_ssh_keys()
fi
}
# This functions cofigures master service
# This function cofigures master service
function configure_salt_master()
{
echo "Configuring salt-master ..."
echo "Configuring salt-master service ..."
# https://docs.saltstack.com/en/latest/ref/configuration/master.html
exec_as_salt cp -p ${SALT_RUNTIME_DIR}/config/master.yml ${SALT_ROOT_DIR}/master
exec_as_salt cp -p "${SALT_RUNTIME_DIR}/config/master.yml" "${SALT_ROOT_DIR}/master"
# Update main configuration
update_template ${SALT_ROOT_DIR}/master \
update_template "${SALT_ROOT_DIR}/master" \
SALT_USER \
SALT_LOG_LEVEL \
SALT_LEVEL_LOGFILE \
@@ -155,13 +162,73 @@ function configure_salt_master()
SALT_KEYS_DIR
# Update keys configuration
update_template ${SALT_ROOT_DIR}/master \
update_template "${SALT_ROOT_DIR}/master" \
SALT_MASTER_SIGN_PUBKEY \
SALT_MASTER_SIGN_KEY_NAME \
SALT_MASTER_PUBKEY_SIGNATURE \
SALT_MASTER_USE_PUBKEY_SIGNATURE
}
# This function configures salt-api if service is set to be enabled
function configure_salt_api()
{
[[ ${SALT_API_SERVICE_ENABLED} == true ]] || return 0
if [[ -n "${SALT_API_USER}" ]]; then
if [[ ${SALT_API_USER} == "${SALT_USER}" ]]; then
log_error "SALT_API_USER cannot be the same as '${SALT_USER}'"
return 1
fi
if [[ -z "${SALT_API_USER_PASS}" ]]; then
log_error "SALT_API_USER_PASS env variable must be set to create '${SALT_API_USER}' user"
return 2
fi
echo "Creating '${SALT_API_USER}' user for salt-api ..."
adduser --quiet --disabled-password --gecos "Salt API" "${SALT_API_USER}"
echo "${SALT_API_USER}:${SALT_API_USER_PASS}" | chpasswd
unset SALT_API_USER_PASS
fi
echo "Configuring salt-api service ..."
CERTS_PATH=/etc/pki
rm -rf "${CERTS_PATH}/tls/certs/*"
salt-call --local tls.create_self_signed_cert cacert_path="${CERTS_PATH}" CN=docker-salt-master
cat >> "${SALT_ROOT_DIR}/master" <<EOF
##### salt-api settings #####
##########################################
# Basic configuration for salt-api
api_logfile: ${SALT_LOGS_DIR}/salt/api
rest_cherrypy:
port: 8000
ssl_crt: /etc/pki/tls/certs/docker-salt-master.crt
ssl_key: /etc/pki/tls/certs/docker-salt-master.key
EOF
# configure supervisord to start salt-api
cat > /etc/supervisor/conf.d/salt-api.conf <<EOF
[program:salt-api]
priority=5
directory=${SALT_HOME}
environment=HOME=${SALT_HOME}
command=/usr/local/bin/salt-api
user=root
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=${SALT_LOGS_DIR}/supervisor/%(program_name)s.log
stderr_logfile=${SALT_LOGS_DIR}/supervisor/%(program_name)s.log
EOF
}
# Initializes main directories
function initialize_datadir()
{
@@ -169,32 +236,32 @@ function initialize_datadir()
# This symlink simplifies paths for loading sls files
[[ -d /srv ]] && [[ ! -L /srv ]] && rm -rf /srv
ln -sfnv ${SALT_BASE_DIR} /srv
ln -sfnv "${SALT_BASE_DIR}" /srv
# Set Salt root permissions
chown -R ${SALT_USER}: ${SALT_ROOT_DIR}
chown -R "${SALT_USER}": "${SALT_ROOT_DIR}"
# Set Salt run permissions
mkdir -p /var/run/salt
chown -R ${SALT_USER}: /var/run/salt
chown -R "${SALT_USER}": /var/run/salt
# Set cache permissions
mkdir -p /var/cache/salt/master
chown -R ${SALT_USER}: /var/cache/salt
chown -R "${SALT_USER}": /var/cache/salt
# Keys directories
mkdir -p ${SALT_KEYS_DIR}/minions
chown -R ${SALT_USER}: ${SALT_KEYS_DIR}
mkdir -p "${SALT_KEYS_DIR}/minions"
chown -R "${SALT_USER}": "${SALT_KEYS_DIR}"
# Logs directory
mkdir -p ${SALT_LOGS_DIR}/salt ${SALT_LOGS_DIR}/supervisor
chmod -R 0755 ${SALT_LOGS_DIR}/supervisor
chown -R root: ${SALT_LOGS_DIR}/supervisor
mkdir -p "${SALT_LOGS_DIR}/salt" "${SALT_LOGS_DIR}/supervisor"
chmod -R 0755 "${SALT_LOGS_DIR}/supervisor"
chown -R root: "${SALT_LOGS_DIR}/supervisor"
[[ -d /var/log/salt ]] && [[ ! -L /var/log/salt ]] && rm -rf /var/log/salt
mkdir -p ${SALT_LOGS_DIR}/salt /var/log
ln -sfnv ${SALT_LOGS_DIR}/salt /var/log/salt
chown -R ${SALT_USER}: ${SALT_LOGS_DIR}/salt
mkdir -p "${SALT_LOGS_DIR}/salt" /var/log
ln -sfnv "${SALT_LOGS_DIR}/salt" /var/log/salt
chown -R "${SALT_USER}": "${SALT_LOGS_DIR}/salt"
}
# Configures logrotate
@@ -243,6 +310,21 @@ ${SALT_LOGS_DIR}/salt/key {
notifempty
}
EOF
if [[ "${SALT_API_SERVICE_ENABLED}" == true ]]; then
# configure salt-api log rotation
cat >> /etc/logrotate.d/salt <<EOF
${SALT_LOGS_DIR}/salt/api {
${SALT_LOG_ROTATE_FREQUENCY}
missingok
rotate ${SALT_LOG_ROTATE_RETENTION}
compress
notifempty
}
EOF
fi
}
# Initializes the system
@@ -253,6 +335,7 @@ function initialize_system()
configure_logrotate
configure_timezone
configure_salt_master
configure_salt_api
setup_salt_keys
setup_ssh_keys
rm -rf /var/run/supervisor.sock

View File

@@ -3,7 +3,7 @@ version: '3'
services:
master:
container_name: salt_master
image: cdalvaro/saltstack-master:3000.3
image: cdalvaro/saltstack-master:3000.3_1
restart: always
volumes:
- "roots/:/home/salt/data/srv"

View File

@@ -1,29 +1,45 @@
#!/usr/bin/env bash
#!/bin/bash
set -e
set -o pipefail
source "${SALT_RUNTIME_DIR}/functions.sh"
[[ ${DEBUG} == true ]] && set -x
[[ "${DEBUG}" == true ]] && set -x
case ${1} in
app:start|app:init|app:gen-signed-keys)
case "${1}" in
app:start|app:gen-signed-keys)
initialize_system
case ${1} in
case "${1}" in
app:start)
echo "Starting salt-master..."
echo "Starting supervisord ..."
exec /usr/bin/supervisord -nc /etc/supervisor/supervisord.conf
;;
app:gen-signed-keys)
shift 1
gen_signed_keys ${1}
gen_signed_keys "${1}"
;;
esac
;;
app:restart)
shift 1
case "${1}" in
salt-master|salt-api)
echo "Restarting ${1} service ..."
exec pkill "${1}"
;;
*)
log_error "Unable to restart ${1} serice. Service is unknown"
exit 1
;;
esac
;;
app:help)
echo "Available options:"
echo " app:start - Start salt-master service. (default)"
echo " app:start - Start configured services. (default)"
echo " app:restart - Restart the specified service on a running container. Choices: salt-master, salt-api"
echo " app:gen-signed-keys <key_name> - Create a master_sign key pair and its signature inside ${SALT_KEYS_DIR}/generated/"
echo " app:help - Displays this help."
echo " [command] - Execute the specified command, eg. bash."

View File

@@ -3,7 +3,10 @@
# Docker Daemon Build Hook
# $IMAGE_NAME var is injected into the build so the tag is correct.
docker pull ${DOCKER_REPO}:latest
docker build \
--cache-from=${DOCKER_REPO}:latest \
--build-arg=BUILD_DATE="$(date +"%Y-%m-%d %H:%M:%S%:z")" \
--build-arg=VCS_REF="$(git rev-parse --short HEAD)" \
-t ${IMAGE_NAME} .