I have made an ansible script to collect IP in the nginx log and then the IP that has been collected will be analyzed, if a malicious IP is detected it will be blocked.
The idea is that in the ansible script each IP analyzed is not created individually but using a loop function
But I’m having a hard time making a looping script in ansible, can anyone help?
Here is the script that i have created
- name: Execute a command using the shell module shell: awk '{print $1}' /var/log/nginx/*.log | sort | uniq -c | sort -nr| head -5 register: results - debug: var=results.stdout_lines - name: Write Output local_action: shell echo "{{ results.stdout_lines }}" > /tmp/output #Collect IP - name: Check 1st IP local_action: shell cat /tmp/output | awk '{ print $3 }'| sed 's/.$//'|sed 's/.$//' register: ip1 - debug: var=ip1.stdout - name: Check 2nd IP local_action: shell cat /tmp/output | awk '{ print $6 }'| sed 's/.$//'|sed 's/.$//' register: ip2 - debug: var=ip2.stdout - name: Check 3rd IP local_action: shell cat /tmp/output | awk '{ print $9 }'| sed 's/.$//'|sed 's/.$//' register: ip3 - debug: var=ip3.stdout - name: Check 4th IP local_action: shell cat /tmp/output | awk '{ print $12 }'| sed 's/.$//'|sed 's/.$//' register: ip4 - debug: var=ip4.stdout - name: Check 5th IP local_action: shell cat /tmp/output | awk '{ print $15 }'| sed 's/.$//'|sed 's/.$//' register: ip5 - debug: var=ip5.stdout #Anlyze IP - name: Analyze 1st IP local_action: shell /usr/bin/abuseipdb -C {{ ip1.stdout }} -o plaintext register: vb1 - debug: var=vb1.stdout - name: Analyze 2nd IP local_action: shell /usr/bin/abuseipdb -C {{ ip2.stdout }} -o plaintext register: vb2 - debug: var=vb2.stdout - name: Analyze 3rd IP local_action: shell /usr/bin/abuseipdb -C {{ ip3.stdout }} -o plaintext register: vb3 - debug: var=vb3.stdout - name: Analyze 4th IP local_action: shell /usr/bin/abuseipdb -C {{ ip4.stdout }} -o plaintext register: vb4 - debug: var=vb4.stdout - name: Analyze 5th IP local_action: shell /usr/bin/abuseipdb -C {{ ip5.stdout }} -o plaintext register: vb5 - debug: var=vb5.stdout ##Block IP if score more than 25 - name: Check 1rst IP and Block IP if score more than 25 shell: /sbin/route add "{{ ip1.stdout }}" gw 127.0.0.1 lo when: "{{ vb1.stdout }} >= 25" - name: Check 2nd IP and Block IP if score more than 25 shell: /sbin/route add "{{ ip2.stdout }}" gw 127.0.0.1 lo when: "{{ vb2.stdout }} >= 25" - name: Check 3rd IP and Block IP if score more than 25 shell: /sbin/route add "{{ ip3.stdout }}" gw 127.0.0.1 lo when: "{{ vb3.stdout }} >= 25" - name: Check 4th IP and Block IP if score more than 25 shell: /sbin/route add "{{ ip4.stdout }}" gw 127.0.0.1 lo when: "{{ vb4.stdout }} >= 25" - name: Check 5th IP and Block IP if score more than 25 shell: /sbin/route add "{{ ip5.stdout }}" gw 127.0.0.1 lo when: "{{ vb5.stdout }} >= 25" #Check Route - name: Make Sure the IP has been blocked shell: /sbin/route -n register: route - debug: var=route.stdout_lines
Here is the /tmp/output
└─$ cat /tmp/output [' 40545 87.250.224.147', ' 20873 87.250.224.126', ' 16665 213.180.203.67', ' 15420 87.250.224.142', ' 14503 13.81.52.25']
Here is the output when running
└─$ cat /tmp/output | awk '{ print $3 }'| sed 's/.$//'|sed 's/.$//' 87.250.224.147 └─$ cat /tmp/output | awk '{ print $6 }'| sed 's/.$//'|sed 's/.$//' 87.250.224.126 └─$ cat /tmp/output | awk '{ print $9 }'| sed 's/.$//'|sed 's/.$//' 213.180.203.67 └─$ cat /tmp/output | awk '{ print $12 }'| sed 's/.$//'|sed 's/.$//' 87.250.224.142 └─$ cat /tmp/output | awk '{ print $15 }'| sed 's/.$//'|sed 's/.$//' 13.81.52.25
2
Answers
so you could use range to loop over your command shell, i show you an example: when you loop with register, it records all output in list.
display variable result:
and result final ips after set_fact:
just adapt the solution to your case: as i dont know your output, check the value of register…
another solution will be to trap alls your ips from your file in one task..
but you have to know your output, but the solution i show is easily adaptable to your case quickly
EDITED:
following your output, you could work directly from your result.stdout_lines:
result:
It is probably better to generate a JAML file from your Nginx log in order to use
include_vars
after that.Btw: The idea of Ansible is to be platform independent. Because of that, it is better to have most of the platform specific stuff in an external script and not in the playbook. When you change the platform, you just have to migrate the external script, instead of rewriting the playbook.
Another alternative is to use scripted inventories. You can create a dynamic inventory by reading the IP addresses to block from your Nginx log. If you put the hosts to block into a group, you can define a single task for the group and delegate it to the firewall, where you block the hosts. You do not need to care about iterations. It is the job of Ansible to iterate.
This is much easier to maintain, than the playbook in your question. And it is extremely inefficient to put every line of a shell script into one local action. Don’t do it.
PS: Yes you can program in a playbook, somehow. But try to avoid it. A playbook is not a useful programming language. You can not abstract with procedures and it has almost no scope. When you work with Ansible you have to change the way you think. Do not think about procedures. Instead thing about data. Take your data and arrange the data in a way, that is suitable for Ansible. If the data does not fit, use Jinja filters to rearrange the data until it fits. But avoid "programming" in a playbook by all means. And if you need to program, better do it in Jinja statements or Python.