- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
correct endpoint for firewall rules?
Hi,
New to API's and coding in general.
I am trying to write a script that adds a new firewall rule to a network (I'm using a test site atm).
However I am getting a 404 error which I assume means my URL is wrong?
I got this from the Meraki reference guide but I'm not sure its correct.
/networks/{network_id}/appliance/firewall/l3firewallRules
Also - I read somewhere that adding a new rule would overwrite all the existing rules! Is that true and if so is there a way to add a rule so that it doesn't effect any existing rules?
Thanks!
import requests
import security
import json
api_key = security.MERAKI_API_KEY
organizationId = security.ORG_ID
network_id = "xxxxxxxxx"
rule = {
'name': 'Test Rule',
'policy': 'deny',
'protocol': 'any',
'srcPort': 'any',
'srcCidr': '1.1.1.1/24',
'dstPort': 'any',
'dstCidr': '0.0.0.0/0',
}
url = f"https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/l3firewallRules"
headers = {
'X-Cisco-Meraki-API-Key': api_key,
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, data=json.dumps(rule), verify=False)
print(response.status_code)
Solved! Go to solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
HTTP400 is sent because the dashboard doesn't like your request. Doesn't mean you are missing a parameter.
Using the Meraki SDK would be easier to troubleshoot.
The issue is within the payload.
data=json.dumps(rule)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is the correct URL:
https://developer.cisco.com/meraki/api/#!update-network-l-3-firewall-rules
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Thanks for the reply, but Im still getting a 404 error 😞
am I getting the url wrong or can something else cause this issue?
url = f"https://api.meraki.com/api/v1/networks/{network_id}/l3FirewallRules"
response = requests.post(url, headers=headers, data=json.dumps(rule), verify=False)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
404 - Not Found The requested resource doesn't exist or incorrect API key
You can test It on the Meraki developer Hub before.
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would troubleshoot this issue with these steps :
1- Create a dummy rule from the dashboard
2- GET the rule via the API
3- PUT the exact same response received from step #2.
You have to be Org admin / Net admin to do that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
huh - if I try to use the PUT operation from the dashboard - its gets a 404 there too
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Have you enabled API access?
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, as mentioned, moments before i tried the PUT I did a successful GET
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think your link may be the out of date version 0
Version 1
https://developer.cisco.com/meraki/api-v1/#!update-network-appliance-firewall-l-3-firewall-rules
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Use this one:
https://developer.cisco.com/meraki/api-latest/
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If I run the exact same script as a GET - it works ok. I can also run the get from the dashboard.
I noticed I was using POST rather than PUT so made that change but if I do that I get a 400 error instead 😞
url = f"https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/l3FirewallRules"
response = requests.put(url, headers=headers, data=json.dumps(rule), verify=False)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
400 - Bad Request The request was unacceptable, often due to missing a required parameter.
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
shouldn't the dashboard tell me if there are any required parameters?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
HTTP400 is sent because the dashboard doesn't like your request. Doesn't mean you are missing a parameter.
Using the Meraki SDK would be easier to troubleshoot.
The issue is within the payload.
data=json.dumps(rule)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not pretty , but should work.
import os
import json
import requests
import codecs
base_url_v1 = 'https://api.meraki.com/api/v1'
NetworkID = XXXXXXXXXXX
headers = {
'x-cisco-meraki-api-key': format(str(apikey)),
'Content-Type': 'application/json'
}
def __returnhandler(statuscode, returntext):
if str(statuscode) == '200':
return returntext
else:
print('HTTP Status Code: {0}\n'.format(statuscode))
def getL3FirewallRules():
geturl = '{0}/networks/{1}/appliance/firewall/l3FirewallRules'.format(str(base_url_v1), str(NetworkID))
dashboard = requests.get(geturl, headers=headers,verify=False)
result = __returnhandler(dashboard.status_code, dashboard.text)
return result
L3FWRules = getL3FirewallRules()
payload = L3FWRules
url = 'https://api.meraki.com/api/v1/networks/{0}/appliance/firewall/l3FirewallRules'.format(NetworkID)
response = requests.request('PUT', url, headers=headers, data = payload,verify=False)
print(response.text.encode('utf8'))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks you!
This put me on the right track. I changed
data=json.dumps(rule)
to
data=rule,
and then changed the rule paramater to this
rule = '''{
"rules": [
{
"comment": "Test Rule.",
"policy": "allow",
"protocol": "tcp",
"destPort": "443",
"destCidr": "192.168.1.0/24",
"srcPort": "Any",
"srcCidr": "Any",
"syslogEnabled": false
}
]
}'''
(slight syntax change)
just my second issue now - this seems to overwrite all the existing rules rather than just add this to the list.
how do I add things without deleting all the others?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can't update, you have to set all rules again when you create a new rule.
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can't append a rule. You have to push the whole rule base.
So I would suggest doing a GET first , append your modifications , then PUT the whole rule base.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
am I going to have to call the existing rules, then add them along with the new rule to the update call and basically re-write all the rules each time?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
https://developer.cisco.com/meraki/build/mx-firewall-control-python-script/
Please, if this post was useful, leave your kudos and mark it as solved.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
regarding updating the rules and having to get a copy of existing rules and then adding those to the new update request - this is a little terrifying - what if it misses a rule or something, id have no way of checking 😕
I guess I could get it to export a json file after the get request as something I could look at to make sure its all ok right?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes. The order of firewall rules is important, and Dashboard can't assume placement. Placing a rule at the end may not actually do anyty, thus it is up to you to place a rule in the correct position.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Another approach to consider is that if you want maintain rules via the API, it may be worth keeping the 'master copy' in a local database, then just write the whole set each time.
Then if you need to check rules, it's an API read and compare against the local copy.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm having a problem appending the new rule list to the existing list :(|
I think its because I have created the existing rule list as a dictionary. However if I try to re-write the dictionary as a list (with square brackets [] ) the code stops working. "Invalid syntax"
import requests
import security
import json
# Replace with your Meraki API key and network ID
api_key = security.MERAKI_API_KEY
organizationId = security.ORG_ID
network_id = "xxxxxxxxxxxxxxxxx"
url = f"https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/l3FirewallRules"
headers = {
'X-Cisco-Meraki-API-Key': api_key,
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers, verify=False)
existingrules = response.json()
print(response.status_code)
print(response.text.encode('utf8'))
with open('ExistingRules.json', 'w') as json_file:
json.dump(response.json(), json_file, indent=4)
newrule = '''{
"rules": [
{
"comment": "Test RuleNEW.",
"policy": "deny",
"protocol": "any",
"destPort": "any",
"destCidr": "192.200.1.0/24",
"srcPort": "Any",
"srcCidr": "Any",
"syslogEnabled": false
}
]
}'''
existingrules.append(newrule)
response = requests.put(url, headers=headers, json=existingrules, verify=False)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As mentioned by @David_Jirku it is probable that appending is not going to behave as you wish.
Usually the last rule in the list is 'allow any-any', if you append a stricter rule it will be ignored as it will be lower in precedence than 'allow any-any'
To add a rule to existingrules, you should be adding an item to the rules array within it, not direct to existingrules.
Have a look at...
https://github.com/CiscoSE/AddMerakiMXL3FirewallRuleToNetworks/blob/master/AddRulesToMXL3Firewall.py
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You could do something along the lines of
# Constants
netowrk_id = "xxxx"
TargetComment = "Google DNS"
# Get Rules for network
FirewallRules = dashboard.appliance.getNetworkApplianceFirewallL3FirewallRules(network_id)
# Determine idx where rule should be updated
target_idx = next((idx for idx, item in enumerate(FirewallRules['rules']) if item['comment'] == TargetComment), None)
# Update rule
FirewallRules['rules'][target_idx].update({
"comment": TargetComment
"policy": "deny",
"protocol": "any",
"destPort": "any",
"destCidr": "192.200.1.0/24",
"srcPort": "Any",
"srcCidr": "Any",
"syslogEnabled": false
})
# Remove Default Rule entry
FirewallRules['rules'].pop(-1)
# Update Rules
NewSetOfRules = dashboard.appliance.updateNetworkApplianceFirewallL3FirewallRules(
networkId=network_id,
rules=FirewallRules['rules']
)
What happens is, that I search through all the elements in FirewallRules for the index of the element with the comment, of the rule I wan't to update.
With the index in hand, I can either update the rule, or use the index to inject a new rule. In the above example I use it to update a specific rule.
Modify it to suit your implementation.
Like what you see? - Give a Kudo ## Did it answer your question? - Mark it as a Solution 🙂
All code examples are provided as is. Responsibility for Code execution lies solely your own.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
thanks. I have a working script now which does a similar thing. It injects the new rule to the existing but the rules are still updated by completely overwriting all existing rules with the list I send in - apparently that's the way it works, rather than just adding in any new items in the index.
It seems to work ok but I found that when you do the GET, the list includes the default allow rule. Then when you go to PUT the updated list - that Allow rule gets added like it was a custom rule so you end up with the default and an extra identical copy.
You get an extra Allow rule every time you do an update. I fixed this by searching the list index for that rule and deleting it (luckily the comment is "default Rule" which is nicely unique) before adding my new rule and sending it back.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Or use the a posteriori knowledge, that the default rule is always at the end of the list and simpy "pop it". 😉
# Remove Default Rule entry
FirewallRules['rules'].pop(-1)
Like what you see? - Give a Kudo ## Did it answer your question? - Mark it as a Solution 🙂
All code examples are provided as is. Responsibility for Code execution lies solely your own.
