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

Proposal/discussion: More flexible ways to enable/disable rules from configuration #3174

Open
LucaGuerra opened this issue Apr 18, 2024 · 15 comments · May be fixed by #3178
Open

Proposal/discussion: More flexible ways to enable/disable rules from configuration #3174

LucaGuerra opened this issue Apr 18, 2024 · 15 comments · May be fixed by #3178
Assignees
Milestone

Comments

@LucaGuerra
Copy link
Contributor

LucaGuerra commented Apr 18, 2024

Motivation

Currently, we have several rules files and many users that wish to enable and disable rules without having to go through each rule file and changing the enabled field. We now have the following options:

  • -D <substring> Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.
  • -T <tag> Turn off any rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -t.
  • -t <tag> Only enable those rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -T/-D.

There are two main issues here:

For this reason I would like to propose another way of accessing this data. The design is up for discussion and feedback is absolutely welcome.

Feature Proposal

I thought about a design that fixes the above two points. A new key in the falco.yaml version called rules (name can be discussed but I would like to keep it short) that allows to specify a sequence of "commands" to enable and disable rules. It would accept a triplet of <command>:<object>:<name>

example (rule and tag names are made up)

rules:
  - only:tag:network
  - enable:rule:shell_in_container
  - enable:rule:k8s_*
  - disable:rule:connection_to_suspicious_server

At the end of this example, Falco would only consider networking tagged rules except for one connection_to_suspicious_server, plus all rules starting with k8s_ and the shell_in_container rule.

The same configuration could also be specified on the command line with something like:

$ falco -o rules[]=only:tag:network -o rules[]=enable:rule:shell_in_container -o rules[]=enable:rule:k8s_* -o rules[]=disable:rule:connection_to_suspicious_server

Note that the syntax rules[] which allows to add an element to a sequence does not exist today and would need to be introduced.

Note that while in my opinion this mechanism provides a good degree of flexibility it may not be ideal and the design could be changed a lot before implementation. Comments are very welcome!

@LucaGuerra
Copy link
Contributor Author

/assign

@leogr
Copy link
Member

leogr commented Apr 18, 2024

Hey @LucaGuerra

I really like the idea of applying commands in sequence 👍 It would solve the issues we currently have. After a quick look, I also have some ideas for possible improvements.

  • I'd avoid only, since we can just use disable with a catch-all

  • I'd prefer a more yaml syntax, for example:

rules:
  - disable:
     rule: *
  - enable:
     tag: network
  - enable:
     rule: Directory traversal monitored file
  - enable:
     rule: k8s_*
  - disable:
    rule: Some rule

wdyt? 🤔

@LucaGuerra
Copy link
Contributor Author

LucaGuerra commented Apr 18, 2024

Thanks for the suggestions @leogr , I do like them! Re. the removal of only it makes sense. Essentially if you want to only rule something you would disable rule * and then enable rule something like in the example. It requires an extra step at the beginning but it's clearer I think.

For the yaml, of course it will need some experimentation but if our engine can allow us to do something like -o rules[].enable.tag=network it'd look pretty clean. Also we would need to decide what to do in this case:

rules:
  - enable:
     tag: network
     rule: something else

could be an error or both could be applied

@leogr
Copy link
Member

leogr commented Apr 18, 2024

could be an error or both could be applied

I'd apply both because of the commutative property (the order does not matter when using the same command).

@leogr
Copy link
Member

leogr commented Apr 23, 2024

cc @falcosecurity/falco-maintainers for visibility

Tentatively for
/milestone 0.38.0

@poiana poiana added this to the 0.38.0 milestone Apr 23, 2024
@incertum
Copy link
Contributor

Hi @LucaGuerra thanks for getting a PR going.

Similar to the existing CLI flags it is unclear to me how we handle precedence -> what is at the end enabled when there are conflicting statements?

For example, I first disable one rule by name that has k8s in the rule name, but I then enable all rules that contain k8s. There are many such scenarios where it needs to be more clear to the end user how to use the new config. WDYT? Other than that, very supportive and it will be a very useful feature.

@leogr
Copy link
Member

leogr commented Apr 23, 2024

Similar to the existing CLI flags it is unclear to me how we handle precedence -> what is at the end enabled when there are conflicting statements?

If I understood correctly, each entry under rules is applied in order. The same should happen with the CLI options (which are applied after the config is read from the file).

Example:

(a)

rules:
  - disable:
     rule: K8s specific rule

and
(b)
-o rules[].enable.rule=k8s*

Results: all k8s rules are enabled.
Rationale: (a) is being shadowed by (b)

Counter example:

(a)

rules:
  - enable:
     rule: K8s*

and
(b)
-o rules[].disable.rule="K8s specific rule"

Results: All K8s rules are enabled, but "K8s specific rule"
Rationale: all k8s rules are initially enabled by (a), then "K8s specific rule" is disabled by (b)

@LucaGuerra Is my interpretation correct?
@incertum wdyt about this behavior?

IMO, it's understandable and natural. Basically, each enabling/disabling step is applied in order. That's it.

@LucaGuerra
Copy link
Contributor Author

@incertum thanks for the comment. So, I agree with you that what happens needs to be clear. While reading the code I noticed that it's even hard to understand what the current options are doing.

In this case, think of it like a series of "commands" that you issue after the ruleset is loaded and are evaluated in order. In your example it works exactly as you mentioned: you first disable a rule, and then enable all rules that match a specific pattern. The end result is logically that you might have re-enabled the rule that you disabled at the beginning.

In the Falco Slack channel today we discussed a concrete use case with an adopter:
They want to include our stable ruleset but only enable specific rules because they're testing out how noisy they are. So they would configure Falco like this:

rules:
  - disable:
      rule: *
  - enable:
      rule: Netcat Remote Code Execution in Container
  - enable:
      rule: Delete or rename shell history
  - enable:
      rule: Terminal shell in container
  - enable:
      rule: Launch Privileged Container

first you disable everything, then you enable only what you need. Their feedback on such a potential solution was positive.

@incertum
Copy link
Contributor

Ok in order works. Another quick question: This config determines the final behavior when for example a rule is disabled in the rules file, but enabled here?

All we need at the end is not just good docs but maybe also some informational print statements in such cases?

@LucaGuerra
Copy link
Contributor Author

This config determines the final behavior when for example a rule is disabled in the rules file, but enabled here?

Yes, basically this takes precedence. First all rules including overrides are applied and then this configuration.

not just good docs but maybe also some informational print statements in such cases?

Interesting idea. When would you print that? Do you think having that printed at Falco startup would be useful? Something like this at startup:

INFO: Disabling rules named "*"
INFO: Enabling rules named "Netcat Remote Code Execution in Container"

or did you have something different in mind?

@incertum
Copy link
Contributor

@LucaGuerra was thinking -- perhaps let's do something very simple and just print all enabled rules (in original order) when test running Falco with the --dry-run option. This would be similar to printing all interesting syscalls for the adaptive syscalls selection option. I find this very useful to double check a config before deploying.

@LucaGuerra
Copy link
Contributor Author

@incertum this makes sense to me. I think it's not really part of this feature but it'd be a welcome addition so you can easily troubleshoot what happens!

@Andreagit97
Copy link
Member

Thank you for this! I think this is something we really need! I'm on board with the design, it seems to cover all our use cases. Just one question, should we deprecate the old command line options -t,-T, and-D? With this method we can control the enabled rules with the config and the CLI so they seem a little bit redundant, WDYT? Maybe we can deprecate them for this release and add remove them in the next one (0.39.0)

@incertum
Copy link
Contributor

@Andreagit97 +1 re deprecating the old flags just so that we have a simpler interface going forward. The timeline you suggest is good.

@leogr
Copy link
Member

leogr commented Apr 30, 2024

Maybe we can deprecate them for this release and add remove them in the next one (0.39.0)

👍 for me too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants