Skip to content

mikesager/saltstack-master

 
 

Repository files navigation

SaltStack Ubuntu Image Publish Workflow Docker Image Size CodeFactor

Dockerized SaltStack Master Sodium v3001.1

Dockerfile to build a SaltStack Master image for the Docker opensource container platform.

SaltStack Master is set up in the Docker image using the install from git source method as documented in the the official bootstrap documentation.

For other methods to install SaltStack please refer to the Official SaltStack Installation Guide.

Table of Contents

Installation

Automated builds of the image are available on Dockerhub and is the recommended method of installation.

docker pull cdalvaro/saltstack-master:3001.1

You can also pull the latest tag which is built from the repository HEAD

docker pull cdalvaro/saltstack-master:latest

or from Quay.io too.

docker pull quay.io/cdalvaro/saltstack-master:latest

Alternatively you can build the image locally.

docker build -t cdalvaro/saltstack-master github.com/cdalvaro/saltstack-master

Quick Start

The quickest way to get started is using docker-compose.

wget https://raw.githubusercontent.com/cdalvaro/saltstack-master/master/docker-compose.yml

Start SaltStack master using:

docker-compose up --detach

Alternatively, you can manually launch the saltstack-master container:

docker run --name salt_master --detach \
    --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:3001.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.

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.

It is also important to know that, in order to keep your keys after removing the container, the keys directory must be mounted.

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 --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:3001.1

Master Signed Keys

It is possible to use signed master keys by establishing the environment variable SALT_MASTER_SIGN_PUBKEY to True.

docker run --name salt_stack --detach \
    --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:3001.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.

Additionally, you can generate new keys by executing the following command:

docker run --name salt_stack -it --rm \
    --volume $(pwd)/keys/:/home/salt/data/keys/ \
    cdalvaro/saltstack-master:3001.1 \
    app:gen-signed-keys new_master_sign

The newly created keys will appear inside keys/generated/new_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:

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.

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:3001.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:

external_auth:
  pam:
    salt_api:
      - .*

More information is available in the following link: External Authentication System (eAuth).

Now you have your saltstack-master docker image ready to accept external authentications and to connect external tools such as 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:
pip3 install salt-pepper
Configuration

Then configure pepper by filling your ~/.pepperrc file with your salt-api credentials:

[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:

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.

Also the container processes seem to be executed as the host's user/group 1000. The container can be configured to map the uid and gid of git to different ids on host by passing the environment variables USERMAP_UID and USERMAP_GID. The following command maps the ids to the current user and group on the host.

docker run --name salt_stack -it --rm \
    --publish 4505:4505 --publish 4506:4506 \
    --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:3001.1

Git Fileserver

This image uses GitPython and PyGit2 as gitfs backends to allow Salt to serve files from git repositories.

It can be enabled by adding gitfs to the fileserver_backend list (see Available Configuration Parameters), and configuring one or more repositories in 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:

ssh-keygen -f gitfs_pygit2 -C '[email protected]'

Place it wherever you want inside the container and specify its path with the configuration parameters: gitfs_pubkey and gitfs_privkey in your .conf file.

For example:

gitfs_provider: pygit2
gitfs_privkey: /home/salt/data/keys/gitfs/gitfs_ssh
gitfs_pubkey: /home/salt/data/keys/gitfs/gitfs_ssh.pub

Important Note

If you get the following error while using gitfs with pygit2

_pygit2.GitError: Failed to authenticate SSH session: Unable to send userauth-publickey request

look if your private key hash empty lines at the bottom of the file and suppress them for solving the error.

3rd Party Formulas

You can add third party formulas to your configuration simply by adding them to your gitfs_remotes:

# fileserver.conf
fileserver_backend:
  - roots
  - gitfs

# gitfs.conf
gitfs_provider: pygit2
gitfs_remotes:
  - https://github.com/saltstack-formulas/apache-formula
  - https://github.com/aokiji/salt-formula-helm.git

This is the SaltStack recommended way of doing it, and you can go to the Git Fileserver section on this document if you need help configuring this service.

You can find a great set of formulas on the following GitHub repositories:

Although, as mention in SaltStack documentation, you are encouraged to fork desired formulas to avoid unexpected changes to your infrastructure.

However, sometimes you may need to load some formulas that are not available on a git repository and you want to have them separated from your main srv directory.

For that case, you can mount a volume containing all your third party formulas separeted in subdirectories into /home/salt/data/3pfs/, and they will be automatically added to the master configuration when your container starts.

# 3pfs directory content
3pfs
├── custom-formula
├── golang-formula
└── vim-formula
docker run --name salt_stack -it --rm \
    --publish 4505:4505 --publish 4506:4506 \
    --env "USERMAP_UID=$(id -u)" --env "USERMAP_GID=$(id -g)" \
    --volume $(pwd)/roots/:/home/salt/data/srv/ \
    --volume $(pwd)/3pfs/:/home/salt/data/3pfs/ \
    --volume $(pwd)/keys/:/home/salt/data/keys/ \
    cdalvaro/saltstack-master:3001.1

If you need to add more third party formulas, you can restart the container, or you can type the following command:

docker exec -it salt_stack /sbin/entrypoint.sh app:reload-3rd-formulas

file_roots base configuration file will be updated with current existing formulas and salt-master service will be restarted to reload the new configuration.

Logs

Salt logs are accessible by mounting the volume /home/salt/data/logs/.

Inside that directory you could find supervisor/ logs and salt/ logs:

docker run --name salt_master --detach \
    --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:3001.1

Check Available Configuration Parameters section for configuring logrotate.

Healthcheck

This image includes a health check script: /usr/local/sbin/healthcheck (although it is disable by default). It is useful to check if the salt-master service is alive and responding.

If you are running this image under k8s, you can define a liveness command as explained here.

If you use docker-compose as your container orchestrator, you can add the following entries to your compose file:

version: '3'

services:
  master:
    container_name: salt_master
    image: cdalvaro/saltstack-master:3001.1
    healthcheck:
      test: ["CMD", "/usr/local/sbin/healthcheck"]
      start_period: 30s

(More info available at compose file official documentation)

Or, if you launch your container with docker:

docker run --name salt_master --detach \
    --publish 4505:4505 --publish 4506:4506 \
    --health-cmd='/usr/local/sbin/healthcheck' \
    --health-start-period=30s \
    --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:3001.1

Then you can manually check this info by running the following command:

docker inspect --format "{{json .State.Health }}" salt_master | jq

Then, the output will be something similar to this:

{
  "Status": "healthy",
  "FailingStreak": 0,
  "Log": [
    {
      "Start": "2020-05-23T16:47:55.1046568Z",
      "End": "2020-05-23T16:48:02.3381442Z",
      "ExitCode": 0,
      "Output": "local:\n    True\n"
    }
  ]
}

Available Configuration Parameters

Please refer the docker run command options for the --env-file flag where you can specify all required environment variables in a single file. This will save you from writing a potentially long docker run command. Alternatively you can use docker-compose.

Below is the list of available options that can be used to customize your SaltStack master installation.

Parameter Description
DEBUG Set this to true to enable entrypoint debugging.
TIMEZONE Set the container timezone. Defaults to UTC. Values are expected to be in Canonical format. Example: Europe/Madrid. See the list of acceptable values.
SALT_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 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
SALT_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_ROOT_USER Forces salt-master to be runned 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
USERMAP_UID Sets the uid for user salt to the specified uid. Default: 1000.
USERMAP_GID Sets the gid for user salt to the specified gid. Default: 1000.

Any parameter not listed in the above table and available in the following link, can be set by creating the directory config and adding into it a .conf file with the desired parameters:

mkdir config
cat > config/ports.conf << EOF
# The tcp port used by the publisher:
publish_port: 3505
# The port used by the communication interface.
ret_port: 3506
EOF

docker run --name salt_master -d \
    --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:3001.1

Usage

To test which salt minions are listening the following command can be executed directly from the host machine:

docker exec -it salt_master salt '*' test.ping

Then, you can apply salt states to your minions:

docker exec -it salt_master salt '*' state.apply [state]

Shell Access

For debugging and maintenance purposes you may want access the container shell. If you are using docker version 1.3.0 or higher you can access a running container shell using docker exec command.

docker exec -it salt_master bash

Restart Services

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)

References

About

🐳🧂 Dockerized SaltStack Master

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Shell 80.4%
  • Dockerfile 12.8%
  • Makefile 6.8%