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

fix endpoint selection for wildcard to/fromEndpoint in CCNP #12890

Merged
merged 4 commits into from Sep 8, 2020

Conversation

fristonio
Copy link
Member

@fristonio fristonio commented Aug 14, 2020

See individual commits for more details.

Example of preflight warning.
image

Fix endpoint selection for a wildcard to/fromEndpoints in CCNP.
Cilium will only allow access from Cilium-managed endpoints in such cases instead of allowing traffic from any source. Preflight checks, when following the upgrade guide, have been extended to warn users of the new behavior.

@fristonio fristonio requested a review from a team as a code owner August 14, 2020 11:22
@fristonio fristonio requested a review from a team August 14, 2020 11:22
@maintainer-s-little-helper maintainer-s-little-helper bot added the dont-merge/needs-release-note-label The author needs to describe the release impact of these changes. label Aug 14, 2020
@fristonio fristonio added the release-note/minor This PR changes functionality that users may find relevant to operating Cilium. label Aug 14, 2020
@maintainer-s-little-helper maintainer-s-little-helper bot removed the dont-merge/needs-release-note-label The author needs to describe the release impact of these changes. label Aug 14, 2020
Copy link
Member

@joestringer joestringer left a comment

Choose a reason for hiding this comment

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

I was expecting this change to be made in the same (or similar) place where we inject the namespace selector for CNP EndpointSelectors, but I don't see that logic here so it's hard to compare against that logic. Were you aware of that other code? Wondering if there's a functional tradeoff from having it here vs. wherever the namespace selector CNP injection logic is.

@fristonio
Copy link
Member Author

Hey Joe!
That was our initial approach towards this. But while working on the issue @aanm and @jrajahalme figured that if we introduce the changes where we inject the namespace selector for CNP we would essentially be modifying the semantics of CCNP. So if a user creates a CCNP with the following spec:

apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: "test-all-endpoints"
spec:
  endpointSelector:
    matchLabels:
      app: nginx
  ingress:
  - fromEndpoints:
    - {}
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP

The policy user gets using cilium policy get will look something like this, where we have changed the semantics itself for CCNP provided by the user by adding the matchExpression.

[
  {
    "endpointSelector": {
      "matchLabels": {
        "any:app": "nginx"
      }
    },
    "ingress": [
      {
        "fromEndpoints": [
          {
            "matchExpressions": [
              {
                "key": "k8s:io.kubernetes.pod.namespace",
                "operator": "Exists"
              }
            ]
          }
        ],
        "toPorts": [
          {
            "ports": [
              {
                "port": "80",
                "protocol": "TCP"
              }
            ]
          }
        ]
      }
    ],
    "labels": [
      {
        "key": "io.cilium.k8s.policy.derived-from",
        "value": "CiliumClusterwideNetworkPolicy",
        "source": "k8s"
      },
      {
        "key": "io.cilium.k8s.policy.name",
        "value": "test-all-endpoints",
        "source": "k8s"
      },
      {
        "key": "io.cilium.k8s.policy.uid",
        "value": "3f3e0474-3ae7-47e5-8fc2-9eb174ed0594",
        "source": "k8s"
      }
    ]
  }
]

This was the reason in the PR, changes were pushed down for a policy update when we resolve the policy for the endpoints rather than injecting it earlier during a parse.

On digging a bit deeper into how this(the current changes) might affect a user we figured that this implementation might also not be correct because we are adding semantics of K8s to a policy that might not even be related to k8s, because at this point we are resolving a general policy rule. So consider a case where user imports the below policy using cilium policy import $POLICY_FILE

[{
    "endpointSelector": {
      "matchLabels": {
        "any:app": "nginx"
      }
    },
    "ingress": [
      {
        "fromEndpoints": [
          {}
        ],
        "toPorts": [
          {
            "ports": [
              {
                "port": "80",
                "protocol": "TCP"
              }
            ]
          }
        ]
      }
    ],
    "labels": []
}]

Even though the policy does not contain any reference to k8s it will still only allow traffic from cilium managed k8s endpoints. So in a non-K8s environment this is essentially blocking all the traffic.

Now if we were to go back to doing this injection where we do namespace injection for CNP, we will also have the same issue we are trying to solve here for CCNP for all the policies imported via cilium policy import $POLICY_FILE. Where we are allowing all traffic for policies with wildcard imported using cilium policy import. So what we need is a way to identify all the cilium managed endpoints(irrespective of the environment like K8s) and then add a match for those in the section that is currently in the PR.

We are still discussing on slack what would be the best way to achieve this. I will mark the Pull Request draft for now.

@fristonio fristonio marked this pull request as draft August 15, 2020 06:40
@joestringer
Copy link
Member

Now if we were to go back to doing this injection where we do namespace injection for CNP, we will also have the same issue we are trying to solve here for CCNP for all the policies imported via cilium policy import $POLICY_FILE.

I think this is an acceptable trade-off. In Kubernetes mode with CNP, we inject the namespace which means that toEndpoints / fromEndpoints matches only pods. With direct cilium policy import, there is no such behaviour so it's "namespace blind" in some sense. Outside of k8s, we're not even guaranteed to have a notion of a 'namespace'.

If there are users who actively care about this kind of case with non-k8s mode, I would encourage them to look into this topic themselves and come up with a proposal to modify the semantics of toEndpoints / fromEndpoints. Right now, I don't think there's sufficient user interest in direct policy import for us to address the underlying questions/semantics in that case.

@fristonio
Copy link
Member Author

Yeah, that seems like a reasonable trade-off to me as well. So just to be clear we will the do namespace injection in to/fromEndpoint selector when we parse the policy from CNP/CCNP right? For direct policy imports, we are currently assuming allow-all as default behavior since we don't have a notion of namespace there?

@jrajahalme @aanm what do you think about this? We will still have the issue we were trying to address earlier, where we change the semantics of CCNP when doing parse.

fristonio added a commit that referenced this pull request Aug 18, 2020
* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
@fristonio
Copy link
Member Author

Pushed the updated fix.

After this patch, a CCNP created with the below configuration

$ cat ccnp.yaml
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: "test-from-endpoints"
spec:
  endpointSelector:
    matchLabels:
      app: test
  ingress:
  - fromEndpoints:
    - {}
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP

Will end in the policy repository like this

$ cilium policy get
[
  {
    "endpointSelector": {
      "matchLabels": {
        "any:app": "test"
      }
    },
    "ingress": [
      {
        "fromEndpoints": [
          {
            "matchExpressions": [
              {
                "key": "k8s:io.kubernetes.pod.namespace",
                "operator": "Exists"
              }
            ]
          }
        ],
        "toPorts": [
          {
            "ports": [
              {
                "port": "80",
                "protocol": "TCP"
              }
            ]
          }
        ]
      }
    ],
    "labels": [
      {
        "key": "io.cilium.k8s.policy.derived-from",
        "value": "CiliumClusterwideNetworkPolicy",
        "source": "k8s"
      },
      {
        "key": "io.cilium.k8s.policy.name",
        "value": "test-from-endpoints",
        "source": "k8s"
      },
      {
        "key": "io.cilium.k8s.policy.uid",
        "value": "7e204037-e1ec-46aa-9884-41fa1ef339d5",
        "source": "k8s"
      }
    ]
  }
]

eventually ending up to allow Ingress from all the endpoints having a namespace label(CIlium managed k8s endpoints), something similar to below output.

$ sudo cilium bpf policy get 728
DIRECTION   LABELS (source:key[=value])                                    PORT/PROTO   PROXY PORT   BYTES   PACKETS
Ingress     reserved:host                                                  ANY          NONE         0       0
Ingress     reserved:remote-node                                           ANY          NONE         0       0
Ingress     k8s:io.cilium.k8s.policy.cluster=default                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.serviceaccount=cilium-etcd-sa
            k8s:io.cilium/app=etcd-operator
            k8s:io.kubernetes.pod.namespace
Ingress     k8s:app=etcd                                                   80/TCP       NONE         0       0
            k8s:etcd_cluster=cilium-etcd
            k8s:io.cilium.k8s.policy.cluster=default
            k8s:io.cilium.k8s.policy.serviceaccount=default
            k8s:io.cilium/app=etcd-operator
            k8s:io.kubernetes.pod.namespace
Ingress     k8s:io.cilium.k8s.policy.cluster=default                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.serviceaccount=kube-dns
            k8s:io.kubernetes.pod.namespace=kube-system
            k8s:k8s-app=kube-dns
Ingress     k8s:eks.amazonaws.com/component=kube-dns                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.cluster=default
            k8s:io.cilium.k8s.policy.serviceaccount=kube-dns
            k8s:io.kubernetes.pod.namespace=kube-system
            k8s:k8s-app=kube-dns
Ingress     k8s:io.cilium.k8s.policy.cluster=default                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.serviceaccount=coredns
            k8s:io.kubernetes.pod.namespace=kube-system
            k8s:k8s-app=kube-dns
Ingress     k8s:io.cilium.k8s.policy.cluster=default                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.serviceaccount=cilium-operator
            k8s:io.cilium/app=operator
            k8s:io.kubernetes.pod.namespace
            k8s:name=cilium-operator
Ingress     k8s:eks.amazonaws.com/component=coredns                        80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.cluster=default
            k8s:io.cilium.k8s.policy.serviceaccount=coredns
            k8s:io.kubernetes.pod.namespace=kube-system
            k8s:k8s-app=kube-dns
Ingress     k8s:io.cilium.k8s.policy.cluster=default                       80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.serviceaccount=cilium-etcd-operator
            k8s:io.cilium/app=etcd-operator
            k8s:io.kubernetes.pod.namespace
            k8s:name=cilium-etcd-operator
Ingress     k8s:app=test                                                   80/TCP       NONE         0       0
            k8s:io.cilium.k8s.policy.cluster=default
            k8s:io.cilium.k8s.policy.serviceaccount=default
            k8s:io.kubernetes.pod.namespace=default
Egress      reserved:unknown

Copy link
Member

@joestringer joestringer left a comment

Choose a reason for hiding this comment

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

Looks good to me, just one minor nit.

pkg/k8s/apis/cilium.io/utils/utils.go Outdated Show resolved Hide resolved
fristonio added a commit that referenced this pull request Aug 20, 2020
* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
@fristonio fristonio marked this pull request as ready for review August 20, 2020 06:51
@fristonio fristonio requested a review from a team August 20, 2020 06:51
@fristonio fristonio requested a review from a team as a code owner August 20, 2020 10:10
@fristonio
Copy link
Member Author

test-me-please

pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
pkg/k8s/apis/cilium.io/v2/validator/validator_test.go Outdated Show resolved Hide resolved
pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
Copy link
Member

@christarazi christarazi left a comment

Choose a reason for hiding this comment

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

LGTM; just one question below.

Copy link
Member

@pchaigno pchaigno left a comment

Choose a reason for hiding this comment

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

LGTM. Just one minor nit below.

pkg/k8s/apis/cilium.io/v2/validator/validator.go Outdated Show resolved Hide resolved
@fristonio
Copy link
Member Author

test-me-please

fristonio added a commit that referenced this pull request Aug 25, 2020
* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
@aanm aanm added the release-note/major This PR introduces major new functionality to Cilium. label Sep 7, 2020
@fristonio
Copy link
Member Author

test-me-please

@aanm aanm added release-note/bug This PR fixes an issue in a previous release of Cilium. and removed release-note/major This PR introduces major new functionality to Cilium. labels Sep 8, 2020
@aanm aanm merged commit 2231af0 into master Sep 8, 2020
@aanm aanm deleted the pr/fristonio/fix-12844 branch September 8, 2020 15:11
aanm pushed a commit that referenced this pull request Sep 8, 2020
* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
fristonio added a commit that referenced this pull request Sep 9, 2020
[ upstream commit 905b8d4 ]

* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
fristonio added a commit that referenced this pull request Sep 9, 2020
[ upstream commit 905b8d4 ]

* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
aanm pushed a commit that referenced this pull request Sep 9, 2020
[ upstream commit 905b8d4 ]

* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
@maintainer-s-little-helper maintainer-s-little-helper bot moved this from Needs backport from master to Backport pending to v1.8 in 1.8.4 Sep 9, 2020
@maintainer-s-little-helper maintainer-s-little-helper bot moved this from Backport pending to v1.8 to Backport done to v1.8 in 1.8.4 Sep 9, 2020
@maintainer-s-little-helper maintainer-s-little-helper bot moved this from Backport pending to v1.8 to Backport done to v1.8 in 1.8.4 Sep 9, 2020
aditighag pushed a commit that referenced this pull request Sep 10, 2020
[ upstream commit 905b8d4 ]

* This commit fixes an issue in endpoint selection when we provide
  wildcard for to/fromEndpoint in CCNP. When a wildcard is provided in CCNP
  fromEndpoint selector we end up with a truly empty endpoint selector.
  This results in allowing all traffic. The commit restricts this to only
  include endpoints that are managed by cilium by checking the presence
  of namespace label in endpoint.

* For a more detailed explaination of the approach and the issue take a
  look at discussion following this github comment -
  #12890 (comment)

Signed-off-by: Deepesh Pathak <deepshpathak@gmail.com>
@joestringer joestringer moved this from Needs backport from master to Backport done to v1.7 in 1.7.10 Sep 30, 2020
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.
Projects
No open projects
1.7.10
Backport done to v1.7
1.8.4
Backport done to v1.8
Development

Successfully merging this pull request may close these issues.

Empty to/fromEndpoints in CCNP matches world
6 participants