I want to change sudo session timeout according to this answer. I can edit ordinary file:
lineinfile:
path: /etc/sudoers
regexp: ^Defaults env_reset
line: Defaults env_reset,timestamp_timeout=60
But in first line of my /etc/sudoers written: # This file MUST be edited with the 'visudo' command as root. How to deal with it?
P.S.
Despite the fact that the short answer is yes, one must read Konstantin Suvorov answer about right way to do it with lineinfile and very interesting techraf answer about possible pitfalls on this way
There's a safenet option for such cases: validate.
The validation command to run before copying into place. The path to the file to validate is passed in via '%s' which must be present as in the example below. The command is passed securely so shell features like expansion and pipes won't work.
If you look at the examples section of lineinfile module, you'll see exactly what you need:
# Validate the sudoers file before saving
- lineinfile:
path: /etc/sudoers
state: present
regexp: '^%ADMIN ALL='
line: '%ADMIN ALL=(ALL) NOPASSWD: ALL'
validate: '/usr/sbin/visudo -cf %s'
It's safe if you've tested the syntax to be correct.
The point of encouraging visudo is to prevent someone from locking themselves out from administering a system by creating an invalid /etc/sudoers, whether by a typo or a thinko.
When you're using Ansible to perform an edit, you can test the code performing that edit to do the right thing with your actual config files, environment, and version of sudo before you roll it out. Thus, the concerns about people making a typo or a syntax error by hand aren't immediately relevant.
While this answer defines things correctly and this one provides a mitigation to potential problems, let's look at your code.
You ask Ansible to (potentially) replace the line defined in the following way:
regexp: ^Defaults env_reset
This is clearly a bad practice and if repeated for a parameter other than Defaults in sudoers file, it is likely to cause a critical problem.
Generally Defaults is the configuration parameter and env_reset is one of possible values.
You cannot assume that the actual configuration file will always contain ^Defaults env_reset string.
If there was a different value set, the regexp wouldn't match and you'd end up adding a second line starting with Defaults.
So the proper way to use lineinfile is to use regexp argument to match only the configuration parameter, not its value. In your case:
regexp: ^Defaults
line: Defaults env_reset,timestamp_timeout
The other potential pitfall is that sudoers contain sections which should be written in proper order. If the file you modify does not contain the line specified by the regular expression, lineinfile will add a new line to the end of the file, where it might get ignored, or result in an error (but that should be discovered by validation), and most likely cause confusion if human looked at the file later. So it might be wise to specify insertafter or insertbefore.
I think what you are missing is that in order to edit /etc/sudoers you need sudo-access. To do this in Ansible, you just need to add the become flag.
name: Change Sudo Timeout
become: yes
lineinfile:
path: /etc/sudoers
regexp: ^Defaults env_reset
line: Defaults env_reset,timestamp_timeout=60
Instead of directly editing the /etc/sudoers you can place your desired setting into the /etc/sudoers.d directory like this:
- name: Change sudo session timeout
lineinfile:
dest: /etc/sudoers.d/ssh_session_timeout
line: 'Defaults env_reset,timestamp_timeout=60K'
create: yes
owner: root
group: root
mode: "0440"
state: present
validate: 'visudo -c -f %s'
Related
Below is the bash profile of the root user in my system.
[root#newvm-2 ~]# cat .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
I want to write a ansible code that will add the below path at the end of PATH in the bash_profile of root user:
/usr/edb/efm
eg: the new PATH will look like
PATH=$PATH:$HOME/bin:/usr/edb/efm
- lineinfile:
regexp: '^(PATH=.*)$'
backrefs: yes
line: '\1:/user/edb/efm'
path: '/root/.bashrc'
lineinfile manipulates individual lines in files.
regexp: '^(PATH=.*)$' says: Find the last line beginning with PATH= and remember the line. This also specifies which line will be changed.
backrefs: yes means that I can use that remembered line in the line I set.
line: '\1:/user/edb/efm' means take the first group the regex matched (the entire line in the () ) and write :/user/edb/efm behind it.
path: '/root/.bashrc' just specifies which file is manipulated, I guessed here, you probably know the right one.
This is just a single task, if you want a whole play for this just prepend
- hosts: all
tasks:
and indent everything once
I have to perform the below steps.
Create a Playbook test.yml.
This playbook should copy the file (somefile.j2) to the Host machine's folder1, only if
somefile.j2 does not exist in host01.
By using vi editor you can add the tasks to test.yml.
[Hint: Use the stat and template module].
somefile.j2 is present at /root.
An inventory file named "myhosts" is present at /root
$ cat myhosts
host01 ansible_ssh_user=root
What should be the contents of test.yml?
Homework questions without "the work done so far to solve the problem and a description of the difficulty" is off-topic. But the conflict in the assignment, which might be considered "a practical, answerable problem that is unique to software development", deserves the answer.
Copy the file to the host only if somefile.j2 does not exist
Use the stat and template module
The assignment requires to use the module stat to find out whether the file exists or not. If it does not exist use the module template to create it.
It is not necessary to use the module stat. The module template "will only transfer the file if the destination does not exist" when "force: no" (default yes). Such "idempotent" behavior of Ansible modules is essential, should be expected, and searched for.
Simply take a look at the examples to see "What should be the contents of test.yml?"
We are using vagrant and ansible to create standard development environments.
The ansible playbooks, vagrant files, etc. are in a git repository.
I've using variable file separation to refer to variable files in the developer's home directory for some senstitive and/or user-specific information (e.g. email address).
We use the variables by doing a vars_file: as part of the playbook, but have to do it for every play.
I don't want to put it in the group_vars/all file because it would then be in the repository and not specific to the user.
I would rather not have a file in the repository that is ignored because people still manage to include it and it screw everybody else up.
Is there a way of doing an equivalent of groups/all which can contain tasks and/or variable definitions that will automatically run whenever a playbook is run?
We use the variables by doing a vars_file: as part of the playbook, but have to do it for every play.
Nope, you can do it on playbook level. (But this might be a new thing, could have been impossible back then, I did not check.)
Is there a way of doing an equivalent of groups/all which can contain tasks and/or variable definitions that will automatically run whenever a playbook is run?
Automatically run/included when?! I don't think this is possible as there would be a lot of open questions like:
Should this be specified on the target machine or the ansible server?
How do you specify for which user should this happen on which host?
If there are tasks: do you want this to be executed on each playbook
when it is run using the given user? What about tasks which specifies
that they run as root (become)? What about tasks that specify a
given user to be executed as? What about tasks that are run as root
but creates a file with the owner matching the given user?
As there are no user scopes with variables and we don't really have a "user context" outlined (see the last questions) we are currently stuck with inclusion of variable files explicitly. Hence the below options:
You can keep using vars_file and specify a first found list.
vars_file:
- - ~/ansible_config/vars.yml
- <default vars file somewhere on the machine>
This way the ansible executor user can redefine values...
You can use the --extra-vars #<filepath> syntax to include all variables from a file, and you can have more than one of these.
A similar thing I do is that I include every variable from every yml file within my GLOBAL_INPUT_DIR (which is an environment variable that can be defined before running the bash script executing ansible-playbook or in a your bash profile or something).
EXTRA_ARGS=`{
{
find "${GLOBAL_INPUT_DIR}" -iname "*.yml";
}\
| while read line; do echo "--extra-vars #${line} "; done \
| tr -d "\n"
}`
ansible-playbook $# ${EXTRA_ARGS}
I usually include something like this in my doings to provide an easy way of redifining variables...
BUT: be aware that this will redefine ALL occurances of a variable name within the playbook (but this was also true with vars_file).
in ansible I'm trying to add a line before '' infile. iam using insert before. it is working as expected. but when ever i ran second time its not creating the duplicate entry of " '" this is also as expected but my concern is i havent mentioned any where not to duplicate in second run why is noot adding the line again
- name: Change the Log Level for log in path/logback.xml
lineinfile:
dest: "path/logback.xml"
line: ' <logger name="org.log" level="DEBUG"/>'
insertbefore: '</configuration>'
backup: yes
lineinfile module doesn't add duplicates, it ensures that specified line is present in the file.
If line is not there, Ansible will add it before insertbefore pattern.
So, if the line is added on the first run, Ansible will do nothing on the second run – it's idempotence in action.
According the Ansible documentation defining variables at runtime, it says I can load variables from a file.
ansible-playbook release.yml --extra-vars "#some_file"
However, in my case I have two files containing extra variables for my playbook invocation.
Concatenating them together is not an option because one is a secret file created and keyed using Vault. The other file is generated from an upstream process.
I have tried:
ansible-playbook release.yml --extra-vars "#some_file #some_other_file"
... but it didn't work. Upon invocation I get
ERROR: file could not read: some_file #some_other_file
so my guess is it takes everything after the first # symbols as the path of the file.
My questions is, can extra-vars accept multiple files?
It turns out I can use:
ansible-playbook release.yml --extra-vars=#some_file --extra-vars=#some_other_file
This does work for me. Please let me know if there is a better answer. Thanks.