Transferring a Large File to a Target Server Using Azure DevOps, CyberArk, and Ansible
I recently needed to drop a large file onto a target Linux server where direct SCP was prohibited. The server is entirely managed using Ansible playbooks in Azure DevOps with it’s credentials stored in CyberArk. Ok no problem…maybe?
Running my pipeline I was presented with an error stating there was insufficient disk space in the /tmp/.ansible/tmp directory on the agent machine.
The following provides some steps for how I overcame this problem. It’s not the most elegant solution but it got the job done!
All code referenced in this post can be found in this repo.
Split the File
First I archived my file:
tar -cvf largefile.tar /path/to/files/
Then I used the split Command to Split the .tar File: The split command allows you to split the file into smaller, more manageable chunks. The general syntax is:
split -b <size> <source-file> <output-prefix>
This command split largefile.tar into 1 GB chunks, resulting in files named largefile_part_aa, largefile_part_ab, etc.
CyberArk
As mentioned the credentials needed by Ansible to access the server are stored in CyberArk, so in my main pipeline I needed to initiate a connection to CyberArk using my service connection:
- task:
name: PWV # Task Name
inputs:
svcConnection: # your cyberark service connection
accounts: # your cyberark account name
env:
PWV_password: $(PWV.cyberark_account_name_seperated_by_underscores)
Note that I needed to configure the password as an environment variable so that it can later be passed to the hosts.ini
file that Ansible uses for authentication.
Become
In my playbook I required a privilege escalation step. In Ansible, you can gain root privileges by using the become directive. This allows a non-root user to run commands with elevated privileges.
You can add the become: true
directive to:
- The entire playbook.
- A specific task.
- A specific play.
If your servers are using sudoexec you will have to create a role. That’s a whole other thing that I won’t go into here. Nevertheless, I’ve included a role in the repo just so you have an idea about how the tree structure might look if you did need that.
Transfer
I then transferred each smaller chunk over. Here is basic example of what the file transfer playbook looked like:
---
- name: create target directory
hosts: all
roles:
- detect-become-method
tasks:
- name: Copy file from agent to target server
become: true
copy:
src: # <agent directory where file to be transferred is located>/largefile_part_aa
dest: # directory on target server
mode: '0755'
- name: Copy file from agent to target server
become: true
copy:
src: # <agent directory where file to be transferred is located>/largefile_part_ab
dest: # directory on target server
mode: '0755'
- name: list target directories contents
command: ls
register: ls_output
- name: display raw output of the ls command
debug:
var: ls_output
...
Reassembly
After all chunks had been transferred to the target system, I reassembled them using the cat command which concatenates all the parts back into the original .tar file.:
cat largefile_part_* > largefile.tar
In my case I could SSH into the server so I was able to run this command myself. I could of course have also added these next steps to my ansible playbook though (and any further steps like running installation binaries).
It’s a good idea to verify that the reassembled file is identical to the original. You can compare checksums or extract the .tar file to ensure it was reassembled correctly.
And that’s it!
⚡️ Enjoyed this post? Buy me a coffee… in sats! Tip me via my Lightning address: [email protected]