{"id":51495762,"url":"https://github.com/martishin/cluster-api-external-ca","last_synced_at":"2026-07-07T15:01:36.969Z","repository":{"id":338712949,"uuid":"1158384609","full_name":"martishin/cluster-api-external-ca","owner":"martishin","description":"Validating a Cluster API patch that enables kubeadm external CA mode with pre-generated bootstrap PKI, step-ca signing, and certificate lineage validation.","archived":false,"fork":false,"pushed_at":"2026-02-22T10:37:22.000Z","size":140,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-21T07:34:14.319Z","etag":null,"topics":["cluster-api","k8s"],"latest_commit_sha":null,"homepage":"https://www.martishin.com/posts/project-cluster-api-external-ca","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martishin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-15T09:25:38.000Z","updated_at":"2026-05-26T12:44:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/martishin/cluster-api-external-ca","commit_stats":null,"previous_names":["martishin/cluster-api-external-ca"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/martishin/cluster-api-external-ca","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martishin%2Fcluster-api-external-ca","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martishin%2Fcluster-api-external-ca/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martishin%2Fcluster-api-external-ca/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martishin%2Fcluster-api-external-ca/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martishin","download_url":"https://codeload.github.com/martishin/cluster-api-external-ca/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martishin%2Fcluster-api-external-ca/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35232326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cluster-api","k8s"],"created_at":"2026-07-07T15:01:35.666Z","updated_at":"2026-07-07T15:01:36.855Z","avatar_url":"https://github.com/martishin.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cluster API External CA PoC\n\nThis repository tests a patch for Cluster API `v1.8.8` that enables external CA:\n\n1. `self-signed` (upstream CAPI, no patch),\n2. `external-ca` (patched CAPI + pre-generated external bootstrap PKI).\n\n## Run Locally\n\n```bash\nmake test-self-signed-ca\nmake test-external-ca\n```\n\nTests run `clean -\u003e setup -\u003e validate`. To clean clusters and generated artifacts after a test run, execute:\n\n```bash\nmake clean\n```\n\nOr run setup/validate separately:\n\n```bash\nmake setup-self-signed-ca\nmake validate-self-signed-ca\n\nmake setup-external-ca\nmake validate-external-ca\n```\n\n## Debug Commands\n\nManagement cluster (kind + CAPI controllers):\n\n```bash\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig get pods -A | grep -E 'capi-|capd-|cert-manager|step-ca' || true\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig -n default get cluster\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig -n default get kcp\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig -n default get md\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig -n default get machine\nkubectl --kubeconfig out/mgmt/mgmt.kubeconfig -n default describe kcp\n```\n\nWorkload cluster:\n\n```bash\nkubectl --kubeconfig out/workload/kubeconfig get nodes -o wide\nkubectl --kubeconfig out/workload/kubeconfig get pods -A\nkubectl --kubeconfig out/workload/kubeconfig get csr\n```\n\nNode-level certificate spot checks:\n\n```bash\n# pick any control-plane node from the workload cluster\nCP_NODE=\"$(kubectl --kubeconfig \"$WORKLOAD_KUBECONFIG\" get nodes -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')\"\n\n# check if CA key exists on that node\nkubectl --kubeconfig \"$WORKLOAD_KUBECONFIG\" debug \"node/$CP_NODE\" --image=busybox:1.36 --quiet -- \\\n  chroot /host ls -l /etc/kubernetes/pki/ca.key\n\n# inspect apiserver cert issuer/subject on that node\nkubectl --kubeconfig \"$WORKLOAD_KUBECONFIG\" debug \"node/$CP_NODE\" --image=busybox:1.36 --quiet -- \\\n  chroot /host openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -issuer -subject\n```\n\n## Execution Flow\n\n1. Deploy kind management cluster with `1` control-plane + `1` worker node.\n2. Build CAPI artifacts for pinned version (`v1.8.8`).\n3. Install CAPI into management cluster.\n4. Deploy bootstrap step-ca into management cluster.\n5. Provision workload cluster in external-ca mode with initial `1` control-plane node (bootstrap PKI signed by management step-ca).\n6. Scale workload workers to `3` (still using bootstrap-signed PKI).\n7. Deploy workload step-ca to workload cluster.\n8. Reroll control-plane to `3` replicas so new control-plane leaf certs are signed through workload signer flow.\n9. Reroll workers so worker kubelet client certs are signed through workload signer flow.\n10. Validate control-plane and worker certificate lineage/subjects/uniqueness.\n\n## Validation Summary\n\n- `self-signed`: expects CA key behavior from upstream kubeadm/CAPI.\n- `external-ca`: expects no CA private key in `\u003ccluster\u003e-ca`, no `/etc/kubernetes/pki/ca.key` on control-plane nodes, expected CA lineage, unique control-plane leaf key hashes after reroll, and worker kubelet client certs signed by the\n  external CA with `CN=system:node:\u003cnode\u003e` and `O=system:nodes`.\n\n## References\n\n- Cluster API repo: https://github.com/kubernetes-sigs/cluster-api/\n- Cluster API book: https://cluster-api.sigs.k8s.io/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartishin%2Fcluster-api-external-ca","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartishin%2Fcluster-api-external-ca","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartishin%2Fcluster-api-external-ca/lists"}