-
Notifications
You must be signed in to change notification settings - Fork 18
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
More Pod attributes for PDP: SA and labels #665
Conversation
Signed-off-by: Ziv Nevo <[email protected]>
pkg/controlplane/authz/manager.go
Outdated
podInfo := m.getPodInfoByIP(req.IP) | ||
if podInfo == nil { | ||
m.logger.Infof("Pod has no info: IP=%v.", req.IP) | ||
return clientAttrs // better return an error here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning an error will simply yield a RST to the client connection.
I think it's better to keep it the way it is (which still allows for allow-all policies to proceed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit problematic when having policies with negative selectors (using the NotIn
and DoesNotExist
operators).
E.g., I have a policy to deny all connections, except from those originating from namespace foo
.
Connections from IPs for which CL cannot link a Pod, will always be allowed.
apiVersion: clusterlink.net/v1alpha1
kind: AccessPolicy
metadata:
name: deny-except-from-foo
spec:
action: deny
from:
- workloadSelector:
matchExpressions:
- key: clusterlink/metadata.clientNamespace
operator: NotIn
value: foo
to:
- workloadSelector: {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right.
I think the right thing to do is to do a non-cached GET from the API-server to get the pod info in this case.
I did not find a way to do this via the given client. This will be the best option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found this:
kubernetes-sigs/controller-runtime#585 (comment)
So there's a non-cached reader, but it's not available to authz.Manager
.
Need to propagate it from cl-controlplane/app/server.go
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently, even this is not good enough. Pod may start running and send requests, even before its IP is updated in etcd. From what I see, some non-cached List()
calls return the Pod with its Node IP, but without its Pod IP. It only gets updated later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How long is this window of a working pod with etcd not yet updated?
If not long, maybe we can stall a bit to wait for the update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or deny and let the client retry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the implementation: now if the client has no attributes (no pod info) AND the PDP has at least one policy which depends on client attributes, the request will be denied, and the client will have to retry.
Note that even if the PDP has no attribute-dependent policies, attribute-less requests can still be denied, depending on the policies (e.g., DENY policies take precedence, or no ALLOW policies)
This is enforced both on egress and on ingress.
pkg/controlplane/authz/manager.go
Outdated
clientAttrs[ClientSALabel] = podInfo.serviceAccount | ||
|
||
if src, ok := podInfo.labels["app"]; ok { | ||
clientAttrs[ServiceNameLabel] = src // deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it take to remove the deprecated attributes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they are being used currently in some experiments, so better wait a bit.
They will not appear in the documentation.
Namespace: server.Namespace, | ||
Image: "curlimages/curl", | ||
Args: []string{"curl", "-s", "-m", "1", "http://" + server.Name}, | ||
}) | ||
return strings.TrimSpace(body), err | ||
} | ||
|
||
// Sleep allows more time for CL to be notified of the new Pod, so CL can retrieve the Pod's info. | ||
func RunClientInPodWithSleep(cluster *util.KindCluster, server *util.Service) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this function. If the non-sleep function fails, you will be covered by the allowRetry=true
for the AccessService
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does the retry work when we run the client in a Pod?
Aren't we just creating Pods again and again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, my bad.
So maybe add a flag that removes the RestartPolicy: v1.RestartPolicyNever
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, my bad. So maybe add a flag that removes the
RestartPolicy: v1.RestartPolicyNever
.
This won't work.
How about using
--retry-delay 1 --retry-all-errors
in the curl pod command line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this works.
Signed-off-by: Ziv Nevo <[email protected]>
Is there a need to designate
IMO, we do not. I think it is up to the user to set the labels they care about and we should not treat
I would propose we deny on lack of sufficient context, to comply with principles of default deny, and let the client retry (e.g., we could consider reset or timeout as the response).
Tests can explicitly confirm the Pod has IP then wait 1s or so? |
pkg/controlplane/authz/manager.go
Outdated
podInfo := m.getPodInfoByIP(req.IP) | ||
if podInfo == nil { | ||
m.logger.Infof("Pod has no info: IP=%v.", req.IP) | ||
return clientAttrs // better return an error here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or deny and let the client retry?
Signed-off-by: Ziv Nevo <[email protected]>
Signed-off-by: Ziv Nevo <[email protected]>
Signed-off-by: Ziv Nevo <[email protected]>
Signed-off-by: Ziv Nevo <[email protected]>
After some rethinking, I now believe it's better for client and service to have distinct attribute prefixes. The main reason is that they don't have the exact same set of attributes (e.g., only clients have a service account, only services have a name). Having distinct prefixes will make it easier to ensure users are not using unavailable attributes in their policies. In addition, distinct prefixes make all attributes share the same pattern - a more consistent scheme. My current proposal for attribute names (inspired by K8s well-known labels): Client (Pod):
Service (export):
Peer:
@elevran , @orozery , @kfirtoledo - your thoughts? |
Signed-off-by: Ziv Nevo <[email protected]>
This PR adds more client-Pod attributes for the PDP to consider. We now have:
clusterlink/metadata.clientName
- the value of the Pod's labelapp
(if it has one)clusterlink/metadata.clientNamespace
- the Pod's namespaceclusterlink/metadata.clientServiceAccount
- the Pod's service accountclient/metadata.<key>
- the value of the Pod's label<key>
(one such attribute for each label)Open questions:
clusterlink/metadata.clientName
? Users can now simply useclient/metadata.app
insteadsleep 3
. Any better ideas?