Reputation: 45350
I am looking for the best way to automate whitelisting IP addresses into iptables
. The list of ip addresses and ports comes from a JSON file /accept-rules.json
which is formatted like:
[
{
"ip": "1.2.3.4",
"cidr": 32,
"protocol": "tcp",
"port": 3306
},
{
"ip": "2.4.5.6",
"cidr": 32,
"protocol": "tcp",
"port": 80
},
{
"ip": "5.6.7.8",
"cidr": 32,
"protocol": "tcp",
"port": 443
},
{
"ip": "6.8.3.1",
"cidr": 32,
"protocol": "tcp",
"port": 53
}
]
I need a bash
or python
script which reads the json file and creates ACCEPT
iptables rules. Example ACCEPT
rules based on the json
above should look like:
iptables -A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 3306 -j ACCEPT
iptables -A INPUT -s 2.4.5.6/32 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -s 5.6.7.8/32 -p tcp -m tcp --dport 443 -j ACCEPT
iptables -A INPUT -s 6.8.3.1/32 -p tcp -m tcp --dport 53 -j ACCEPT
Any idea of the best way to code this up?
Upvotes: 2
Views: 4027
Reputation: 70782
There is a cleaner pure bash version. (without eval
)
declare -A iptArray
iptArray[action]='A'
getval() {
[[ "$@" =~ \"([^\*]*)\"\ *:\ *\"?([^\",]*)\"?[,\ ]*$ ]] && \
iptArray[${BASH_REMATCH[1]}]=${BASH_REMATCH[2]}
}
while read line;do
getval $line
[[ "$line" =~ } ]] && \
echo iptables -${iptArray[action]} INPUT -p ${iptArray[protocol]} \
-s ${iptArray[ip]}/${iptArray[cidr]} \
--dport ${iptArray[port]} -j ACCEPT
done < ipt_whitelist.json
iptables -A INPUT -p tcp -s 1.2.3.4/32 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 2.4.5.6/32 --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 5.6.7.8/32 --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s 6.8.3.1/32 --dport 53 -j ACCEPT
(Delete echo
for doing action instead of just printing it)
jq
toolAs you know have to found values named protocol
, ip
, cidr
and port
in each field, you could ensure ordering and extract values by using jq
in something like:
i=0
while :;do
for var in proto ip mlen port ;do
read -r $var
[ "${!var}" = "null" ] && break 2
done < <(
jq -r ".[$i].protocol,.[$i].ip,.[$i].cidr,.[$i].port" <whitelist.json
)
echo iptables -A INPUT -p $proto -s $ip/$mlen -dport $port -j ACCEPT
((i++))
done
iptables -A INPUT -p tcp -s 1.2.3.4/32 -dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 2.4.5.6/32 -dport 80 -j ACCEPT
iptables -A INPUT -p tcp -s 5.6.7.8/32 -dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s 6.8.3.1/32 -dport 53 -j ACCEPT
(Again: Delete echo
for doing action instead of just printing it)
Upvotes: 2
Reputation: 414199
A cleaner Python version:
#!/usr/bin/env python
import json
import sys
for rule in json.load(sys.stdin):
print("iptables -I INPUT -s {ip}/{cidr} -p {protocol} "
"-m {protocol} --dport {port} -j ACCEPT".format(**rule))
Note: It uses -I
to insert rules at the beginning.
$ json2iptables < accept-rules.json
iptables -I INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 3306 -j ACCEPT
iptables -I INPUT -s 2.4.5.6/32 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -I INPUT -s 5.6.7.8/32 -p tcp -m tcp --dport 443 -j ACCEPT
iptables -I INPUT -s 6.8.3.1/32 -p tcp -m tcp --dport 53 -j ACCEPT
Upvotes: 1
Reputation:
Note that iptables -A
adds rules to the end of the table. When matching rules, iptables works from top to bottom and the first match wins so if you had previously blocked an address then white listing it with -A
won't work (many default rulesets hav a blaket reject all at the end for example) It's better to use iptables -I
to insert rules at the begining in this case.
#!/bin/bash
function getval {
set -- $1
RET=${2//[\",]/}
}
while read line
do
set -- $line
if [[ "$1" == '"ip":' ]]
then
getval "$line"
IPADDRESS=$RET
read line
getval "$line"
CIDR=$RET
read line
getval "$line"
PROTOCOL=$RET
read line
getval "$line"
PORT=$RET
/sbin/iptables -I INPUT -s "$IPADDRESS"/"$CIDR" -p "$PROTOCOL" -m "$PROTOCOL" --dport "$PORT" -j ACCEPT
fi
done <file.json
Upvotes: 1
Reputation:
Python implementation:
import json
rules_file = open('accept-rules.json', 'r')
rules = json.load(rules_file)
rules_file.close()
iptables = open('iptavles.sh', 'w')
for rule in rules:
rule_str = 'iptables -A INPUT -s %s/%s -p tcp -m %s --dport %s -j ACCEPT\n' % (rule['ip'], rule['cidr'], rule['protocol'], rule['port'])
iptables.write(rule_str)
iptables.close()
accept-rules.json - start json file, iptables.sh - goal file
Upvotes: 0
Reputation: 35950
Here is a python code:
This will generate a bash script file 'accept.sh' with all the iptable entries.
# accept.py
fp = open("accept-rules.json", "r")
data = fp.readlines()
fp1 = open("accept.sh", "w")
for line in data:
if "{" in line:
datum = {}
elif "}" in line:
s = "iptables -A INPUT -s " + datum["ip"] + "/" + datum["cidr"] + " -p " + datum["protocol"] + " -m " + datum["protocol"] + " --dport " + datum["port"] + " -j ACCEPT\n"
fp1.write(s)
elif "[" in line or "]" in line:
continue
else:
datum[line.split(":")[0].strip().strip('"')] = line.split(":")[1].strip().strip(",").strip('"')
fp1.close()
fp.close()
Upvotes: 1