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

Add support for ANP and BANP in the explain command #188

Merged
merged 4 commits into from
Mar 8, 2024

Conversation

Peac36
Copy link
Contributor

@Peac36 Peac36 commented Jan 14, 2024

Issue: #153

Screenshot from 2024-01-14 18-09-48
Screenshot from 2024-01-14 18-10-02

These images are based on the following files:

Also made some modifications to the original requirements:

  • Add Ingress/Egress rule names in the action column.
  • Add some formatting to the subject column.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jan 14, 2024
Copy link

netlify bot commented Jan 14, 2024

Deploy Preview for kubernetes-sigs-network-policy-api ready!

Name Link
🔨 Latest commit e9a2916
🔍 Latest deploy log https://app.netlify.com/sites/kubernetes-sigs-network-policy-api/deploys/65e9ec4316d4240008cace3d
😎 Deploy Preview https://deploy-preview-188--kubernetes-sigs-network-policy-api.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@k8s-ci-robot
Copy link
Contributor

Welcome @Peac36!

It looks like this is your first PR to kubernetes-sigs/network-policy-api 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/network-policy-api has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@k8s-ci-robot k8s-ci-robot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Jan 14, 2024
@k8s-ci-robot
Copy link
Contributor

Hi @Peac36. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jan 14, 2024
@astoycos
Copy link
Member

/ok-to-test
/assign @huntergregory

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jan 16, 2024
@astoycos
Copy link
Member

Thanks for this @Peac36! We'll get to it ASAP

@@ -50,7 +50,7 @@ func (s *SliceBuilder) TargetsTableLines(targets []*Target, isIngress bool) {
ruleType = "Egress"
}
for _, target := range targets {
sourceRules := slice.Sort(target.SourceRules)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend sorting all output so that it's:

  • deterministic
  • predictable for the reader

case *IPPeerMatcher:
s.IPPeerMatcherTableLines(a)
case *PodPeerMatcher:
s.PodPeerMatcherTableLines(a, NewV1Effect(true))
default:
panic(errors.Errorf("invalid PeerMatcher type %T", a))
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an unexpected case, right? might be worth a warning at least

@mattfenwick
Copy link
Contributor

nice one @Peac36 ! thanks for posting screenshots of the output 👍 👍 !!

I'll defer to @astoycos and @huntergregory <- they're the real approvers , please let me know if you'd like me to take a closer look at anything but overall I feel like this is a good patch!

@huntergregory
Copy link
Contributor

Thanks for making this PR @Peac36 ! Have been OOF and then got a concussion, but will aim to review this early next week!

Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again @Peac36 for tackling this important visualization piece!

You found all the code pieces nicely. The only remaining functionality is handling SameLabels and NotSameLabels.

Also, thanks for looking to improve the formatting. We will need to make sure everything is clear for every case. Along that line, could you add UTs to make sure we have expected outputs for all cases? For NPv1, I'd suggest using the example policies from cyclonus analyze --use-example-policies (believe that's the correct arg but you can also check cyclonus analyze --help).

cmd/policy-assistant/pkg/matcher/peermatcherv2.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/target.go Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
@@ -107,14 +107,12 @@ func LabelSelectorTableLines(selector metav1.LabelSelector) string {
}
var lines []string
if len(selector.MatchLabels) > 0 {
lines = append(lines, "Match labels:")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep this and Match expressions: ? Similarly to my previous comment, leaving this will make the output clearer imo

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or feel free to change the wording, and we can assess outputs for both the MatchLabels case and MatchExpressions

Copy link
Contributor Author

@Peac36 Peac36 Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it that way. We can change it later when we are sure for the output layout.

cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
@Peac36
Copy link
Contributor Author

Peac36 commented Jan 30, 2024

Thank you for the input. I'll try to resolve it as soon as possible.

@huntergregory
Copy link
Contributor

huntergregory commented Jan 30, 2024

EDIT: removed "verdict" idea below since traffic decisions could be made by overlapping peers.

About the Action column, I like the idea of adding the source there.
image

Taking it a step further, I think we could make it quicker to glance at and hold the user's hand a little more. Since a policy's rules share the same priority, we could consolidate a policy into a single line (so long as the rules share the same ports/protocols) and explicitly point out which actions are ineffective.

Example:

ANP:
    pri=15 (policy1): Allow (ineffective rules: Deny, Skip, Allow, Deny)
    pri=16 (policy3): Deny (ineffective rules: Skip)
    pri=35 (policy2): Skip
BANP: Deny (ineffective rules: Allow, Deny)

Another example:

ANP:
    pri=15 (policy1): Skip
BANP: Deny

Implementation Ideas

  • Find ANP with same subject, namespaces, and ports, then sort by priority

Testing

We should try to come up with a UT that covers these kinds of examples with multiple policies.

Also, a case where a policy has multiple rules that share the same subject and namespaces, but not the same ports to help convey that output behavior.

@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Feb 5, 2024
@Peac36
Copy link
Contributor Author

Peac36 commented Feb 11, 2024

@huntergregory - I've resolved most of the initial feedback and started working on the new implementation idea but I have a question about Source rules. Should we list all ANPs that affect this subject or we can just drop the column and add the policy name in the action column?

@huntergregory
Copy link
Contributor

Thanks @Peac36. I'm thinking to list all ANPs that affect this subject to keep in-line with the previous design. For context, here are those example policies I referenced before, and the previous output for NPv1:

$ ./cyclonus analyze --use-example-policies --mode explain
INFO[2024-02-11T16:40:59-08:00] log level set to 'info'
explained policies:
+---------+--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|  TYPE   |       TARGET       |                            SOURCE RULES                             |           PEER           |       PORT/PROTOCOL       |
+---------+--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
| Ingress | namespace: default | default/accidental-and                                              | namespace: default       | all ports, all protocols  |
|         | Match labels:      | default/accidental-or                                               | pods: Match labels:      |                           |
|         |   a: b             |                                                                     |   role: client           |                           |
+         +                    +                                                                     +--------------------------+                           +
|         |                    |                                                                     | namespace: Match labels: |                           |
|         |                    |                                                                     |   user: alice            |                           |
|         |                    |                                                                     | pods: Match labels:      |                           |
|         |                    |                                                                     |   role: client           |                           |
+         +                    +                                                                     +--------------------------+                           +
|         |                    |                                                                     | namespace: Match labels: |                           |
|         |                    |                                                                     |   user: alice            |                           |
|         |                    |                                                                     | pods: all                |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-nothing-to-v2-all-web                                 | no pods, no ips          | no ports, no protocols    |
|         | Match labels:      |                                                                     |                          |                           |
|         |   all: web         |                                                                     |                          |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-specific-port-from-role-monitoring-to-app-apiserver   | namespace: default       | port 5000 on protocol TCP |
|         | Match labels:      |                                                                     | pods: Match labels:      |                           |
|         |   app: apiserver   |                                                                     |   role: monitoring       |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-from-app-bookstore-to-app-bookstore-role-api          | namespace: default       | all ports, all protocols  |
|         | Match labels:      |                                                                     | pods: Match labels:      |                           |
|         |   app: bookstore   |                                                                     |   app: bookstore         |                           |
|         |   role: api        |                                                                     |                          |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+                           +
|         | namespace: default | default/allow-from-multiple-to-app-bookstore-role-db                | namespace: default       |                           |
|         | Match labels:      |                                                                     | pods: Match labels:      |                           |
|         |   app: bookstore   |                                                                     |   app: bookstore         |                           |
|         |   role: db         |                                                                     |   role: api              |                           |
+         +                    +                                                                     +--------------------------+                           +
|         |                    |                                                                     | namespace: default       |                           |
|         |                    |                                                                     | pods: Match labels:      |                           |
|         |                    |                                                                     |   app: bookstore         |                           |
|         |                    |                                                                     |   role: search           |                           |
+         +                    +                                                                     +--------------------------+                           +
|         |                    |                                                                     | namespace: default       |                           |
|         |                    |                                                                     | pods: Match labels:      |                           |
|         |                    |                                                                     |   app: inventory         |                           |
|         |                    |                                                                     |   role: web              |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-nothing                                               | no pods, no ips          | no ports, no protocols    |
|         | Match labels:      |                                                                     |                          |                           |
|         |   app: foo         |                                                                     |                          |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-all-to-app-web                                        | all pods, all ips        | all ports, all protocols  |
|         | Match labels:      | default/allow-all-to-version2-app-web                               |                          |                           |
|         |   app: web         | default/allow-all-to-version3-app-web                               |                          |                           |
|         |                    | default/allow-all-to-version4-app-web                               |                          |                           |
|         |                    | default/allow-from-anywhere-to-app-web                              |                          |                           |
|         |                    | default/allow-from-namespace-to-app-web                             |                          |                           |
|         |                    | default/allow-from-namespace-with-labels-type-monitoring-to-app-web |                          |                           |
|         |                    | default/allow-nothing-to-app-web                                    |                          |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+                           +
|         | namespace: default | default/allow-all-within-namespace                                  | namespace: default       |                           |
|         | all pods           | default/allow-nothing-to-anything                                   | pods: all                |                           |
+---------+--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         |                    |                                                                     |                          |                           |
+---------+--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
| Egress  | namespace: default | default/allow-egress-on-port-app-foo                                | all pods, all ips        | port 53 on protocol TCP   |
|         | Match labels:      | default/allow-egress-to-all-namespace-from-app-foo-on-port-53       |                          | port 53 on protocol UDP   |
|         |   app: foo         | default/allow-no-egress-from-labels-app-foo                         |                          |                           |
|         |                    | default/allow-nothing                                               |                          |                           |
+         +--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+
|         | namespace: default | default/allow-no-egress-from-namespace                              | no pods, no ips          | no ports, no protocols    |
|         | all pods           |                                                                     |                          |                           |
+---------+--------------------+---------------------------------------------------------------------+--------------------------+---------------------------+

@huntergregory
Copy link
Contributor

@Peac36 btw would you mind continuing the PR in separate commits? Will make it easier to review/track changes

@huntergregory
Copy link
Contributor

Also @Peac36, we're planning to record a demo in a week or so for the Policy Assistant. Would be awesome to showcase your work! I'd like to give you a shoutout in a slide for our upcoming KubeCon presentation, similar to slide 25 here from the Fall.

Feel free to join the Kubernetes Slack workspace -> sig-network-policy-api channel and DM me there!

@Peac36
Copy link
Contributor Author

Peac36 commented Feb 21, 2024

@Peac36 btw would you mind continuing the PR in separate commits? Will make it easier to review/track changes

Sure.

Also @Peac36, we're planning to record a demo in a week or so for the Policy Assistant. Would be awesome to showcase your work! I'd like to give you a shoutout in a slide for our upcoming KubeCon presentation, similar to slide 25 here from the Fall.

Awesome. I'm almost ready with the grouping of the ANPs and after that, I'll take care of the BANPs and the tests. I will be ready with the whole thing probably on Monday. I hope this is OK for you guys.

@Peac36 Peac36 force-pushed the update/153 branch 3 times, most recently from 5c73100 to c5db850 Compare February 26, 2024 18:22
@Peac36
Copy link
Contributor Author

Peac36 commented Feb 26, 2024

Hey @huntergregory I'm ready with the feedback and implementation of the idea you gave.

Here is a short preview.

Screenshot from 2024-02-26 20-29-13

Added tests for BuildV1AndV2NetPols to assert that

  • Anps with the same target would be grouped together
  • Anps that have the same target,protocols, and peers would be together
  • Banps would be added to a target group if it has the same peers and protocols.

Let me know if you have more ideas for tests.

Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Peac36 the screenshot looks really good. Can we flip the ordering for priorities in Action column? Highest priority (lowest pri number) coming first.

Had a few thoughts on simplifying implementation. My main goal is to keep parallels with NPv1 where possible, and to minimize change to NPv1 and functionality outside the summary table.

Also, thanks for adding tests. So I was thinking, to prevent regressions, it'd be nice to just have maybe one integration test comparing the output of cyclonus analyze --mode explain to an expected table (including NPv1).

Pretty simple, just something like this as a regular UT (no need for gomega?) in a new file test/integration/explain_test.go:

tableOutput := policy.ExplainTable()
expectedTable := """---------------------------
| Name | Subject | Action |
| abc     | ns=x     | allow   |
---------------------------
require.Equal(t, expectedTable, tableOutput)
"""

Also, we don't have a PR check for it yet. Could you run go test . in both test/integration/ and pkg/matcher/ directories to make sure previous tests are all green?

cmd/policy-assistant/examples/example.go Outdated Show resolved Hide resolved
cmd/policy-assistant/examples/example.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/builder.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/builder.go Outdated Show resolved Hide resolved
@@ -87,6 +89,8 @@ func SetupAnalyzeCommand() *cobra.Command {
func RunAnalyzeCommand(args *AnalyzeArgs) {
// 1. read policies from kube
var kubePolicies []*networkingv1.NetworkPolicy
var kubeANPs []*v1alpha1.AdminNetworkPolicy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for a follow-up PR: set these via CLI (#201)

cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
default:
panic(errors.Errorf("invalid PeerMatcher type %T", a))
s.PodPeerMatcherTableLines(t, NewV1Effect(true), "")
case *PeerMatcherAdmin:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplification idea: before this function, combine all ANPs + BANPs sharing the same subject into one target using BuildV1AndV2NetPols(simplify=true). Then at this case in the switch statement, we know this is an admin target. Let's make a separate function call here to render the target's peers, and break out of the current for loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within this function call, we can group by PeerMatchers by Peer and Port

cmd/policy-assistant/pkg/matcher/builder_tests.go Outdated Show resolved Hide resolved
@Peac36 Peac36 force-pushed the update/153 branch 5 times, most recently from 8fdff90 to 82478cb Compare March 4, 2024 15:28
@Peac36
Copy link
Contributor Author

Peac36 commented Mar 5, 2024

@huntergregory - Can you review it again? I refactor it based on your feedback. So instead of grouping in the parsing stage, I introduced a new struct that combines all anps and bansp before printing stage. The code is much simpler now

Also, we don't have a PR check for it yet. Could you run go test . in both test/integration/ and pkg/matcher/ directories to make sure previous tests are all green?

All green.

Pretty simple, just something like this as a regular UT (no need for gomega?) in a new file test/integration/explain_test.go:

Done. Added a test for printing anps and banps as well.

Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for simplifying @Peac36, this will help us in the long run. And thanks for working on this quickly. Let's address a couple questions/nits and then we can get this merged. Would you be able to tackle these ASAP?

Seeing a few discrepancies between your last screenshot and the text in your integration test. Do you know why? Which is correct?

Before:
image

After:
image

cmd/policy-assistant/test/integration/explain_test.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
cmd/policy-assistant/pkg/matcher/explain.go Outdated Show resolved Hide resolved
@Peac36
Copy link
Contributor Author

Peac36 commented Mar 6, 2024

Thanks for the feedback @huntergregory. Already fixed some of them, however, I'll need some more - probably later tomorrow will be able to resolve them all. About the discrepancies - the issue came from here:

https://github.com/kubernetes-sigs/network-policy-api/pull/188/files#diff-0c40ee241d83fc2c8e730d1cfea6a20eccbfd5a0c99a346073bee43e6646c44dR194

I missed including the namespace selector when building the map key so the grouping was incorrect.

Here is the result after the fix. Please note that I made some changed to the Banp so the result should not be the same as the one from previous examples.
Screenshot from 2024-03-06 18-42-13

@Peac36
Copy link
Contributor Author

Peac36 commented Mar 7, 2024

@huntergregory - I've resolved your last feedback.

Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome thank you @Peac36 !!

/lgtm

@mattfenwick could we get your seal of approval? Also going to raise a PR to add myself to cmd/policy-assistant/OWNERS.

@huntergregory
Copy link
Contributor

Andrew added me as owner actually, let’s see if this works 😆

/lgtm

/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 8, 2024
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: huntergregory, Peac36

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Mar 8, 2024
@k8s-ci-robot k8s-ci-robot merged commit 0368c76 into kubernetes-sigs:main Mar 8, 2024
8 checks passed
@mattfenwick
Copy link
Contributor

Awesome thank you @Peac36 !!

/lgtm

@mattfenwick could we get your seal of approval? Also going to raise a PR to add myself to cmd/policy-assistant/OWNERS.

I know it's too late but I'll do it anyway!

/lgtm
/approve

great work @Peac36 , I love where y'all are taking this!

@huntergregory
Copy link
Contributor

Congrats @Peac36 on the first policy assistant PR!

Just messaged you on Slack about something for tomorrow (Monday) if you have time

@huntergregory
Copy link
Contributor

Fixed #153

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants