-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Approve Worker Nodes CSRs (#713)
This commit adds an endpoint to approve CSRs from worker nodes via the CAPI provider
- Loading branch information
1 parent
82985e3
commit db9fdd6
Showing
5 changed files
with
152 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package api | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
|
||
apiv1 "github.com/canonical/k8s-snap-api/api/v1" | ||
"github.com/canonical/k8s/pkg/utils" | ||
"github.com/canonical/lxd/lxd/response" | ||
"github.com/canonical/microcluster/v3/state" | ||
"golang.org/x/sync/errgroup" | ||
certv1 "k8s.io/api/certificates/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
// postApproveWorkerCSR approves the worker node CSR for the specified seed. | ||
// The certificate approval process follows these steps: | ||
// 1. The CAPI provider calls the /x/capi/refresh-certs/plan endpoint from a | ||
// worker node, which generates a CSR and creates a CertificateSigningRequest | ||
// object in the cluster. | ||
// 2. The CAPI provider then calls the /k8sd/refresh-certs/run endpoint with | ||
// the seed. This endpoint waits until the CSR is approved and the certificate | ||
// is signed. Note that this is a blocking call. | ||
// 3. The CAPI provider calls the /x/capi/refresh-certs/approve endpoint from | ||
// any control plane node to approve the CSR. | ||
// 4. The /x/capi/refresh-certs/run endpoint completes and returns once the | ||
// certificate is approved and signed. | ||
func (e *Endpoints) postApproveWorkerCSR(s state.State, r *http.Request) response.Response { | ||
snap := e.provider.Snap() | ||
|
||
req := apiv1.ClusterAPIApproveWorkerCSRRequest{} | ||
|
||
if err := utils.NewStrictJSONDecoder(r.Body).Decode(&req); err != nil { | ||
return response.BadRequest(fmt.Errorf("failed to parse request: %w", err)) | ||
} | ||
|
||
if err := r.Body.Close(); err != nil { | ||
return response.InternalError(fmt.Errorf("failed to close request body: %w", err)) | ||
} | ||
|
||
client, err := snap.KubernetesClient("") | ||
if err != nil { | ||
return response.InternalError(fmt.Errorf("failed to get Kubernetes client: %w", err)) | ||
} | ||
|
||
g, ctx := errgroup.WithContext(r.Context()) | ||
|
||
// CSR names | ||
csrNames := []string{ | ||
fmt.Sprintf("k8sd-%d-worker-kubelet-serving", req.Seed), | ||
fmt.Sprintf("k8sd-%d-worker-kubelet-client", req.Seed), | ||
fmt.Sprintf("k8sd-%d-worker-kube-proxy-client", req.Seed), | ||
} | ||
|
||
for _, csrName := range csrNames { | ||
g.Go(func() error { | ||
if err := client.WatchCertificateSigningRequest( | ||
ctx, | ||
csrName, | ||
func(request *certv1.CertificateSigningRequest) (bool, error) { | ||
request.Status.Conditions = append(request.Status.Conditions, certv1.CertificateSigningRequestCondition{ | ||
Type: certv1.CertificateApproved, | ||
Status: corev1.ConditionTrue, | ||
Reason: "ApprovedByCK8sCAPI", | ||
Message: "This CSR was approved by the Canonical Kubernetes CAPI Provider", | ||
LastUpdateTime: metav1.Now(), | ||
}) | ||
_, err := client.CertificatesV1().CertificateSigningRequests().UpdateApproval(ctx, csrName, request, metav1.UpdateOptions{}) | ||
if err != nil { | ||
return false, fmt.Errorf("failed to update CSR %s: %w", csrName, err) | ||
} | ||
return true, nil | ||
}, | ||
); err != nil { | ||
return fmt.Errorf("certificate signing request failed: %w", err) | ||
} | ||
return nil | ||
}) | ||
} | ||
|
||
if err := g.Wait(); err != nil { | ||
return response.InternalError(fmt.Errorf("failed to approve worker node CSR: %w", err)) | ||
} | ||
|
||
return response.SyncResponse(true, apiv1.ClusterAPIApproveWorkerCSRResponse{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters