Skip to content

endpoint: Push L4-only policies into BPF maps#2992

Merged
tgraf merged 1 commit intocilium:masterfrom
joestringer:submit/l4-policy-fix
Mar 8, 2018
Merged

endpoint: Push L4-only policies into BPF maps#2992
tgraf merged 1 commit intocilium:masterfrom
joestringer:submit/l4-policy-fix

Conversation

@joestringer
Copy link
Copy Markdown
Member

@joestringer joestringer commented Mar 2, 2018

Fix L4-only policy enforcement on ingress without `fromEndpoints` selector

The description of L4Filter.FromEndpoints is as follows:

// FromEndpoints limit the source labels for allowing traffic. If
// FromEndpoints is empty, then it selects all endpoints.

However, to date when pushing L4Filters into the BPF maps, we were
treating an empty FromEndpoints slice as selecting nothing. This lead
to L4-only policies not allowing traffic on ingress, and with upcoming
egress label-based policies implementations, would also break the
current workflow for specifying ToPorts policies on egress (ie,
without a wildcard EndpointSelector).

Treat the empty L4Filter selector list as a wildcard and push a
label-dependent l4 map entry into the datapath for each known identity
in the node.

While we're at it, extend the L4 policy tests to cover egress as well.

Fixes: #2907

Signed-off-by: Joe Stringer joe@covalent.io

@joestringer joestringer added pending-review release-note/bug This PR fixes an issue in a previous release of Cilium. sig/policy Impacts whether traffic is allowed or denied based on user-defined policies. labels Mar 2, 2018
@joestringer joestringer requested review from a team as code owners March 2, 2018 00:03
@joestringer
Copy link
Copy Markdown
Member Author

test-me-please

@joestringer
Copy link
Copy Markdown
Member Author

For egress path in future, it would be nice to instead map down the wildcard selector as {identity: 0, dport...} because then we can still appropriately apply L4-only policies even if IP->ID mapping fails.

Comment thread pkg/endpoint/policy.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not use filter.FromEndpoints directly? ohh I see, you're adding a L3 wildcard if L3 is not defined. Can you please add a comment for that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done.

Comment thread pkg/endpoint/policy.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done.

Comment thread pkg/endpoint/policy.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Out of curiosity, does this means all SecIDs will be selected?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

For the case where the endpoint selector is empty, the new code inserts a wildcard selector which should select all SecIDs, yes.

@tgraf
Copy link
Copy Markdown
Contributor

tgraf commented Mar 2, 2018

I think this fix is not wrong but incomplete and in order to complete we will run into a problem.

First of all, it's contrary to what we have documented right now:

// - All members of this structure are optional. If omitted or empty, the
//   member will have no effect on the rule.

However, I agree that going this route is correct but I think we need to do it differently, because what you fix here must also apply to FromCIDR and FromEntities. We can't apply the logic to just FromEndpoints. A rule which only has ToPorts 80 set should also allow from any external client and it should also allow from the host. This means that if we have rule such as:

[{
    "labels": [{"key": "name", "value": "l4-rule"}],
    "endpointSelector": {"matchLabels":{"app":"myService"}},
    "ingress": [{
        "toPorts": [
            {"ports":[ {"port": "80", "protocol": "TCP"}]}
        ]
    }]
}]

Then this would have to translate into something like this:

[{
    "labels": [{"key": "name", "value": "l4-rule"}],
    "endpointSelector": {"matchLabels":{"app":"myService"}},
    "ingress": [{
        "toPorts": [
            {"ports":[ {"port": "80", "protocol": "TCP"}]}
        ],
        "fromEndpoints": [{}],
        "fromCIDR": ["0/0"],
        "fromEntities": [ "all" ],
    }]
}]

Assuming the above model, it then raises the question, how do to define a rule which only allows ingress from label "foo" without any further privileges granted? This is why we currently have a difference between empty selector to wildcard and nil.

I agree that it is confusing and that we have to change it. The good news is that we can change it while preserving backwards compatibility by bumping to v3 and converting from v2 to v3.

I suggest we do the following:

  1. Embed toPorts into the From* and To* structures to make the L3 dependant L4 part obvious and explicitly require the user to specify the wildcard if wanted. This will make it super obvious what is going on at all times.
  2. Declare the IngressRule and EgressRule a union which means that only one of FromEndpoints, FromRequires, FromCIDR and FromEntities can be specified. This makes it super obvious that there is no point in combing label based source selector and CIDR based source rules.
  3. Only add ToPorts to the From* and To* fields that support L3 dependant L4. This means we would currently exclude FromCIDR and ToCIDR until we have added support for it.

Example:

  endpointSelector:
    matchLabels:
      role: backend
  ingress:
  - fromEndpoints:
    - toPorts:
      - ports:
        - port: "80"
          protocol: TCP

@tgraf
Copy link
Copy Markdown
Contributor

tgraf commented Mar 3, 2018

@joestringer

After further discussion: I will open an issue to propose the above proposal for a policy v3 and we fix this in v2 in the following way:

  • Wildcard all L3 selectors (FromEndpoints, FromCIDR, and FromEntities) if none of the L3 selectors are specified. If any of them are specified in the rule, no wildcard expansion happens.

@joestringer
Copy link
Copy Markdown
Member Author

Sounds good, I'll get to that this week.

@joestringer
Copy link
Copy Markdown
Member Author

@tgraf I looked into it, we don't have such information at the L4Filter at the moment. The two paths forward I see are either:

  1. Restrict other combinations at the API layer (Reject policies that contain rules with more than one L3 match in a single rule #3015).
    • We only actually support two combinations with ToPorts: Either with FromEndpoints specified, or not at all.
    • If we restrict this at the API layer, then the current approach in this PR will solve the problem for now.
    • In future we'll need to fix it up, but that's OK. We'll do so when the support is expanded beyond the current support.
  2. Plumb CIDRs through the policy down to L4Filter.

@tgraf
Copy link
Copy Markdown
Contributor

tgraf commented Mar 6, 2018

@joestringer OK, I would pick 1) then and solve this properly via #3005

The description of `L4Filter.FromEndpoints` is as follows:

// FromEndpoints limit the source labels for allowing traffic. If
// FromEndpoints is empty, then it selects all endpoints.

However, to date when pushing L4Filters into the BPF maps, we were
treating an empty `FromEndpoints` slice as selecting nothing. This lead
to L4-only policies not allowing traffic on ingress, and with upcoming
egress label-based policies implementations, would also break the
current workflow for specifying `ToPorts` policies on egress (ie,
without a wildcard EndpointSelector).

Treat the empty L4Filter selector list as a wildcard and push a
label-dependent l4 map entry into the datapath for each known endpoint
in the node.

While we're at it, extend the L4 policy tests to cover egress as well.

Fixes: cilium#2907

Signed-off-by: Joe Stringer <joe@covalent.io>
@joestringer joestringer force-pushed the submit/l4-policy-fix branch from c7e52ab to f8b5e4c Compare March 8, 2018 19:31
@joestringer
Copy link
Copy Markdown
Member Author

test-me-please

@joestringer
Copy link
Copy Markdown
Member Author

Addressed the comments and rebased, ready for review. The comment in the patch assumes merging of #3015, but I believe this should fix the issue as-is.

@tgraf tgraf merged commit 1bd0c87 into cilium:master Mar 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/bug This PR fixes an issue in a previous release of Cilium. sig/policy Impacts whether traffic is allowed or denied based on user-defined policies.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants