Ansible mount with credential file - ansible

I have a playbook containing a mount task which seems to be failing when i try using the credentials option.
The task below succeeds
- name: "mount share"
mount:
state: "mounted"
fstype: "cifs"
name: "/opt/shared"
src: "//192.168.2.5/my_shared_drive"
opts: "username=john,password=secretpass,file_mode=0644,dir_mode=0755,gid=root,uid=root"
While the one below fails with a credentials missing related error message.
- name: "mount share"
mount:
state: "mounted"
fstype: "cifs"
name: "/opt/shared"
src: "//192.168.2.5/my_shared_drive"
opts: "credentials=/root/secretcreds,file_mode=0644,dir_mode=0755,gid=root,uid=root"
Below is the content of the credentials file
[root#localhost]# cat /root/secretcreds
username=john
password=secretpass

It seems like there is a bug, there is an open issue #22930.

Related

ansible mount a remote nfs share to the localhost server running ansible playbook

When running ansible.posix.mount, an ssh connection is created to the src, then the path directory is created on said server.
I want to be able to just mount nfs share from a remote server locally on the box running the ansible playbook.
I understand that the second task in my playbook below is performing said task on any hosts in my inventory under "nfs-server", however I need to include that host as it is the destination ip variable I need to point the mount share at. I do not want to have to add IP address destinations to my settings.yml, would rather iterate via the inventory file if possible.
What am I missing?
Here is my playbook:
- name: Create directory
hosts: localhost
gather_facts: False
tasks:
- name: Include vars
include_vars:
file: settings.yaml
name: settings
- name: Create local directory "nfs-ansible"
file:
path: ./nfs-ansible
state: directory
delegate_to: localhost
- name: Mount nfs share to localhost
hosts: nfs-server
gather_facts: False
become: yes
tasks:
- name: Include idrac vars
include_vars:
file: settings.yaml
name: settings
- name: Mount share from nfs-server
ansible.posix.mount:
src: "{{ hostvars[inventory_hostname].ipaddress }}:/nfs-share"
path: ./nfs-ansible
state: mounted
fstype: nfs
As best I can tell from your question, you don't actually want to run against the nfs-server group, you merely want to use its ipaddress hostvar to mount locally. If that understanding is correct:
- name: Create directory
hosts: localhost
gather_facts: False
tasks:
- name: Include vars
include_vars:
file: settings.yaml
name: settings
- name: Create local directory "nfs-ansible"
file:
path: ./nfs-ansible
state: directory
# delegate to is redundant in a playbook targeting "localhost" to begin with
# delegate_to: localhost
- name: Mount share from nfs-server
become: yes
ansible.posix.mount:
src: "{{ hostvars[nfs_server0].ipaddress }}:/nfs-share"
path: ./nfs-ansible
state: mounted
fstype: nfs
vars:
nfs_server0: '{{ groups["nfs-server"] | first }}'

Ansible: Handling temporary file idempotently and securely

In Ansible (RHEL 8 if it matters), I need to create a temporary file from a template with sensitive content. After a few other tasks are completed, it should be deleted. The temporary file is an answerfile for an installer that will run as a command. The installer needs a user name and password.
I can't figure out if there is a way to do this easily in Ansible.
The brute-force implementation of what I'm looking for would look similar to this:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
creates: /somewhereelse/installedprogram
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
Of course, this code is not idempotent - the answer file would get created and destroyed on each run.
Is there a better way to do this?
Test the existence of the file. If it exists skip the block. For example
- stat:
path: /somewhereelse/installedprogram
register: st
- block:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
when: not st.stat.exists
(not tested)
Taking the task "Delete answerfile" out of the block will make the code more secure. It will always make sure the credentials are not stored in the file. The task won't fail if the file is not present.
- stat:
path: /somewhereelse/installedprogram
register: st
- block:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
when: not st.stat.exists
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
(not tested)
I think that this solution potentially represents a slight improvement on your solution.
With this solution the tasks which create and delete the answerfile will be skipped (rather than always run and reporting changed) if the program you're targeting is already installed.
I still don't love this solution as I don't really like skips.
# Try call the installedprogram. --version is arbitrary here.
# --help, or a simple `which installedprogram` could be alternatives.
- name: Try run installedprogram
command: '/somewhereelse/installedprogram --version'
register: installedprogram_exists
ignore_errors: yes
changed_when: False
# Only create answer file if installedprogram is not installed
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
when: installedprogram_exists.rc != 0
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
creates: /somewhereelse/installedprogram
# Only delete answer file if installedprogram is not installed
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
when: installedprogram_exists.rc != 0

Download a file from a windows share using Ansible

I have a file in windows share. I need to download this file using ansible.
Playbook
- name: Copy installer
get_url:
url: file:'\\Winserver\Share_Binary\Installer-v6.tar.gz'
dest: /tmp
Error Output:
"mode": "01777",
"msg": "Request failed: <urlopen error [Errno 2] No such file or directory: \"'\\\\\\\\Winserver\\\\Share_Binary\\\\Installer-v6.tar.gz'\">",
"owner": "root",
"size": 4096,
"state": "directory",
"uid": 0,
"url": "file:'\\\\Winserver\\Share_Binary\\Installer-v6.tar.gz'"
The file exists. When I paste \\Winserver\Share_Binary\Installer-v6.tar.gz in the file explorer in my system I could see the file. Please advice.
This can be accomplished with a credential file and 3 Ansible tasks.
First, create a credential file (e.g. /home/youruser/smbshare.cred) containing the username and password of a service account with permissions to mount the CIFS share:
username=your_service_account_name
password=your_service_account_password
Make sure your remote ansible user owns the file (or root if you're using become) and it has 0400 permissions. You might consider generating this credential file with Ansible and/or encrypting it with Ansible Vault in the future as well.
Task 1: Use the mount module to mount the SMB share on the target.
- name: Mount SMB share
mount:
path: /mnt/smbshare
src: '\\\\Winserver\\Share_Binary'
fstype: cifs
opts: 'credentials=/home/youruser/smbshare.cred'
state: mounted
Task 2: Use the copy module to copy the file wherever you actually want it.
- name: Copy installer tarball to target
copy:
src: /mnt/smbshare/Installer-v6.tar.gz
dest: /some/local/path/Installer-v6.tar.gz
owner: foo
group: foo
mode: 0640
Task 3: Use the mount module to unmount the SMB share.
- name: Unmount SMB share
mount:
path: /mnt/smbshare
state: unmounted
Note: Depending on your environment, you might need to add more mount options (refer to mount.cifs(8) man page) to the opts: parameter in task 1.
not sure if get_url is capable to do that. Pls try this one:
- name: Get file from smb.
command:
smbclient //Winserver/Share_Binary/ <pass> -U <user> -c "get Installer-v6.tar.gz"
creates=/tmp/Installer-v6.tar.gz
Of course, you have to install smbclient first

Why are my nfs4 mounts not working with ansible?

With Ansible, I cannot mount nfs4.
I have nfs4 exports configured on the server, and I can mount both nfs4 and nfs using a bash shell.
I can also get nfs to work in ansible, just not nfs4.
so I'm wondering how I can mount a share like /pool1/volume1 on the server to the same style path on the client-
/pool1/volume1
tried switching to standard nfs which worked, and I can mount nfs4 in a bash shell, but not with ansible
This works-
- name: mount softnas NFS volume
become: yes
mount:
fstype: nfs
path: "/pool1/volume1"
opts: rsize=8192,wsize=8192,timeo=14,intr,_netdev
src: "10.0.11.11:/pool1/volume1"
state: mounted
But this doesn't
- name: mount softnas NFS volume
become: yes
mount:
fstype: nfs4
path: "/pool1/volume1"
opts: rsize=8192,wsize=8192,timeo=14,intr,_netdev
src: "10.0.11.11:/pool1/volume1"
state: mounted
and if i use this command from a shell, this works fine in mounting the paths into test.
sudo mount -t nfs4 10.0.11.11:/ /test
although its not quite right, because id like /pool1/volume1 and /pool2/volume2 to not appear under /test
my exports file on the server is this-
/ *(ro,fsid=0)
# These mounts are managed in ansible playbook softnas-ebs-disk-update-exports.yaml
# BEGIN ANSIBLE MANAGED BLOCK /pool1/volume1/
/pool1/volume1/ *(async,insecure,no_subtree_check,no_root_squash,rw,nohide)
# END ANSIBLE MANAGED BLOCK /pool1/volume1/
# BEGIN ANSIBLE MANAGED BLOCK /pool2/volume2/
/pool2/volume2/ *(async,insecure,no_subtree_check,no_root_squash,rw,nohide)
# END ANSIBLE MANAGED BLOCK /pool2/volume2/
when I try to switch to nfs4, i get this error with ansible
Error mounting /pool1/volume1/: mount.nfs4: mounting 10.0.11.11:/pool1/volume1/ failed, reason given by server: No such file or directory
Came across this same issue, using Ansible 2.11.5 the above answer didn't work for me. Ansible was complaining about the fstype "nfs4" and quoting was needed for the "opts" equal signs. Here is what I used:
- name: mount AWS EFS Volume
mount:
fstype: nfs
path: "/mnt/efs"
opts: "nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"
src: "{{ efs_share_address[env] }}:/"
state: mounted
From the roles var file:
efs_share_address:
qa: 10.2.2.2
stage: 10.3.3.3
production: 10.4.4.4
Check if mount point exists
mkdir /pool1/volume1 # if not exists. Or create an ansible task to create the directory
Updated to change as the share is /
- name: mount softnas NFS volume
become: yes
mount:
fstype: nfs4
path: "/pool1/volume1"
opts: rsize=8192,wsize=8192,timeo=14,intr,_netdev
src: "10.0.11.11:/"
state: mounted
If you don't want to mount /, then share the /pool1/volume1 in the server.
I'm not sure how I fixed it exactly, but I decided to opt for the recommended workflow of binding my exports below the /export folder, and using
/export *(ro,fsid=0)
...as the root share. and then these-
/export/pool1/volume1 *(async,insecure,no_subtree_check,no_root_squash,rw,nohide)
/export/pool2/volume2 *(async,insecure,no_subtree_check,no_root_squash,rw,nohide)

Ansible playbook to install NCPA agent on Windows

I am trying to install Nagios NCPA agent on Windows using Ansible play book. Here is my simple playbook
- name: Install NCPA
win_package:
path: https://assets.nagios.com/downloads/ncpa/ncpa-2.1.4.exe
- name: Copy the ncpa.cfg template
win_template:
src: ncpa.cfg.j2
dest: 'C:\Program Files (x86)\Nagios\NCPA\etc\ncpa.cfg'
- name: Restart NCPA
win_service:
name: ncpapassive
state: restarted
However I am getting the below error:
"msg": "product_id is required when the path is not an MSI or the path is an MSI but not local",
How to I find out the product_id for ncpa?
You can skip product_id if you add any of creates_* arguments to your first task, for example:
creates_path: C:\Program Files (x86)\Nagios\NCPA\___main_executable_file__.exe
Or you can search on a machine with your package istalled; per win_package manual:
product_id [ ]
You can find product ids for installed programs in the Windows registry editor either at HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall or for 32 bit programs at HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall.
This SHOULD be set when the package is not an MSI, or the path is a url or a network share and credential delegation is not being used. The creates_* options can be used instead but is not recommended.
Finally managed to make it work with a dummy product ID.
- name: Create download directory
win_file:
path: C:\\Temp
state: directory
- name: Copy the executable package to download directory
win_copy:
src: ncpa-2.1.4.exe
dest: 'C:\Temp\ncpa-2.1.4.exe'
#- name: Download NCPA executable
# win_get_url:
# url: https://assets.nagios.com/downloads/ncpa/ncpa-2.1.4.exe
# dest: C:\Temp\ncpa-2.1.4.exe
# force: no
# skip_certificate_validation: yes
- name: Install NCPA
win_package:
path: 'C:\Temp\ncpa-2.1.4.exe'
arguments: '/S /TOKEN=demo-token'
product_id: '{ncpa}'
ignore_errors: true
register: installmsi
failed_when: "'was installed' not in installmsi.msg"
- name: Copy the ncpa.cfg template
win_template:
src: ncpa.cfg.j2
dest: 'C:\Program Files (x86)\Nagios\NCPA\etc\ncpa.cfg'
- name: Restart NCPA
win_service:
name: ncpapassive
state: restarted

Resources