Ansible to update sshd config file - unix

I'm writing an Ansible play to automate new user creation in 100+ Unix servers. I've got the part right where it creates an user and assigns password. But our organization hardening policy demands, whenever a new user is added, username must be updated in "AllowUsers" parameter of sshd_config file. I'm new to Ansible and have no clue how to get this done.
Here's "AllowUsers" section of sshd_config file.
AllowUsers root user1 user2 user2
This is how it should be after adding a new user "testuser"
AllowUsers root user1 user2 testuser

I searched for solution that doesn't do anything if the user already is on the list. This is how it should work in Ansible. My solution at first searches for the user and only if the user is not on the list it will be added.
tasks:
- name: Check if bamboo user already is in SSHD AllowUsers list
command: grep -P '^[ \t]*AllowUsers[ \t]+([-\w ]+[ \t]+)*bamboo([ \t]+.+)*$' /etc/ssh/sshd_config
register: allow_users_exists
changed_when: no
ignore_errors: yes
- name: Allow bamboo user SSH login
lineinfile:
regexp: ^[ \t]*AllowUsers([ \t]+.*)$
line: AllowUsers bamboo\1
dest: /etc/ssh/sshd_config
backrefs: yes
validate: sshd -t -f %s
when: allow_users_exists.rc != 0
notify:
- reload sshd
handlers:
- name: reload sshd
service:
name: sshd
state: reloaded
In this special case I'm searching for static user "bamboo". You could use a variable instead like this:
command: grep -P '^[ \t]*AllowUsers[ \t]+([-\w ]+[ \t]+)*{{ username | regex_escape() }}([ \t]+.+)*$' /etc/ssh/sshd_config
and
line: AllowUsers {{ username }}\1
Results
In:
AllowUsers ubuntu #sdfd
Out:
AllowUsers bamboo ubuntu #sdfd
In:
AllowUsers ubuntu
Out:
AllowUsers bamboo ubuntu
In:
AllowUsers ubuntu bamboo
Out:
AllowUsers ubuntu bamboo

with lineinfile module match regexp of the line say "^AllowUsers .+" and construct the line with new user name. some sample example
- command: grep "^AllowUsers " /etc/ssh/sshd_config
register: old_user_list
- lineinfile:
regexp: "^AllowUsers .+"
line: "{{ old_user_list.stdout }} {{new-user-name}}"
when: old_user_list.rc == 0

Related

cloud-init instance cloud config runcmd commands not executed in openstack

I am creating the instance in openstack with centos 8 hardened image. The configuration script as follows:
#cloud-config
users:
- name: clouduser
password: password
sudo: ['ALL=(ALL) ALL']
groups: sudo
shell: /bin/bash
ssh_pwauth: True
lock_passwd: False
plain_text_passwd: password
runcmd:
- mkdir /run/test
here the user is created and I am able to login the instance but the commands in runcmd is not executed . even the runcmd log in /var/log/cloud-init.log is ran successfully but there is no folder is created in the /run/ folder and /etc/cloud/cloud.cfg is no change (runcmd module in cloud-config and script-user in cloud-finish are there and its executed successfully) but no commands got executed. the same commands if I run inside the instance its working fine. commands in bootcmd is also working but not with runcmd? I can't figure out why it's not being executed?

PermitrootLogin no in sshd but sshd -T shows permitrootlogin yes

so I've set up "PermitRootLogin no" in /etc/sshd_config and I have restarted the sshd service but the root user can still login via ssh.
Further investigation shows that the run-time config differs from the sshd_config file:
[root#CEBECOM-Hq5AT03 ~]# grep PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin no
[root#CEBECOM-Hq5AT03 ~]# service sshd restart
Redirecting to /bin/systemctl restart sshd.service
[root#CEBECOM-Hq5AT03 ~]# sshd -T |grep -i permitrootlogin
permitrootlogin yes
I also tried to restart the machine but still I can login with root...
Any idea?
Edit: I have some more info.
I found out that I have to put the PermitRootLogin before a Match directive in order for it to work:
# here it works
PermitRootLogin no
Match Group sFTP
ChrootDirectory /sftp/salsftp
ForceCommand internal-sftp
AllowTcpForwarding no
# here it doesn't work
# PermitRootlogin no
I can't find a reason why it behaves like this.
Ah ok I got it. From the sshd_config man page:
Match Introduces a conditional block. If all of the criteria on the
Match line are satisfied, the keywords on the following lines
override those set in the global section of the config file,
until either another Match line or the end of the file
So if I put the PermitRootlogin after the Match this will be considered as part of the Match configuration. Since root is not on the sFTP group then the PermitRootLogin directive was ignored.

restrict commands that salt-minion is able to publish

configured the salt-stack environment like below:
machine1 -> salt-master
machine2 -> salt-minion
machine3 -> salt-minion
This setup is working for me and I can publish i.e. the command "ls -l /tmp/" from machine2 to machine3 with
salt-call publish.publish 'machine3' cmd.run 'ls - /tmp/'
How it's possible to restrict the commands that are able to be published?
In the currently setup it's possible to execute every command on machine3 and that we would be very risky. I was looking in the salt-stack documentation but unfortunately, I didn't find any example how to configure it accordingly.
SOLUTION:
on machine1 create file /srv/salt/_modules/testModule.py
insert some code like:
#!/usr/bin/python
import subprocess
def test():
return __salt__['cmd.run']('ls -l /tmp/')
if __name__ == "__main__":
test()
to distribute the new module to the minions run:
salt '*' saltutil.sync_modules
on machine2 run:
salt-call publish.publish 'machine3' testModule.test
The peer configuration in the salt master config can limit what commands certain minion can publish, e.g.
peer:
machine2:
machine1:
- test.*
- cmd.run
machine3:
- test.*
- disk.usage
- network.interfaces
This will allow minion machine2 to publish test.* and cmd.run commands.
P.S. Allowing minions to publish cmd.run command is not a good idea generally, just put it here as example.

How to create a directory using Ansible

How do you create a directory www at /srv on a Debian-based system using an Ansible playbook?
You want the file module. To create a directory, you need to specify the option state: directory :
- name: Creates directory
file:
path: /src/www
state: directory
You can see other options at https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html
You can even extend the file module and even set the owner,group & permission through it. (Ref: Ansible file documentation)
- name: Creates directory
file:
path: /src/www
state: directory
owner: www-data
group: www-data
mode: 0775
Even, you can create the directories recursively:
- name: Creates directory
file:
path: /src/www
state: directory
owner: www-data
group: www-data
mode: 0775
recurse: yes
This way, it will create both directories, if they didn't exist.
Additional for all answers here, there is lot of situations when you need to create more then one directory so it is a good idea to use loops instead creating separate task for each directory.
- name: creates multiple directories in one task
file:
path: "{{ item }}"
state: directory
loop:
- /srv/www
- /dir/foo
- /dir/bar
you can create using:
Latest version 2<
- name: Create Folder
file:
path: /srv/www/
owner: user
group: user
mode: 0755
state: directory
Older version
- name: Create Folder
file:
path=/srv/www/
owner=user
group=user
mode=0755
state=directory
Refer - http://docs.ansible.com/ansible/file_module.html
Directory can be created using file module only, as directory is nothing but a file.
# create a directory if it doesn't exist
- file:
path: /etc/some_directory
state: directory
mode: 0755
owner: foo
group: foo
- name: Create a directory
ansible.builtin.file:
path: /etc/some_directory
state: directory
mode: '0755'
- file:
path: /etc/some_directory
state: directory
mode: 0755
owner: someone
group: somegroup
That's the way you can actually also set the permissions, the owner and the group. The last three parameters are not obligatory.
You can create a directory. using
# create a directory if it doesn't exist
- file: path=/src/www state=directory mode=0755
You can also consult
http://docs.ansible.com/ansible/file_module.html
for further details regaridng directory and file system.
Just need to put condition to execute task for specific distribution
- name: Creates directory
file: path=/src/www state=directory
when: ansible_distribution == 'Debian'
You can use the statement
- name: webfolder - Creates web folder
file: path=/srv/www state=directory owner=www-data group=www-data mode=0775`
enter code here
- name: creating directory in ansible
file:
path: /src/www
state: directory
owner: foo
you can refer to ansible documentation
If you want to create a directory in windows:
- name: create folder in Windows
win_file:
path: C:\Temp\folder\subfolder
state: directory
See the win_file module for more information.
to create directory
ansible host_name -m file -a "dest=/home/ansible/vndir state=directory"
We have modules available to create directory , file in ansible
Example
- name: Creates directory
file:
path: /src/www
state: directory
you can use the "file" module in this case, there are so many arguments that you can pass for a newly created directory like the owner, group, location, mode and so on.....
please refer to this document for the detailed explanation on the file module...
https://docs.ansible.com/ansible/latest/modules/file_module.html#file-module
remember this module is not just for creating the directory !!!
To check if directory exists and then run some task (e.g. create directory) use the following
- name: Check if output directory exists
stat:
path: /path/to/output
register: output_folder
- name: Create output directory if not exists
file:
path: /path/to/output
state: directory
owner: user
group: user
mode: 0775
when: output_folder.stat.exists == false
You can do it as one of the following ways:
Example 1: If Parent Directory already exists:
- name: Create a new directory www at given path
ansible.builtin.file:
path: /srv/www/
state: directory
mode: '0755'
Example 2: If Parent Directory does not exist:
- name: Create a new directory www at given path recursively
ansible.builtin.file:
path: /srv/www/
state: directory
mode: '0755'
recurse: yes
Here in Example 2, it will recursively create both directories if they are not present.
You can see the Official Documentation for further info on file_module
You can directly run the command and create directly using ansible
ansible -v targethostname -m shell -a "mkdir /srv/www" -u targetuser
OR
ansible -v targethostname -m file -a "path=/srv/www state=directory" -u targetuser
---
- hosts: all
connection: local
tasks:
- name: Creates directory
file: path=/src/www state=directory
Above playbook will create www directory in /src path.
Before running above playbook. Please make sure your ansible host connection should be set,
"localhost ansible_connection=local"
should be present in /etc/ansible/hosts
for more information please let me know.
Use file module to create a directory and get the details about file module using command "ansible-doc file"
Here is an option "state" that explains:
If directory, all immediate subdirectories will be created if they do not exist, since 1.7 they will be created with the supplied permissions.
If file, the file will NOT be created if it does not exist, see the [copy] or [template] module if you want that behavior.
If link, the symbolic link will be created or changed. Use hard for hardlinks.
If absent, directories will be recursively deleted, and files or symlinks will be unlinked.
Note that file will not fail if the path does not exist as the state did not change.
If touch (new in 1.4), an empty file will be created if the path does not
exist, while an existing file or directory will receive updated file
access and modification times (similar to the way touch works from
the command line).
Easiest way to make a directory in Ansible.
name: Create your_directory if it doesn't exist.
file:
path: /etc/your_directory
OR
You want to give sudo privileges to that directory.
name: Create your_directory if it doesn't exist.
file:
path: /etc/your_directory
mode: '777'
Hello good afternoon team.
I share the following with you.
- name: Validar Directorio
stat:
path: /tmp/Sabana
register: sabana_directorio
- debug:
msg: "Existe"
when: sabana_directorio.stat.isdir == sabana_directorio.stat.isdir
- name: Crear el directorio si no existe.
file:
path: /tmp/Sabana
state: directory
when: sabana_directorio.stat.exists == false
With which you can validate if the directory exists before creating it
I see lots of Playbooks examples and I would like to mention the Adhoc commands example.
$ansible -i inventory -m file -a "path=/tmp/direcory state=directory ( instead of directory we can mention touch to create files)
You need to use file module for this case. Below playbook you can use for your reference.
---
- hosts: <Your target host group>
name: play1
tasks:
- name: Create Directory
files:
path=/srv/www/
owner=<Intended User>
mode=<Intended permission, e.g.: 0750>
state=directory
here is easier way.
- name: create dir
command: mkdir -p dir dir/a dir/b

How can I execute multiple commands using Salt Stack?

I tried to add:
mypack:
pkg:
- installed
- pkgs:
- mercurial
- git
cmd.run:
- name: 'mkdir -p /opt/mypack'
cmd.run: 'hg pull -u -R /opt/mypack || hg clone -R /opt https://...'
cmd.run: 'ln -s /opt/mypack/etc/init.d/xxx /etc/init.d/xxx'
But for some reason this the state seems to execute/install but the commands are not executed, or at least not all of them.
I need a solution to run multiple commands and to fail the deployment if any of these fails.
I know that I could write a bash script and include this bash script, but I was looking for a solution that would work with only the YAML file.
You want this:
cmd-test:
cmd.run:
- name: |
mkdir /tmp/foo
chown dan /tmp/foo
chgrp www-data /tmp/foo
chmod 2751 /tmp/foo
touch /tmp/foo/bar
Or this, which I would prefer, where the script is downloaded from the master:
cmd-test:
cmd.script:
- source: salt://foo/bar.sh
- cwd: /where/to/run
- user: fred
In addition to the above (better) suggestions, you can do this:
cmd-test:
cmd.run:
- names:
- mkdir -p /opt/mypack
- hg pull -u -R /opt/mypack || hg clone -R /opt https://...
- ln -s /opt/mypack/etc/init.d/xxx /etc/init.d/xxx
For reasons I don't understand yet (I'm a Salt novice), the names are iterated in reverse order, so the commands are executed backwards.
You can do as Dan pointed out, using the pipe or a cmd.script state. But it should be noted that you have some syntax problems in your original post. Each new state needs a name arg, you can't just put the command after the colon:
mypack:
pkg:
- installed
- pkgs:
- mercurial
- git
cmd.run:
- name: 'my first command'
cmd.run:
- name: 'my second command'
However, that actually may fail as well, because I don't think you can put multiple of the same state underneath a single ID. So you may have to split them out like this:
first:
cmd.run:
- name: 'my first command'
second:
cmd.run:
- name: 'my second command'
As one of the users pointed out above, this works in proper order (salt 3000.2)
install_borg:
cmd.run:
- names:
- cd /tmp
- wget https://github.com/borgbackup/borg/releases/download/1.1.15/borg-linux64
- mv borg-linux64 /usr/local/bin/borg
- chmod u+x /usr/local/bin/borg
- chown root:root /usr/local/bin/borg
- ln -s /usr/local/bin/borg /usr/bin/borg
- unless: test -f /usr/bin/borg

Resources