Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage *all* Firewall Filters with Terraform? #321

Open
Nornode opened this issue Dec 19, 2023 · 8 comments
Open

Manage *all* Firewall Filters with Terraform? #321

Nornode opened this issue Dec 19, 2023 · 8 comments
Labels
enhancement New feature or request

Comments

@Nornode
Copy link

Nornode commented Dec 19, 2023

Is your feature request related to a problem? Please describe.
Yes, Managed all Filters with terraform
I'm missing a clear and consise way of managing all firewall filters (and soon other parts too?) through Terraform.

Describe the solution you'd like
With an input variable I'd like to manage all firewall filters.
e.g.

---

firewall_filters:
  special_dummy_rule_to_show_fasttrack_counters:
    disabled: false
    action: "passthrough"
    chain: "forward"
    comment: "Default Config"

  defconf input accept established related untracked:
    disabled: false
    action: "accept"
    chain: "input"
    connection_state: "established,related,untracked"
    hw_offload: false
    priority: 0
    random: 0
    comment: "Default Config"

  defconf input drop invalid:
    disabled: false
    chain: "input"  
    action: "drop"
    connection_state: "invalid"
    
  defconf accept ICMP:
    disabled: false
    chain: "input"
    action: "accept"
    protocol: "icmp"
    comment: "Default Config - Allow ICMP"
    hw_offload: false

Placing another custom rule in between one rule or last, I'd wish for the module/resource to arrange the rules in order on the router.

I don't know if this is really something that is possible or even possible?
I guess it would case many re-creates and potentially also locking out access during re-creates... ?

Additional context
Add any other context or screenshots about the feature request here.

@Nornode Nornode added the enhancement New feature or request label Dec 19, 2023
@Nornode
Copy link
Author

Nornode commented Dec 19, 2023

Unfortunately the example and documentation is a bit shorthanded and added example or references to other implementations may work better?

As I see it in the example it only gives one option and that is to add more rules on place 0 after filtering out some crucial ones.?

place_before = "${data.routeros_firewall_filter.fw.rules[0].id}"

And if I use the above example reference, what would happen if I create two filters on the same apply? - They'd get teh same "place_after" position..

@vaerh
Copy link
Collaborator

vaerh commented Dec 19, 2023

Please see the end of this discussion.

@Nornode
Copy link
Author

Nornode commented Dec 19, 2023

Please see the end of this discussion.

Looks like its linking back to this issue?

@Nornode
Copy link
Author

Nornode commented Dec 19, 2023

Thanks,
Yeah, I think I was more towards the bit-bang approach...
Given the var.firewall_filters above.

constructing:
IT's easy to construct a locals block resulting in this:

firewall_filter = {
  "defconf accept ICMP TF_Managed" = "*3"
  "defconf accept in ipsec policy TF_Managed" = "*6"
  "defconf accept out ipsec policy TF_Managed" = "*7"
  "defconf accept to local loopback CAPsMAN TF_Managed" = "*4"
  "defconf drop all from WAN not DSTNATed TF_Managed" = "*B"
  "defconf drop all not coming from LAN TF_Managed" = "*5"
  "defconf fasttrack TF_Managed" = "*8"
  "defconf forward accept established,related, untracked TF_Managed" = "*9"
  "defconf forward drop invalid TF_Managed" = "*A"
  "defconf input accept established related untracked TF_Managed" = "*1"
  "defconf input drop invalid TF_Managed" = "*2"
  "special dummy rule to show fasttrack counters" = "*C"
  "special_dummy_rule_to_show_fasttrack_counters TF_Managed" = "*F"
}

It should be fairly simple to do something along the lines with:

locals {
    firewall_filter = { for key, value in data.routeros_firewall.fw.rules : value.comment => value.id }  # Seen above 

    ## Following is Pseudo Code and does not work! - But shows How I thought it can be solved.
    id_of_next_filter_in_variable = { for key, value in var.firewall_filters : key => (index(keys(var.firewall_filters), key) + 1) } 
    
    firewall_filters = for i in keys(local.firewall_filter) : i => { 
      place_before = local.id_of_next_filter_in_variable[i].value
      ... = ... ##Any other key & value pair in var.firewall_filter
    }
}

Idea is that you should end up with something looking like this:
All dynamicly created because they are all configured in var.firewall_filters as a single structure.

local.firewall_filters = {
  special_dummy_rule_to_show_fasttrack_counters =
    place_before = "*1"
    ...
  defconf input accept established related untracked = 
    place_before = "*2"
    ...
  defconf input drop invalid = 
    place_before = "*3"
    ...
  ...
    ...
}

Then it can be then created as something like:

resource "routeros_ip_firewall_filter" "rule" {
  for_each =  { for key, value in local.firewall_filters : key => value  } 

  place_before          = try(each.value.place_before, "*1")
  disabled              = try(each.value.disabled, var.disabled)
  action                = each.value.action
  chain                 = each.value.chain
  connection_state      = try(each.value.connection_state, null)
  connection_nat_state  = try(each.value.connection_nat_state, null)
  hw_offload            = try(each.value.hw_offload, false )
  ... = ...
}

Or do you know of a reason this should not work?

I can just think of a few complications that can occur:

  1. Creating several filters at the same time when the data is not yet updated.
  2. Creating one "last" isn't possible

@vaerh
Copy link
Collaborator

vaerh commented Dec 19, 2023

There are a few things about your approach that I'm not sure work:

  • You don't know the rule ids before creating the rules, so it's not correct to operate on the id.
  • You don't know in what order the rules will arrive, for this reason place_before stops working on large rule sets.

@OJFord
Copy link
Contributor

OJFord commented Mar 27, 2024

I think if not applying exclusively from Terraform after a reset without default configuration (which is also my preference I think, to keep defconf) it will be best to declare the resources for the defconf rules etc. and then import them?

Then they can not only be reference by other rules but also we can easily see (and accept or not) drift after an update. Except of course newly added rules.

The only thing better / that would account for rules added in an ROS update that I can think of would be a kind of meta resource that took ownership over all rules, like:

resource "routeros_ip_firewall" "example" {
    filters = [
      # ...
    ]

    # or:
    # filter {
    # ...
}

Then if you added that empty and applied against a default router it would refresh, see the defconf rules, and want to remove them. Just some one-time setup to add them in, handily planning again would point out any typos or bits you got wrong/missed, and then they'd be managed going forwards, and any new defconf added in an update would work the same way on next plan.

@vaerh
Copy link
Collaborator

vaerh commented Mar 27, 2024

It seems to me that the creation and management of the meta resource should be done from some higher level application. Now it is possible to comfortably operate with firewall rules by implementing the move command. It is possible to control the completeness and order of firewall rules created by TF, but there is no possibility to react adequately to changes made by external systems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants