diff --git a/docs/install/2_prereq.md b/docs/install/2_prereq.md index a92e109..eb442d3 100644 --- a/docs/install/2_prereq.md +++ b/docs/install/2_prereq.md @@ -42,14 +42,31 @@ kind create cluster --name sdc /// tab | other /// -## Install Cert-Manager -The config-server (extension api-server) requires a certificate, which is created via cert-manager. The corresponding CA cert needs to be injected into the cabundle spec field of the `api-service` resource. +## Install cert-manager + +SDC depends on [cert-manager](https://cert-manager.io) to issue the TLS +certificate served by the config-server's aggregated API server and to keep +the `APIService` `caBundle` in sync with the SDC root CA via `cainjector`. +cert-manager **must be installed and ready before** the SDC manifests are +applied. See [Cert-Manager & TLS Trust Chain](4_cert-manager.md) for how the +chain is built and rotated. + +Install cert-manager (tested with `v1.20.2`): ```bash kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.20.2/cert-manager.yaml -# If the SDC resources, see below are being applied to fast, the webhook of the cert-manager is not already there. -# Hence we need to wait for the resource be become Available -kubectl wait -n cert-manager --for=condition=Available=True --timeout=300s deployments.apps cert-manager-webhook +``` + +Wait for all three cert-manager components to be Available — the controller +issues certificates, the `cainjector` populates the `APIService` `caBundle`, +and the webhook validates cert-manager CRs. SDC needs all three before its +resources are applied: + +```bash +kubectl wait -n cert-manager --for=condition=Available=True --timeout=300s \ + deployment/cert-manager \ + deployment/cert-manager-cainjector \ + deployment/cert-manager-webhook ``` [kind-install]: https://kind.sigs.k8s.io/docs/user/quick-start/#installation diff --git a/docs/install/4_cert-manager.md b/docs/install/4_cert-manager.md new file mode 100644 index 0000000..925bbfe --- /dev/null +++ b/docs/install/4_cert-manager.md @@ -0,0 +1,115 @@ +# Cert-Manager & TLS Trust Chain + +The SDC `api-server` registers itself with Kubernetes as an +[aggregated API server][agg-api] to store the `config` and `configset` +resources outside of etcd. kube-apiserver only proxies requests to it when +it can validate the served TLS certificate against a CA that the +`APIService` object trusts. + +SDC builds that trust chain with [cert-manager][cm-home], following the +[self-signed bootstrapping pattern][cm-bootstrap]. + +!!! note + Make sure cert-manager is installed and Ready first — see + [Pre-Requisites › Install cert-manager](2_prereq.md#install-cert-manager). + +## Chain overview + +```mermaid +flowchart LR + A[ClusterIssuer
selfsigned-cluster-issuer] + B[Certificate
sdc-ca
isCA: true] + S1[(Secret
sdc-ca-secret)] + C[Issuer
sdc-ca-issuer] + D[Certificate
api-server-cert] + S2[(Secret
api-server-cert)] + P[api-server
Deployment] + AS[APIService
v1alpha1.config.sdcio.dev] + KA[kube-apiserver] + + A -- signs --> B + B -- stored in --> S1 + S1 -- consumed by --> C + C -- signs --> D + D -- stored in --> S2 + S2 -- mounted by --> P + B -. cainjector populates caBundle .-> AS + KA -- validates against caBundle --> P +``` + +| Resource | Role in SDC | +| --- | --- | +| `selfsigned-cluster-issuer` | Bootstraps the chain so the SDC root CA can sign itself. | +| `sdc-ca` | The SDC root CA. Its key/cert pair is written to the `sdc-ca-secret` Secret and is the trust anchor for every SDC certificate. | +| `sdc-ca-issuer` | Namespaced issuer in `sdc-system` that uses `sdc-ca-secret` to sign SDC workload certificates. | +| `api-server-cert` | Serving cert for the SDC api-server. Its Secret is mounted by the api-server Deployment at `/apiserver.local.config/certificates`. | + +## APIService CA injection + +For kube-apiserver to accept the api-server's TLS cert, the `APIService`'s +`spec.caBundle` must contain a CA that signed it. SDC sets the `caBundle` +declaratively by annotating the `APIService`: + +```yaml +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1alpha1.config.sdcio.dev + annotations: + cert-manager.io/inject-ca-from: sdc-system/sdc-ca +spec: + group: config.sdcio.dev + service: + name: api-server + namespace: sdc-system + port: 6443 + version: v1alpha1 + versionPriority: 15 + groupPriorityMinimum: 1000 +``` + +The annotation references the **CA `Certificate`** (`sdc-system/sdc-ca`), +not the leaf. cert-manager's `cainjector` reads the `ca.crt` from +`sdc-ca-secret` and writes it into `spec.caBundle`, refreshing it whenever +the CA rotates. + +## Renewal + +cert-manager renews each `Certificate` on its own schedule based on its +`duration` / `renewBefore`. + +- **`api-server-cert`** — re-issued in place into the `api-server-cert` + Secret. The kubelet refreshes the Secret-backed volume mount and the + api-server hot-reloads the new key/cert from disk; no pod restart is + needed. + +- **`sdc-ca`** — re-issued into `sdc-ca-secret` and `cainjector` writes the + new CA into the `APIService.caBundle`. cert-manager does **not** cascade + the CA renewal to leaves, so any cert signed by the previous CA stops + validating against the new bundle and must be rotated — either by waiting + for its own `renewBefore` window or by forcing a renewal, e.g.: + + ```bash + cmctl renew -n sdc-system api-server-cert + ``` + + Plan CA renewals accordingly: the `sdc-ca` `Certificate` ships with a + long `duration` (10 years) so this doesn't happen often. + +## Verifying the chain + +After installing SDC, all of the following should be `Ready` / `True`: + +```bash +kubectl get clusterissuer selfsigned-cluster-issuer +kubectl -n sdc-system get issuer sdc-ca-issuer +kubectl -n sdc-system get certificate sdc-ca api-server-cert +kubectl get apiservice v1alpha1.config.sdcio.dev +``` + +The `APIService` should show `Available=True` once `cainjector` has +populated `spec.caBundle` and the api-server pod is serving on `:6443`. + +[agg-api]: https://kubernetes.io/docs/tasks/extend-kubernetes/configure-aggregation-layer/ +[cm-home]: https://cert-manager.io +[cm-bootstrap]: https://cert-manager.io/docs/configuration/selfsigned/#bootstrapping-ca-issuers diff --git a/mkdocs.yml b/mkdocs.yml index 6b1860b..300295b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ nav: - Overview: install/1_overview.md - Pre-Requisites: install/2_prereq.md - Installation: install/3_k8s_installation.md + - Cert-Manager & Trust Chain: install/4_cert-manager.md - User Guide: - Introduction: user-guide/introduction.md - Configuration: