#!/usr/bin/env python3 # # Copyright (C) 2018 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # import sys import os import pwd import socket import urllib3 import jinja2 from vyos.config import Config from vyos import ConfigError config_file = r'/etc/salt/minion' # Please be careful if you edit the template. config_tmpl = """ ### Autogenerated by salt-minion.py ### ##### Primary configuration settings ##### ########################################## # The hash_type is the hash to use when discovering the hash of a file on # the master server. The default is sha256, but md5, sha1, sha224, sha384 and # sha512 are also supported. # # WARNING: While md5 and sha1 are also supported, do not use them due to the # high chance of possible collisions and thus security breach. # # Prior to changing this value, the master should be stopped and all Salt # caches should be cleared. hash_type: {{ hash_type }} ##### Logging settings ##### ########################################## # The location of the minion log file # The minion log can be sent to a regular file, local path name, or network # location. Remote logging works best when configured to use rsyslogd(8) (e.g.: # ``file:///dev/log``), with rsyslogd(8) configured for network logging. The URI # format is: <file|udp|tcp>://<host|socketpath>:<port-if-required>/<log-facility> #log_file: /var/log/salt/minion #log_file: file:///dev/log #log_file: udp://loghost:10514 # log_file: {{ log_file }} # The level of messages to send to the console. # One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'. # # The following log levels are considered INSECURE and may log sensitive data: # ['garbage', 'trace', 'debug'] # # Default: 'warning' log_level: {{ log_level }} # Set the location of the salt master server, if the master server cannot be # resolved, then the minion will fail to start. master: {% for host in master -%} - {{ host }} {% endfor %} # The user to run salt user: {{ user }} # The directory to store the pki information in pki_dir: /config/salt/pki/minion # Explicitly declare the id for this minion to use, if left commented the id # will be the hostname as returned by the python call: socket.getfqdn() # Since salt uses detached ids it is possible to run multiple minions on the # same machine but with different ids, this can be useful for salt compute # clusters. id: {{ salt_id }} # The number of minutes between mine updates. mine_interval: {{ mine_interval }} verify_master_pubkey_sign: {{ verify_master_pubkey_sign }} """ default_config_data = { 'hash_type': 'sha256', 'log_file': '/var/log/salt/minion', 'log_level': 'warning', 'master' : 'salt', 'user': 'minion', 'salt_id': socket.gethostname(), 'mine_interval': '60', 'verify_master_pubkey_sign': 'false' } def get_config(): salt = default_config_data conf = Config() if not conf.exists('service salt-minion'): return None else: conf.set_level('service salt-minion') if conf.exists('hash_type'): salt['hash_type'] = conf.return_value('hash_type') if conf.exists('log_file'): salt['log_file'] = conf.return_value('log_file') if conf.exists('log_level'): salt['log_level'] = conf.return_value('log_level') if conf.exists('master'): master = conf.return_values('master') salt['master'] = master if conf.exists('id'): salt['salt_id'] = conf.return_value('id') if conf.exists('user'): salt['user'] = conf.return_value('user') if conf.exists('mine_interval'): salt['mine_interval'] = conf.return_value('mine_interval') salt['master-key'] = None if conf.exists('master-key'): salt['master-key'] = conf.return_value('master-key') salt['verify_master_pubkey_sign'] = 'true' return salt def generate(salt): paths = ['/etc/salt/','/var/run/salt','/opt/vyatta/etc/config/salt/'] directory = '/opt/vyatta/etc/config/salt/pki/minion' uid = pwd.getpwnam(salt['user']).pw_uid http = urllib3.PoolManager() if salt is None: return None if not os.path.exists(directory): os.makedirs(directory) tmpl = jinja2.Template(config_tmpl) config_text = tmpl.render(salt) with open(config_file, 'w') as f: f.write(config_text) path = "/etc/salt/" for path in paths: for root, dirs, files in os.walk(path): for usgr in dirs: os.chown(os.path.join(root, usgr), uid, 100) for usgr in files: os.chown(os.path.join(root, usgr), uid, 100) if not os.path.exists('/opt/vyatta/etc/config/salt/pki/minion/master_sign.pub'): if not salt['master-key'] is None: r = http.request('GET', salt['master-key'], preload_content=False) with open('/opt/vyatta/etc/config/salt/pki/minion/master_sign.pub', 'wb') as out: while True: data = r.read(1024) if not data: break out.write(data) r.release_conn() return None def apply(salt): if salt is not None: os.system("sudo systemctl restart salt-minion") else: # Salt access is removed in the commit os.system("sudo systemctl stop salt-minion") os.unlink(config_file) return None if __name__ == '__main__': try: c = get_config() generate(c) apply(c) except ConfigError as e: print(e) sys.exit(1)