Skip to content

Commit

Permalink
Improve flannel RBAC changes
Browse files Browse the repository at this point in the history
Only wait for k3s-controller RBAC when AuthorizeNodeWithSelectors blocks kubelet from listing nodes

Signed-off-by: Brad Davidson <[email protected]>
  • Loading branch information
brandond committed Jan 11, 2025
1 parent dde2fef commit 6b0247f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 7 deletions.
21 changes: 14 additions & 7 deletions pkg/agent/flannel/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions pkg/util/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 6b0247f

Please sign in to comment.