Improve flannel RBAC changes

Only wait for k3s-controller RBAC when AuthorizeNodeWithSelectors blocks kubelet from listing nodes

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
pull/11571/head
Brad Davidson 2025-01-10 22:52:37 +00:00 committed by Brad Davidson
parent dde2fef0c5
commit 6b0247fa4d
2 changed files with 42 additions and 7 deletions

View File

@ -69,14 +69,21 @@ func Prepare(ctx context.Context, nodeConfig *config.Node) error {
func Run(ctx context.Context, nodeConfig *config.Node) error {
logrus.Infof("Starting flannel with backend %s", nodeConfig.FlannelBackend)
if err := util.WaitForRBACReady(ctx, nodeConfig.AgentConfig.KubeConfigK3sController, util.DefaultAPIServerReadyTimeout, authorizationv1.ResourceAttributes{
Verb: "list",
Resource: "nodes",
}, ""); err != nil {
return errors.Wrap(err, "flannel failed to wait for RBAC")
kubeConfig := nodeConfig.AgentConfig.KubeConfigKubelet
resourceAttrs := authorizationv1.ResourceAttributes{Verb: "list", Resource: "nodes"}
// Compatibility code for AuthorizeNodeWithSelectors feature-gate.
// If the kubelet cannot list nodes, then wait for the k3s-controller RBAC to become ready, and use that kubeconfig instead.
if canListNodes, err := util.CheckRBAC(ctx, kubeConfig, resourceAttrs, ""); err != nil {
return errors.Wrap(err, "failed to check if RBAC allows node list")
} else if !canListNodes {
kubeConfig = nodeConfig.AgentConfig.KubeConfigK3sController
if err := util.WaitForRBACReady(ctx, kubeConfig, util.DefaultAPIServerReadyTimeout, resourceAttrs, ""); err != nil {
return errors.Wrap(err, "flannel failed to wait for RBAC")
}
}
coreClient, err := util.GetClientSet(nodeConfig.AgentConfig.KubeConfigK3sController)
coreClient, err := util.GetClientSet(kubeConfig)
if err != nil {
return err
}
@ -90,7 +97,7 @@ func Run(ctx context.Context, nodeConfig *config.Node) error {
return errors.Wrap(err, "failed to check netMode for flannel")
}
go func() {
err := flannel(ctx, nodeConfig.FlannelIface, nodeConfig.FlannelConfFile, nodeConfig.AgentConfig.KubeConfigK3sController, nodeConfig.FlannelIPv6Masq, netMode)
err := flannel(ctx, nodeConfig.FlannelIface, nodeConfig.FlannelConfFile, kubeConfig, nodeConfig.FlannelIPv6Masq, netMode)
if err != nil && !errors.Is(err, context.Canceled) {
logrus.Errorf("flannel exited: %v", err)
os.Exit(1)

View File

@ -147,6 +147,34 @@ func WaitForRBACReady(ctx context.Context, kubeconfigPath string, timeout time.D
return nil
}
// CheckRBAC performs a single SelfSubjectAccessReview or SubjectAccessReview, returning a
// boolean indicating whether or not the requested access would be allowed. This is basically
// `kubectl auth can-i`.
func CheckRBAC(ctx context.Context, kubeconfigPath string, ra authorizationv1.ResourceAttributes, user string, groups ...string) (bool, error) {
restConfig, err := GetRESTConfig(kubeconfigPath)
if err != nil {
return false, err
}
authClient, err := authorizationv1client.NewForConfig(restConfig)
if err != nil {
return false, err
}
var reviewFunc genericAccessReviewRequest
if len(user) == 0 && len(groups) == 0 {
reviewFunc = selfSubjectAccessReview(authClient, ra)
} else {
reviewFunc = subjectAccessReview(authClient, ra, user, groups)
}
status, err := reviewFunc(ctx)
if err != nil {
return false, err
}
return status.Allowed, nil
}
// selfSubjectAccessReview returns a function that makes SelfSubjectAccessReview requests using the
// provided client and attributes, returning a status or error.
func selfSubjectAccessReview(authClient *authorizationv1client.AuthorizationV1Client, ra authorizationv1.ResourceAttributes) genericAccessReviewRequest {