Skip to content

🐛 Make joinConfiguration.discovery.bootstrapToken.token optional #12107

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

Merged
merged 1 commit into from
Apr 28, 2025

Conversation

Amulyam24
Copy link
Contributor

@Amulyam24 Amulyam24 commented Apr 17, 2025

What this PR does / why we need it:
In the cluster-api provider for IBM cloud, we set the API server endpoint explicitly in the join configuration. With the recent change via #11949, it has become mandatory to set the token value and cluster deployment fails with

KubeadmConfigTemplate.bootstrap.cluster.x-k8s.io "capibm-e2e-2nmy7v-md-0" is invalid: spec.template.spec.joinConfiguration.discovery.bootstrapToken.token: Invalid value: "": spec.template.spec.joinConfiguration.discovery.bootstrapToken.token in body should be at least 1 chars long, 

This PR adds the change to not set a hard validation for token and use the one generated by bootstrap provider in case it is empty.

Which issue(s) this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close the issue(s) when PR gets merged):
Fixes #

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Apr 17, 2025
@Amulyam24
Copy link
Contributor Author

/cc @Karthik-K-N

@k8s-ci-robot k8s-ci-robot added the do-not-merge/needs-area PR is missing an area label label Apr 17, 2025
@k8s-ci-robot k8s-ci-robot added the size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. label Apr 17, 2025
@Amulyam24 Amulyam24 changed the title Set min length validation to 0 for Bootstrap token 🐛 Set min length validation to 0 for Bootstrap token Apr 17, 2025
@Karthik-K-N
Copy link
Contributor

/cc @chrischdi @fabriziopandini

@@ -585,7 +585,7 @@ type BootstrapTokenDiscovery struct {
// token is a token used to validate cluster information
// fetched from the control-plane.
// +required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MinLength=0
Copy link
Member

Choose a reason for hiding this comment

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

I looked into #12019 that fixed a similar issue by making the field optional and adding omit empty, which seems a cleaner option to allow users to not set a field.

@JoelSpeed WDYT?

Also, Is this a non-breaking change? (I assume it is not breaking, but I would like to double check)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into #12019 that fixed a similar issue by making the field optional and adding omit empty, which seems a cleaner option to allow users to not set a field.

Right, making it optional would be better, will wait for @JoelSpeed's response.

Also, Is this a non-breaking change? (I assume it is not breaking, but I would like to double check)

It should be a non breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Technically any change we would make here could be considered breaking.

Adding a min length of 0 to a required field is odd and I would avoid personally. A required field where the zero value is valid does not actually behave as a required field for those using structured clients. For those using unstructured clients, it's even weirder, they have to specify the key, and possibly then set the zero value.

The lesser of two evils here, if there needs to be a case where this field is empty, it to make the field optional with omitempty.

Who consumes this API? Do we understand what the consumers will do if they see an empty string here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for the response, Token is being currently used in kubeadm_config controller and we have logic written to handle both the cases, that is to respect the value if set or generate one. Reference

// if BootstrapToken already contains a token, respect it; otherwise create a new bootstrap token for the node to join
if config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token == "" {
remoteClient, err := r.ClusterCache.GetClient(ctx, util.ObjectKey(cluster))
if err != nil {
return ctrl.Result{}, err
}
token, err := createToken(ctx, remoteClient, r.TokenTTL)
if err != nil {
return ctrl.Result{}, errors.Wrapf(err, "failed to create new bootstrap token")
}
config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token = token
log.V(3).Info("Altering JoinConfiguration.Discovery.BootstrapToken.Token")
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per suggestions, changed to field to optional. PTAL.

@Amulyam24 Amulyam24 force-pushed the token branch 2 times, most recently from ec3058e to 2426f1d Compare April 21, 2025 05:22
@Amulyam24 Amulyam24 changed the title 🐛 Set min length validation to 0 for Bootstrap token 🐛 Make joinConfiguration.discovery.bootstrapToken.token optional Apr 21, 2025
@Amulyam24 Amulyam24 force-pushed the token branch 2 times, most recently from c1f3b94 to fadadca Compare April 21, 2025 06:18
@Amulyam24
Copy link
Contributor Author

@fabriziopandini @JoelSpeed, PTAL if the change is okay?

@@ -584,10 +584,10 @@ type Discovery struct {
type BootstrapTokenDiscovery struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

This object now has no required field, so there will be difference in behaviour between not specifying the object, and specifying bootstrapToken: {}.

This is generally not desirable.

Is it valid to have an empty bootstrapToken? In the current use case, which alternative field would be used instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

From code reading what I can see is that the both the scenario's are handled currently, If boostStrapToken is not set and its nil, its being initialized first.
Also we have necessary checks for respecting the already set values as well.
Reference:

// otherwise it is necessary to ensure token discovery is properly configured
if config.Spec.JoinConfiguration.Discovery.BootstrapToken == nil {
config.Spec.JoinConfiguration.Discovery.BootstrapToken = &bootstrapv1.BootstrapTokenDiscovery{}
}
// calculate the ca cert hashes if they are not already set
if len(config.Spec.JoinConfiguration.Discovery.BootstrapToken.CACertHashes) == 0 {
hashes, err := certificates.GetByPurpose(secret.ClusterCA).Hashes()
if err != nil {
log.Error(err, "Unable to generate Cluster CA certificate hashes")
return ctrl.Result{}, err
}
config.Spec.JoinConfiguration.Discovery.BootstrapToken.CACertHashes = hashes
}
// if BootstrapToken already contains an APIServerEndpoint, respect it; otherwise inject the APIServerEndpoint endpoint defined in cluster status
apiServerEndpoint := config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint
if apiServerEndpoint == "" {
if !cluster.Spec.ControlPlaneEndpoint.IsValid() {
log.V(1).Info("Waiting for Cluster Controller to set Cluster.Spec.ControlPlaneEndpoint")
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
}
apiServerEndpoint = cluster.Spec.ControlPlaneEndpoint.String()
config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint = apiServerEndpoint
log.V(3).Info("Altering JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint", "apiServerEndpoint", apiServerEndpoint)
}
// if BootstrapToken already contains a token, respect it; otherwise create a new bootstrap token for the node to join
if config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token == "" {
remoteClient, err := r.ClusterCache.GetClient(ctx, util.ObjectKey(cluster))
if err != nil {
return ctrl.Result{}, err
}
token, err := createToken(ctx, remoteClient, r.TokenTTL)
if err != nil {
return ctrl.Result{}, errors.Wrapf(err, "failed to create new bootstrap token")
}
config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token = token
log.V(3).Info("Altering JoinConfiguration.Discovery.BootstrapToken.Token")
}

Please correct If I missed anything @chrischdi @fabriziopandini

Copy link
Member

Choose a reason for hiding this comment

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

I think we are ok

Discovery has two mutually exclusive options, FileDiscovery and TokenDiscovery.

If File discovery is set, TokenDiscovery must not be set
If File discovery is not set, TokenDiscovery is used, either with the values specified by the users or, if those value are missing, with defaults.

Considering this, there wont be any difference in behaviour between not specifying the object, and specifying empty bootstrapToken: in both cases you accept all the defaults for TokenDiscovery

@fabriziopandini
Copy link
Member

fabriziopandini commented Apr 28, 2025

I'm merging to get this fix in tomorrow's patch release
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Apr 28, 2025
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 1732d327cb8bccf3fed135e106cbf19d668447cf

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: fabriziopandini

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 28, 2025
@mboersma
Copy link
Contributor

/area bootstrap

@k8s-ci-robot k8s-ci-robot added the area/bootstrap Issues or PRs related to bootstrap providers label Apr 28, 2025
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/needs-area PR is missing an area label label Apr 28, 2025
@k8s-ci-robot k8s-ci-robot merged commit 8f348b6 into kubernetes-sigs:main Apr 28, 2025
19 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v1.11 milestone Apr 28, 2025
@fabriziopandini
Copy link
Member

/cherry-pick release-1.10

@k8s-infra-cherrypick-robot

@fabriziopandini: #12107 failed to apply on top of branch "release-1.10":

Applying: Make joinConfiguration.discovery.bootstrapToken.token optional
Using index info to reconstruct a base tree...
A	bootstrap/kubeadm/api/v1beta2/kubeadm_types.go
M	bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
M	bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
M	controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
M	controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
Falling back to patching base and 3-way merge...
Auto-merging internal/apis/bootstrap/kubeadm/v1alpha4/kubeadm_types.go
CONFLICT (content): Merge conflict in internal/apis/bootstrap/kubeadm/v1alpha4/kubeadm_types.go
Auto-merging controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
CONFLICT (content): Merge conflict in controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
Auto-merging controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
CONFLICT (content): Merge conflict in controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
Auto-merging bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
CONFLICT (content): Merge conflict in bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
Auto-merging bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
CONFLICT (content): Merge conflict in bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Patch failed at 0001 Make joinConfiguration.discovery.bootstrapToken.token optional

In response to this:

/cherry-pick release-1.10

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@fabriziopandini
Copy link
Member

@Amulyam24 @Karthik-K-N looks like it is required a manual cherry pick for the 1.10 branch

Amulyam24 pushed a commit to Amulyam24/cluster-api that referenced this pull request Apr 29, 2025
🐛 Make joinConfiguration.discovery.bootstrapToken.token optional
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/bootstrap Issues or PRs related to bootstrap providers cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XS Denotes a PR that changes 0-9 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants