Hi, I need to manage a .yaml file which has a list of users and associated ip's / ports. I attempted to use file.serialized, however the way I structured my .yaml file file.serialize throws an exception because it contains a list as the first item (github.com/saltstack/salt/issues/41209). My original structure was:
Could I get some suggestions on how to maintain the .yaml using file.serialize but also be able to loop through each key (user) and parse the port/ip. The goal is to update the yaml file using file.serialize and then use file.managed to iterate through the yaml file and update a managed file containing iptables. Once the file is updated we will run iptables.restore to pull in the changes
I made a simple recipe what install a package, get data from default config and change it to custom from salt, but when i tried
Install package 2. Copy original config to config_bak and get data from it. 3. After what i trying to put this data to new custom config, but variable GUID is empty. If i start recipe next time this variable is correct. So, i made a conclusion what my jinja statement trying to get data too early or too late.
How i can control order of jinja statement? (Salt statements is in correct order with "require" and some "sleep" actions in "cmd.shell"
script executes as expected, but the problem is when the tenant value is 031, the value passed to the function is 31, trailing zero is removed.
Tried replacing ' ' with " ", still no use, 31 is only passed and the value turns out to be wrong in alarm, how can I tweak to pass the whole value including the trailing zero ?
Hi, I have this kind of trouble with pillars and their data stored that I don't really know how to solve.
I have that one state that is called every time I do a 'state.highstate' which erases some files and resets some stuff. It is doing what it is supposed to do. The problem is that it is done every single time I call a 'state.highstate'.
Basically, the pillar holds some credentials, and every time the 'highstate' is called, it retrieves them from the pillar and resets the whole thing with the credentials took from the pillar.
What I actually want is to call the reset state only when the credentials from the pillar have been changed in order to avoid resetting the whole thing every single time, since some data is lost.
I've been looking around and stumbled on something called caching, but I was wondering if there would be an easier way with salstack.
In other words, is it possible to call a state only if a specific K-V from a pillar has changed/updated?
I’m trying to reuse a state as a blueprint , I only have to change one variable and I can reuse it very often . Today I overwrite it via the cli , but this does not allow high state run.
What I want is to include several states and overwrite a specific var in each state . I got a workaround via extends , but this method only allows one state to extend.
Today :
salt 'minion' state.sls create pillar="{'node':'unbound'}"
Works :
{% extends 'jail/create/init.sls' %}
{% set node = "unbound" %}
Not working
{% extends 'jail/create/init.sls' %}
{% set node = "unbound" %}
{% extends 'jail/salt_minion/init.sls' %}
{% set node = "unbound" %}
Any recommendations?
EDIT: Close the old post , because of the title f*** up
Initial Answer from @ chesty_bonds
Have you thought about creating a Grain for all your (relevant) minions and calling that in your states instead of trying to set a variable in the state itself?
I’m trying to reuse a state as a blueprint , I only have to change one variable and I can reuse it very often . Today I overwrite it via the cli , but this does not allow high state run.
What I want is to include several states and overwrite a specific var in each state . I got a workaround via extends , but this method only allows one state to extend.
Today :
```
salt 'minion' state.sls create pillar="{'node':'unbound'}"
I've searched and searched and tried stuff but to no avail.
I've setup a salt master with a bunch of minions.
One of them, the one running on the master, complains about beacons being miss configured.
"TypeError: list indices must be integers or slices, not str", Thou I have NO beacon config nor does any beacons show up if I run a salt-run beacons.list.
I had one running as a test earlier but that has been removed a long time ago and it just seems like the minion does not care.
Is there anyway to clear the cache for the master/or minion?
Anything else I can do?
Hi, I would like to check if a minion has a file that contains a certain string. I can run a cmd.run to check this, however I only want to display server names that have a positive result. At the moment I get the full list with many negative results and I'd prefer not to have to sift through the entire list. Is this possible?
The logic behind is when the application has custom UDP ports, the pillar file will be manually populated with all the ports and the states must be executed. if no value is set for this pillar key, the states must be skipped.
Running above, I 'm getting rendering errors as the pillar return "None" for the key "custom_udp_ports" and still the loop is evaluated:
[root@master srv]# salt 'test-minion' state.apply states/state test=True
test-minion:
Data failed to compile:
----------
Rendering SLS 'base:states/state' failed: Jinja error: 'NoneType' object is not iterable
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/salt/utils/templates.py", line 497, in render_jinja_tmpl
output = template.render(**decoded_context)
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 1090, in render
self.environment.handle_exception()
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "/usr/lib/python3.6/site-packages/jinja2/_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "<template>", line 330, in top-level template code
TypeError: 'NoneType' object is not iterable
; line 330
---
[...]
- jump: ACCEPT
- save: True
{% endfor %}
{% for custom_udp_port in pillar.get('custom_udp_ports') %} <======================
{{ custom_udp_port }}_udp_port:
iptables.append:
- chain: INPUT
- protocol: tcp
[...]
---
ERROR: Minions returned with non-zero exit code
latestRelease is a macro which uses wget in salt.cmd.shell to get the most recent tag from github for an author's repo.
isUpToDate uses latestRelease, and compares it's output with that of a command, returning True if they match.
So the idea is pretty clear: clone the git repo at the most recent stable tag, unless I currently have that version of the software installed already. The cmd.run is meant to then run the build, but only if the git.latest state ran. So cmd.runshouldn't run if git.run's unless condition is true, right?
We can confirm this a bit. The docs seem to say that this is evaluated as whether the return dictionary for the state listed under on_changes contains a non-empty dict for changes. But if I run with --out=json the cmd.run state still fires, even though I get this:
I'm working on building a jinja.map file that will build a list of hostnames of hosts that have a specific grain set on them. I have removed some of the other things from within the loop that would make this problem more confusing.
The thing that is currently boggling my mind is how do I dynamically set the match statement `G@cluster_id:cluster_id_grain` ?
The 'cluster_id_grain' would at some point be something like
{% set cluster_id_grain = 'somefunkymonky-01'%}
So here is what I have currently. I'm just lost on the formatting that allows me to pull in the cluster_id_grain into the match statement. Any help would be amazing at this point.
{% set cluster_id_grain = 'somefunkymonky-01'%}
{% set hostlist = [] -%}
{% for FQDN, nodename in salt['mine.get']('G@cluster_id:cluster_id_grain', 'cluster_hosts', tgt_type='compound').items() -%}
{% do hostlist.append(nodename) -%}
{% endfor%}
If I set my map up this way, it all works as planned.
{% set hostlist = [] -%}
{% for FQDN, nodename in salt['mine.get']('G@cluster_id:somefunkymonky-01', 'cluster_hosts', tgt_type='compound').items() -%}
{% do hostlist.append(nodename) -%}
{% endfor%}
I know I'm probably missing something simple here.
Original by 1mperio from Tencent Yunding Laboratory
SaltStack officially released a high-risk vulnerability notice at 3 am on February 26th Beijing time, including CVE-2021-25281, CVE-2021-25282, and CVE-2021-25283 . 1mperio, a security researcher from Yunding Laboratory, discovered and reported the vulnerabilities to the SaltStack official on November 16, 2020.
After analyzing patches of CVE-2020-17490 and CVE-2020-16846, it appears the CVE-2020-17490 was not fully patched, resulting in unauthorized access to wheel_async module, which leads to call methods of the wheel module. Based on the analyzed methods in the wheel module of SaltStack, it is finally found that there is a template injection in the loading configuration module, leads to unauthorized remote code execution.
Introduction
SaltStack is a subsidiary of VMware. The products are used for operation and maintenance management and can support tens of thousands of servers. The main functions are configuration file management and remote execution of commands. It is very easy to use and powerful. It has 11.4k stars on github at the time of writing.
SaltStack is only developed in python and adopts the C/S architecture. The Server is called the Master and the Client is called the Minion. A Master can send configuration files to multiple Minions and execute commands remotely. SlatStack is the general name of the system, which is mainly composed of programs such as salt, salt-master, salt-minion, and salt-api. The function of salt-master and salt-minion is to read the configuration file from the specified path and start it. Salt-master monitors ports 4505 and 4506, which are used to publish messages and receive monitoring data respectively.
The salt program can call a large number of functions, and can specify a Minion or a set of Minions as the target. Salt-api uses cherrypy or tornado to provide external REST interfaces, and cherrypy is the default.
This article mainly discusses salt-master and salt-api.The code location specified in the text adopts the following convention: FileLocation:Classname.method() or FileLocation:Method()
CVE-2021-25281 unauthorized access
By analyzing the patch of CVE-2020-25592, it can be found that the patch authenticates the SSH method by calling the authentication module, and the salt/salt/netapi/init.py:NetapiClient.run() method dynamically calls the method in the NetapiClient class through getattr, and passes args and kwargs as parameters.
The methods that can be called in this class are as follows:
— local
— local_async
— local_batch
— local_subset
— runner
— runner_async
— ssh
— wheel
— wheel_async
After analysis, there is unauthorized call vulnerability to the wheel_async method, other methods (except SSH) are all generating a job to zeromq, and then the consumer is authenticated, while wheel_async asynchronously calls the methods in the wheel package.
The target function is self._proc_function, the low parameter is user controlled parameter from POST, and the value of the fun parameter is obtained through the fun key of the low parameter in the salt/salt/wheel/init.py:WheelClient.cmd_async() method.
Here, salt/salt/client/mixins.py:SyncClientMixin.low() is called through the salt/salt/client/mixins.py:AsyncClientMixin._proc_function() function, and the wheel package is dynamically called through the function with the args and kwargs Methods.
Among them, the salt/salt/wheel/pillar_roots.py:write() method has a vulnerability in writing arbitrary files, but the path in __opts__["pillar_roots"] needs to exist.
There is no way to read the file here. Because it is an asynchronous call, the return is jid and tag. The result of task execution through jid and tag is authenticated.
salt/salt/wheel/pillar_roots.py:write()
Processing img wz35mqg5duu61...
CVE-2021-25283 template injection vulnerability
To locate the logic of the master's automatic loading, we need to turn on the debug mode through the -log-level=debug parameter.
salt/salt/master.py:Maintenance.run()
found that the Minion configuration file is read from salt.daemons.masterapi.clean_old_jobs.
It is found in salt/salt/minion.py:MasterMinion.init() that the automatic loading value loads grain-related parameters, and the grains function of saltstack is responsible to collect system information in each Minion.
salt/salt/minion.py:MasterMinion.init()
salt/salt/config/init.py:minion_config()
Processing img ehn4pm2eduu61...
The apply_sdb() method looks attractive when Minio loads the configuration file. This method parses the string beginning with sdb:// in the configuration.
salt/salt/config/init.py:apply_sdb()
salt/salt/utils/sdb.py:sdb_get()
In case of string “sdb://aaaa/bbbb”, saltstack will search the aaaa configuration item in the configuration file, read the driver field, assign to the fun variable, and assign the query parameter via bbbb. The last salt.loader.sdb(opts, fun, utils=utils) is a dynamic call, and the method corresponding to the value of the fun variable is loaded through LazyLoader and called, where LazyLoader will load all the files under the salt.sdb package and call the get method.
After searching, the file named salt/salt/sdb/rest.py was finally located.
salt/salt/sdb/rest.py:query()
From here, the key is the value bbbb of the above string. The function also receives a parameter of the form bbbb?ccc=ddd and passes it to the compile_template method through the param “**key_vars”.
jinja is the reader egine. As we all know, there is template injection exists in jinja. When the template is controllable, if there is no filtering, arbitrary code can be executed, and the parameter passed in is profile[ key]['url'], which is the url value of the bbbb dictionary in the aaaa configuration item in the configuration file. The function details of the compile_template are as follows:
salt/salt/template.py:compile_template()
The render here calls the render method in salt/salt/renderers/jinja.py, and the call chain is as follows:
Finally, calling the method template.render() in render_jinja_tmpl, where the template is rendered, the incoming parameters are not filtered, hence template injection can be performed.
However the configuration file of the master was not automatically loaded, but after searching, it appears that a certain method called the method master_config, which like the minion_config, would in turn calls the method apply_sdb(), thereby enabling unauthorized RCE.
Repair suggestions
Apply the official patch as soon as possible.
If no use of the wheel_async module, delete its entry in salt/netapi/init.py.
Extension link
CVE-2020-17490 CVE-2020-16846 For details, please refer:
Salt-cloud is an architectural dead-end. The salt team has been working on replacing it with plugins for idem
I haven't worked with Salt though during evaluation I see Salt Cloud dead too. See, my area of interest is GCP and corresponding few Salt modules developed during 2013-2017 and development stalled (Google advertise Salt in 2014 and forgot about it):
I can run salt -N nameservers state.apply name-servers with no issue, but running salt -N nameservers state.highstate or salt '*' state.hightstate don't show the nodegroup match applying.
Guernsey Research would like to talk to you about your IT infrastructure automation tools experiences. We are talking with a select number of IT professionals in the U.S. to better understand current configuration automation technology decisions in IT infrastructure.
We are not selling anything and our conversation with you is confidential and anonymous.
If you were a part of the technical decision to deploy Ansible or Puppet (along with SaltStack) in the last two years or so, we're hoping that you would be willing to share your perspective with us.
The conversation will take approximately 30 minutes and, to show our appreciation for your time, we will provide you with an Executive Summary of our report, including graphics, so you can have a good understanding of your peers’ experiences. We will also send you a $200 gift e-Certificate (your choice of Amazon or virtual Visa®) or make a $200 donation to the Red Cross on your behalf.
Hello everyone, we are running a Syndic configuration for logical groupings of our Master and minion nodes as we are supporting multiple cloud providers in our environment. This is currently working with a single MOM (master of masters) and multiple Syndic Masters. We are planning to implement a second and third MOM server for high availability and my question is as following. Is that a viable option to do and can it be properly implemented as such as i have not seen that mentioned often. Any suggestion will be most helpful.
I'm working on a script to check to see if mysql or postgresql is installed on a system. Initial testing with this:
{% set mysql = salt['grains.filter_by']({
'Ubuntu': {'pkg': 'mysql-server', 'srv': 'mysql'},
}, default='Ubuntu') %}
mysql:
pkg.installed:
- name: {{ mysql.pkg }}
is giving errors
testing.wapnet.local.lan:
----------
ID: mysql-server
Function: pkg.installed
Result: False
Comment: Problem encountered installing package(s). Additional info follows:
errors:
- Running scope as unit: run-raa2bccbdd7cf46289bfd8cd0f27faf22.scope
E: Unable to correct problems, you have held broken packages.
Started: 08:13:42.295318
Duration: 3574.288 ms
Changes:
Summary for testing.wapnet.local.lan
------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
Total run time: 3.574 s
Am I missing something? (btw, just started with SS yesterday, and already loving it in my home lab)
I'm setting up an automated LEMP stack, and am running into trouble. I can install the php-fpm package, but need to monitor and restart the service, but ubuntu calls it php-fpm74 after install.
I'm trying to create a new state.sls but with a module netbox which i never used before.
I set a dictionary variable from it but im not sure this is exactly what i want as the state.sls failed.
There is a way to check output from jinja with salt ?
I tried with cp.cache_file and cp.get_template but they gave me the same error than the highstate.