Salt state to change permissions on a single existing file - salt-stack

I know this is probably something super easy that I am just overlooking. For the life of me, I don't see an existing salt state that one can use to simply change the permissions on an already existing file. There's a file.managed state that can be used to "create" a file based on source but what if you just want to insure the permissions on a file that is not created through salt has the correct permission and update them if not.
For example, I can create a state like the following:
base security tcpd host-allows:
file.managed:
- name: /etc/hosts.allow
- create: False
- user: root
- group: root
- mode: 644
However, when I apply this state, I get a warning:
[WARNING ] State for file: /etc/hosts.allow - Neither 'source' nor 'contents' nor 'contents_pillar' nor 'contents_grains' was defined, yet 'replace' was set to 'True'. As there is no source to replace the file with, 'replace' has been set to 'False' to avoid reading the file unnecessarily.
Is there a better way to handle something like this?

Yes, file.managed is used to modify file content but it also has a replace argument which can be used to change only permissions and ownership.
See https://docs.saltstack.com/en/latest/ref/states/all/salt.states.file.html#salt.states.file.managed
replace
: True
If set to False and the file already exists, the file will not be modified even if changes would otherwise be made. Permissions and ownership will still be enforced, however.

Related

How to grant one particular user read access to a unix file

I want to give one particular user read access to a file on a unix machine. I am not root so I guess I can not do chown.
I tried searching for something that uses chmod, but there it looks like I can't specify a particular user, only a one-self, group, or all.
I guess this was asked before already, but I couldn't find anything.
Generally when you want more fine-grained permissions in Linux, you should use Access Control Lists. The Arch Wiki has a good guide on how to set it up.
Once set up, you can define more complex rules for modifying the access control policies for your mounted filesystem.
You can set these rules with commands that look like: setfacl -m "u:johny:r-x" abc.
This says "Give (user) Johny read and execute permissions to the file/directory specified by the path abc".
You would then also be able to see the permissions for a filesystem object using getfacl
root#testvm:/var/tmp# getfacl appdir/
# file: appdir/
# owner: root
# group: appgroup
user::rwx
group::rwx
group:testusers:r--
mask::rwx
other::r-x
In this example you can see the default for any user/group which is not (in) the testusers group, can read, write, or execute the directory. But testusers can only read.
The traditional, Unix way is, as you suggest, to chown the file and set permissions that way.
You might also be able to use access control lists (ACLs). Have a look for the getfacl and setfacl commands (link). The bad news is that ACLs are not always enabled and the default OS install doesn't always include the commands, which doesn't help you if you don't have root.

What is the best means of securely delivering minion specific files using Salt?

I have a number of files that I need to transfer to specific minion hosts in a secure manner, and I would like to automate that process using Salt. However, I am having trouble figuring out the best means of implementing a host restricted transfer.
The salt fileserver works great for non-host-specific transfers. However, some of the files that I need to transfer are customer specific and so I need to ensure that they are only accessible from specific hosts. Assumedly Pillar would be the ideal candidate for minion specific restrictions, but I am having trouble figuring out a means of specifying file transfers using pillar as the source.
As far as I can tell Pillar only supports SLS based dictionary data, not file transfers. I’ve tried various combinations of file.managed state specifications with paths constructed using various convolutions (including salt://_pillar/xxx), but thus far I have not been able to access anything other than token data defined within an SLS file.
Any suggestions for how to do this? I am assuming that secure file transfers should be a common enough need that there should be a standard means of doing it, as opposed to writing a custom function.
The answer depends on what exactly you're trying to secure. If only a part of the files involved are "sensitive" (for example, passwords in configuration files), you probably want to use a template that pulls the sensitive parts in from pillar:
# /srv/salt/app/files/app.conf.jinja
[global]
user = {{ salt['pillar.get']("app:user") }}
password = {{ salt['pillar.get']("app:password") }}
# ...and so on
For this case you don't need to care if the template itself is accessible to minions.
If the entire file(s) involved are sensitive, then I think you want to set up the file_tree external pillar, and use file.managed with the contents_pillar option. That's not something I've worked with, so I don't have a good example.
Solution Synopsis: Using PILLAR.FILE_TREE
A: On your master, set-up a directory from which you will server the private files (e.g: /srv/salt/private).
B: Beneath that create a “hosts” subdirectory, and then beneath that create a directory for each of the hosts that will have private files.
/srv/salt/private/hosts/hostA
/srv/salt/private/hosts/hostB
… where hostA and hostB are the ids of the target minions.
See the docs if you want to use node-groups instead of host ids.
C: Beneath the host dirs, include any files you want to transfer via pillar.
echo “I am Foo\!” > /srv/salt/private/hosts/hostA/testme
D: In your master config file (e.g: /etc/salt/master), include the following stanza:
ext_pillar:
- file_tree:
root_dir: /srv/salt/private
follow_dir_links: False
keep_newline: True
debug: True
E: Create a salt state file to handle the transfer.
cat > /srv/salt/files/base/foo.sls << END
/tmp/pt_test:
file.managed:
- contents_pillar: testme
END
F: Run pillar refresh, and then run your state command:
salt hostA state.apply foo
Following the last step, hostA should have a file named /tmp/pt_test that contains the text “I am Foo!”.

load_file returns NULL in Mariadb without error. Where is the reason for this failure logged?

System information:
Linux Fedora 26
Mariadb version 10.1.25
I have executed all the statements as described in MariaDB Insert BLOB Image.
In addition I have also disabled selinux.
But load_file still returns NULL without giving an error.
I followed these instructions (https://mariadb.com/kb/en/the-mariadb-library/general-query-log/) to enable general logging but 'queries.log' only reports that the query has been executed without giving information on why it returns NULL instead of the wanted output.
Does Mariadb log the reason for this failure? If so, where?
Verify the rest of the constraints:
LOAD_FILE(file_name)
Reads the file and returns the file contents as a string. To use this function, the file must be located on the server host, you must specify the full path name to the file, and you must have the FILE privilege. The file must be readable by all and its size less than max_allowed_packet bytes. If the secure_file_priv system variable is set to a nonempty directory name, the file to be loaded must be located in that directory.
If the file does not exist or cannot be read because one of the preceding conditions is not satisfied, the function returns NULL.
The character_set_filesystem system variable controls interpretation of file names that are given as literal strings.
You need ALL directories in the path have SET executable bit

SaltStack: Get logged in user name

I'm trying to use Salt to set up my dev environment so that it can be identical to my staging environment. One of the things I need to do is add some environment variables to the current users .bashrc file.
I currently have this in my .sls file:
/home/fred/.bashrc:
file.append:
- text:
- export GOROOT=/usr/local/go
- export GOPATH=/home/fred/dev/go
- export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
I then use salt-call to run the state locally under root (since there are other things that I need root for). This isn't ideal, however, if you name isn't fred. How can I rewrite this so that it will work for the current user even when salt-call is run under root?
It seems like I can get to the name of the machine, so if the machine name is something like username-dev, would I be able to parse that somehow and replace all of the instances of fred with the new username? Is there a better way?
This method will gives you the ability to submit different username per one time. I assumed that you don't have a specific users list
/home/{{ pillar.newuser }}/.bashrc:
file.append:
- text:
- export GOROOT=/usr/local/go
- export GOPATH=/home/fred/dev/go
- export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
the commandline:
salt-call state.sls golang_env pillar='{"newuser": "fred"}'
But if you have a specific users list then you can follow this method as mentioned at the docs

How do I manage minion roles with salt-stack pillars?

I'm trying to understand how to use Salt with roles like Chef can be used, but I have some holes in my understanding that reading lots of docs has failed to fill at this point.
The principle issue is that I'm trying to manage roles with Salt, like Chef does, but I don't know how to appropriately set the pillar value. What I want to do is assign, either by script or by hand, a role to a vagrant box and then have the machine install the appropriate files on it.
What I don't understand is how I can set something that will tell salt-master what to install on the box given the particular role I want it to be. I tried setting a
salt.pillar('site' => 'my_site1')
in the Vagrantfile and then checking it in the salt state top.sls file with
{{ pillar.get('site') == 'my_site1'
-<do some stuff>
But this doesn't work. What's the correct way to do this?
So, it becomes easier when matching ids in pillars. First, set the minion_id to be something identifiable, for example test-mysite1-db (and above all unique. Hence the username initials at the end as an example.
in the top.sls in /srv/pillar do
base:
'<regex_matching_id1>':
- webserver.mysite1
'<regex_matching_id2>':
- webserver.mysite2
And then in webserver.mysite1 put
role : mysiteid1
for example.
Then in /srv/state/top.sls you can then match with jinja or just with
base:
'role:mysiteid1':
- match: pillar
- state
- state2
Hence, roles derived from the ids. Works for me.
How to implement and utilize roles is intentionally vague in the salt documentation. Every permutation of how to implement, and then how to use, roles carries with it trade-offs -- so it is up to you to decide how to do it.
In your scenario I can assume that you want rather singular 'roles' or purposes associated with a virtualbox VM, and then have state.highstate run the states associated with that role.
If the above is correct, I would go with grains rather than pillars while learning salt for the sake of simplicity.
On each minion
Just add role: webserver to /etc/salt/grains and restart the salt-minion.
On the master
Update /srv/state/top.sls file to then associate state .sls files with that grain.
base:
'*':
- fail2ban
role:webserver:
- match: grain
- nginx
role:dbserver:
- match: grain
- mysql

Resources