From 622406de2c05247e16bd129c748b37dc00254b69 Mon Sep 17 00:00:00 2001 From: Felix Schuster <1911679+flxflx@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:22:27 +0200 Subject: [PATCH] Add overview of security protocols (#3376) --- dev-docs/chain-of-trust.jpg | Bin 0 -> 48810 bytes dev-docs/security-overview.md | 236 +++++++++++++++++++++++++++++++++ docs/docs/workflows/upgrade.md | 2 +- 3 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 dev-docs/chain-of-trust.jpg create mode 100644 dev-docs/security-overview.md diff --git a/dev-docs/chain-of-trust.jpg b/dev-docs/chain-of-trust.jpg new file mode 100644 index 0000000000000000000000000000000000000000..713e4715eb20fc669f9baf9abc1641c5ea0a0f87 GIT binary patch literal 48810 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 P{db%EAB+L9UxWVxL3iyr literal 0 HcmV?d00001 diff --git a/dev-docs/security-overview.md b/dev-docs/security-overview.md new file mode 100644 index 0000000000..0c6b0e4afb --- /dev/null +++ b/dev-docs/security-overview.md @@ -0,0 +1,236 @@ +# Constellation - Security Protocols Overview + +The security of Constellation is based on a set of protocols. +The protocols are outlined in the following. +The following diagram sketches the basic trust relationships between the entities in a Constellation cluster. +![chain of trust](chain-of-trust.jpg) + +## Software components + +Abstractly, the Constellation software comprises three core components: +1. The command-line interface (CLI) executable, which is run by the cluster administrator on their local machine. +2. The node images, which are run inside Confidential VMs (CVMs). +Among other, each node image contains a Linux kernel and a user mode program called Bootstrapper. +3. The Constellation service containers, which are run on Kubernetes. +There are three core services: KeyService, JoinService, and VerificationService. + +## CLI: root of trust +The CLI executable is signed by Edgeless Systems. +To ensure non-repudiability for CLI releases, Edgeless Systems publishes corresponding signatures to the public ledger of the [Sigstore project](https://www.sigstore.dev/). +There's a [step-by-step guide](https://docs.edgeless.systems/constellation/workflows/verify-cli) on how to verify CLI signatures based on Sigstore. + +The CLI contains the [measurements](https://github.com/edgelesssys/constellation/blob/edc0c7068ef4527efeaf584a2a35e0f51f58c426/internal/attestation/measurements/measurements_enterprise.go#L21) of the latest Constellation node image for all supported cloud platforms. +The CLI writes these measurements as part of the *attestation config* to a cluster's config file with the ["config generate" command](https://docs.edgeless.systems/constellation/workflows/config). +Note that Constellation currently uses 16 TPM-based runtime measurements for each cloud platform. +The purpose and source of the measurements are described in the [next section](#remote-attestation-of-nodes). +In addition to the measurements, the attestation config contains expected patch levels for the CPU microcode and the X.509 certificate of the CPU vendor's remote attestation infrastructure. +An example of an attestation config is given [below](#attestation-config). + +In case a different version of the node image is to be used, the corresponding measurements can be fetched using the CLI's ["config fetch-measurements" command](reference/cli#constellation-config-fetch-measurements). +This command downloads the measurements and the corresponding signature from Edgeless Systems from https://cdn.confidential.cloud. +See for example the following files corresponding to node image v2.16.3: +* [Measurements](https://cdn.confidential.cloud/constellation/v2/ref/-/stream/stable/v2.16.3/image/measurements.json) +* [Signature](https://cdn.confidential.cloud/constellation/v2/ref/-/stream/stable/v2.16.3/image/measurements.json.sig) + +In addition to the attestation config, the CLI contains the following data in hardcoded form: +* The [long-term public key of Edgeless Systems](https://github.com/edgelesssys/constellation/blob/edc0c7068ef4527efeaf584a2a35e0f51f58c426/internal/constants/constants.go#L264) to verify the signature of downloaded measurements. +* The [hashes of the expected Kubernetes binaries](https://github.com/edgelesssys/constellation/blob/edc0c7068ef4527efeaf584a2a35e0f51f58c426/internal/versions/versions.go#L199). +* The [Helm charts used for the installation of services](https://github.com/edgelesssys/constellation/tree/main/internal/constellation/helm/charts), which include hashes of the respective containers. +Note that the Helm charts and the hashes are [generated at build time](https://github.com/edgelesssys/constellation/blob/main/internal/constellation/helm/imageversion/imageversion.go). +A future version of the CLI will provide a command to print the Helm charts. + +## Cluster creation + +When a cluster is [created](https://docs.edgeless.systems/constellation/workflows/create), the CLI interacts with the API of the respective infrastructure provider, for example Azure, and launches CVMs with the applicable node image. +These CVMs are called *nodes*. +On each node, the Bootstrapper is launched. + +The CLI automatically selects one of the nodes as *first node*. +The CLI automatically verifies the first node's remote-attestation statement using the attestation config. +Details on remote attestation are given in the [next section](#remote-attestation-of-nodes). + +Based on the remote-attestation statement, the CLI and the Bootstrapper running on the first node set up a temporary TLS connection between them. +We refer to this type of connection as "attested TLS" (aTLS). +This connection is mainly used for three things (see the the [interface definition](https://github.com/edgelesssys/constellation/blob/main/bootstrapper/initproto/init.proto) for a comprehensive list of exchanged data): +1. The CLI sends the hashes of the expected Kubernetes binaries to the first node. +2. The CLI generates the [master secret](../architecture/keys.md#master-secret) of the to-be-created cluster and sends it to the first node. +3. The first node generates a [kubeconfig file](https://www.redhat.com/sysadmin/kubeconfig) and sends it to the CLI. +The kubeconfig file contains Kubernetes credentials for the CLI and the Kubernetes cluster's public key, among others. + +After this, the aTLS connection is closed and the Bootstrapper marks the node irrevocably as "initialized". +This mechanism prevents a node from accidentally or maliciously joining different clusters. +On all supported CVM platforms this is currently implemented by *extending* TPM register 15 with the unique ID of the cluster (`clusterID`). +More information can be found in the [Constellation documentation](https://docs.edgeless.systems/constellation/architecture/keys#cluster-identity). + +For [launch digest-based attestation](#remote-attestation-of-nodes) on future CVM platforms, an alternative would be to extend `clusterID` to the so called RTMR registers of Intel TDX. +TDX provides four RTMRs, which are automatically included in the `auxiliary data` part of a remote-attestation statement. +For AMD SEV-SNP, a different solution exists. + +## Remote attestation of nodes + +To identify themselves, nodes use the remote-attestation functionality of the underlying CVM platform. +Constellation supports Intel TDX and AMD SEV-SNP based platforms. +Abstractly, Intel TDX and AMD SEV-SNP hash the initial memory contents of the CVMs. +This hash is also called `launch digest`. +The launch digest is reflected in each remote-attestation statement that is requested by the software inside the CVM. +Abstractly, a remote-attestation statement `R` from a CVM looks as follows: + +``` +R = Sig-CPU(, , ) +``` + +The `payload` is controlled by the software running inside the CVM. +In the case of a Constellation node, the `payload` is always the public key of the respective Bootstrapper running inside the CVM. +Thus, `R` can be seen as a certificate for that public key issued by the CPU. +Based on this, nodes establish attested TLS (aTLS) connections. +aTLS is used during [cluster creation](#cluster-creation) and when [growing a cluster](#cluster-growth). + +### Measurements + +In the ideal case, the underlying CVM platform does not inject any of its own software into a CVM. +In that case, a Constellation node image can contain its own firmware/UEFI. +This allows for the creation of node images for which the launch digest covers all defining parts of a node, including the firmware, the kernel, the kernel command line, and the disk image. +In this case, the launch digest is the only measurement that's required to verify the identity and integrity of a node. + +### Measured Boot as fallback + +However, currently, all supported CVM platforms (AWS, Azure, and GCP) inject custom firmware into CVMs. +Thus, in practice, Constellation relies on conventional [measured boot](https://docs.edgeless.systems/constellation/architecture/images#measured-boot) to reflect the identity and integrity of nodes. + +In measured boot, in general, the software components involved in the boot process of a system are "measured" into the 16 registers of a Trusted Platform Module (TPM). +The values of these registers are also called "runtime measurements". +All supported CVM platforms provide TPMs to CVMs. +Constellation nodes use these to measure their boot process. +They include the 16 runtime measurements as `auxiliary data` in `R`. +On each CVM platform, runtime measurements are taken differently. +Details on this are given in the [Constellation documentation](https://docs.edgeless.systems/constellation/architecture/attestation#runtime-measurements). + +With measured boot, Constellation only checks the 16 runtime measurements during the verification of a node's remote-attestation statement. +The launch digest is not considered, because it only covers the firmware injected by the CVM platform and may change whenever the CVM platform is updated. +Currently, on AWS and GCP the TPM implementation resides outside the CVM. +On Azure, the TPM implementation is part of the injected firmware and resides inside the CVM. +More information can be found in the [Constellation documentation](https://docs.edgeless.systems/constellation/overview/clouds). + +## Kubernetes bootstrapping on the first node + +The Bootstrapper on the first node downloads and verifies the Kubernetes binaries, using the hashes it received from the CLI. +These binaries include for example [kubelet](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/), [kube-apiserver](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/), and [etcd](https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/). +With these, the Bootstrapper creates a single-node Kubernetes cluster. +Etcd is a distributed key-value store that Kubernetes uses to store configuration data for services. +The etcd agent runs on each control-plane node of a cluster. +The agents use mTLS for communication between them. +Etcd uses the Raft protocol (over mTLS) to distribute state between nodes. +All essential configuration data of a cluster is kept in etcd. + +Initially, the Bootstrapper on the first node [writes](https://github.com/edgelesssys/constellation/blob/d65987cb15cf9ebdbbd2975f177937c1acbc90f8/bootstrapper/internal/kubernetes/kubernetes.go#L173) the hashes of the expected Kubernetes binaries to a specific key in etcd. + +Next, the CLI the connects to the Kubernetes API server (kube-apiserver) using the kubeconfig file it received from the Bootstrapper. +This results in an mTLS connection between the CLI and the Kubernetes API server. +The CLI uses this connection for two essential operations at the Kubernetes level: + +1. It writes the attestation config to a specific key in etcd. +1. It executes the [hardcoded Helm charts](#cli-root-of-trust), which, most notably, install the three core services KeyService, JoinService, and VerificationService, the [constellation-node-operator](https://github.com/edgelesssys/constellation/tree/main/operators/constellation-node-operator), and a small number of standard services like Cilium and cert-manager. + +The latter causes the first node to download, verify, and run the containers defined in the Helm charts. +The containers that are specific to Constellation are hosted at https://ghcr.io/edgelesssys. + +After this, the Constellation cluster is operational on the first node. + +## Cluster growth + +Additional nodes can now join the cluster - either as control-plane nodes or as worker nodes. +For both, the process for joining the cluster is identical. +First, the Bootstrapper running on a *new node* contacts the JoinService of the existing cluster. +The JoinService verifies the remote-attestation statement of the new node using the attestation config stored in etcd. +On success, an aTLS connection between the two is created, which is used mainly for the following (see the the [interface definition](https://github.com/edgelesssys/constellation/blob/main/joinservice/joinproto/join.proto) for a comprehensive list of exchanged data): + +1. The new node sends a certificate signing request (CSR) for its *node certificate* to the JoinService. +1. The JoinService issues a corresponding certificate with a lifetime of one year and sends it to the new node. +The JoinService uses the signing key of the Kubernetes cluster for this, which is [generated by kubeadm](https://kubernetes.io/docs/setup/best-practices/certificates/). Note that the lifetime of the node certificate is a best practice only, as Constellation relies on the untrusted infrastructure to provide time when validating certificates. +1. The JoinService sends a [kubeadm token](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-token/) to the new node. +1. The JoinService sends the hashes of the expected Kubernetes binaries to the new node. +1. The JoinService sends encryption key for the new node's local storage. +This key is generated and managed by the cluster's KeyService. +1. The JoinService sends the certificate of the cluster's control plane to the new node. + +After this, the aTLS connection is closed and the node is marked as "initialized" in the same way as described [above](#cluster-creation). + +The Bootstrapper downloads, verifies, and runs the given Kubernetes binaries. +Further, the Bootstrapper uses the kubeadm token to download the configuration of the cluster from the Kubernetes API server. +The kubeadm token is never used after this. + +The kubelet on the new node uses its own node certificate and the certificate of the cluster's control plane (which the new node both received from the JoinService) to establish an mTLS connection with the cluster's Kubernetes API server. +Once connected, the new node registers itself as control-plane node or worker node of the cluster. +This process uses the standard Kubernetes mechanisms for adding nodes. + +In Constellation, a virtual private network (VPN) exists between all nodes of a cluster. +This VPN is created with the help of Cilium. +To join this VPN, the new node generates WireGuard credentials for itself and writes the public key to etcd via the mTLS connection with the Kubernetes API server. +It also downloads the public keys of existing nodes from etcd. +Subsequently, the Cilium agents running on other nodes fetch the new node's public key from etcd as well. + +Note that etcd communication between nodes is an exception: This traffic always goes via mTLS based on node certificates. + +## Cluster upgrade + +Whenever a cluster is [upgraded](https://docs.edgeless.systems/constellation/workflows/upgrade), the CLI connects to the Kubernetes API server and, essentially, updates the following data in etcd: + +1. The attestation config +1. The hashes of the expected Kubernetes binaries + +Further, the CLI applies updated Helm charts to update the cluster's services. +Again, these Helm charts are hardcoded in the CLI. +See the [implementation](https://github.com/edgelesssys/constellation/blob/d65987cb15cf9ebdbbd2975f177937c1acbc90f8/cli/internal/cmd/apply.go#L358) of the `apply()` function for a sequence diagram of all steps. +Subsequently, the constellation-node-operator replaces existing nodes with new ones. +New nodes go through the [usual process for joining the cluster](#cluster-growth). + +## Examples + +This section gives real life examples of key data structures and the corresponding commands to retrieve those. + +### Attestation config + +```bash +kubectl -n kube-system get cm join-config -o json +``` +```json +{ + "apiVersion": "v1", + "binaryData": { + "measurementSalt": "2A4Fzfdr/61XbJvk1PDqzh0R4rVnEujyXudsfgRZzUY=" + }, + "data": { + "attestationConfig": "{\"measurements\":{\"1\":{\"expected\":\"3695dcc55e3aa34027c27793c85c723c697d708c42d1f73bd6fa4f26608a5b24\",\"warnOnly\":true},\"11\":{\"expected\":\"f09cef0d077127fb26bc8d013fc09e13afbb70f0f734ced98f46666544998efe\",\"warnOnly\":true},\"12\":{\"expected\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"warnOnly\":true},\"13\":{\"expected\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"warnOnly\":true},\"14\":{\"expected\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"warnOnly\":true},\"15\":{\"expected\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"warnOnly\":true},\"2\":{\"expected\":\"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969\",\"warnOnly\":true},\"3\":{\"expected\":\"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969\",\"warnOnly\":true},\"4\":{\"expected\":\"e5020193148fbad0dbaf618fb3ef15665c72ff87a54e24b2d8f5bdf9719bb50b\",\"warnOnly\":true},\"6\":{\"expected\":\"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969\",\"warnOnly\":true},\"8\":{\"expected\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"warnOnly\":true},\"9\":{\"expected\":\"37ef16fd0ae8d2fb3b1914f0b8ff046e765b57fec6739d2ebf1fd4d182071437\",\"warnOnly\":true}},\"bootloaderVersion\":\"latest\",\"teeVersion\":\"latest\",\"snpVersion\":\"latest\",\"microcodeVersion\":\"latest\",\"amdRootKey\":\"-----BEGIN CERTIFICATE-----\\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\\nAFZEAwoKCQ==\\n-----END CERTIFICATE-----\\n\",\"amdSigningKey\":\"\"}" + }, + "kind": "ConfigMap", + "metadata": { + "creationTimestamp": "2024-09-25T11:11:50Z", + "name": "join-config", + "namespace": "kube-system", + "resourceVersion": "387", + "uid": "fdd0d5eb-cf58-4608-99c9-eede08895615" + } +} +``` +### Hashes of Kubernetes binaries +```bash +kubectl -n kube-system get cm k8s-components-sha256-7b73c7675df78e5753b6e0fc86a9982127fd16141837599d5ce16df6bfe6a2a0 -o json +``` +```json +{ + "apiVersion": "v1", + "data": { + "cluster-version": "v1.29.8", + "components": "[{\"url\":\"https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz\",\"hash\":\"sha256:c2485ddb3ffc176578ae30ae58137f0b88e50f7c7f2af7d53a569276b2949a33\",\"install_path\":\"/opt/cni/bin\",\"extract\":true},{\"url\":\"https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.29.0/crictl-v1.29.0-linux-amd64.tar.gz\",\"hash\":\"sha256:d16a1ffb3938f5a19d5c8f45d363bd091ef89c0bc4d44ad16b933eede32fdcbb\",\"install_path\":\"/run/state/bin\",\"extract\":true},{\"url\":\"https://storage.googleapis.com/kubernetes-release/release/v1.29.8/bin/linux/amd64/kubelet\",\"hash\":\"sha256:df6e130928403af8b4f49f1197e26f2873a147cd0e23aa6597a26c982c652ae0\",\"install_path\":\"/run/state/bin/kubelet\"},{\"url\":\"https://storage.googleapis.com/kubernetes-release/release/v1.29.8/bin/linux/amd64/kubeadm\",\"hash\":\"sha256:fe054355e0ae8dc35d868a3d3bc408ccdff0969c20bf7a231ae9b71484e41be3\",\"install_path\":\"/run/state/bin/kubeadm\"},{\"url\":\"https://storage.googleapis.com/kubernetes-release/release/v1.29.8/bin/linux/amd64/kubectl\",\"hash\":\"sha256:038454e0d79748aab41668f44ca6e4ac8affd1895a94f592b9739a0ae2a5f06a\",\"install_path\":\"/run/state/bin/kubectl\"},{\"url\":\"data:application/json;base64,W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL2NvbnRhaW5lcnMvMC9pbWFnZSIsInZhbHVlIjoicmVnaXN0cnkuazhzLmlvL2t1YmUtYXBpc2VydmVyOnYxLjI5LjhAc2hhMjU2OjZmNzJmYTkyNmM5YjA1ZTEwNjI5ZmUxYTA5MmZkMjhkY2Q2NWI0ZmRmZDBjYzdiZDU1Zjg1YTU3YTZiYTFmYTUifV0=\",\"install_path\":\"/opt/kubernetes/patches/kube-apiserver+json.json\"},{\"url\":\"data:application/json;base64,W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL2NvbnRhaW5lcnMvMC9pbWFnZSIsInZhbHVlIjoicmVnaXN0cnkuazhzLmlvL2t1YmUtY29udHJvbGxlci1tYW5hZ2VyOnYxLjI5LjhAc2hhMjU2OjZmMjdkNjNkZWQyMDYxNGM2ODU1NGI0NzdjZDdhNzhlZGE3OGE0OThhOTJiZmU4OTM1Y2Y5NjRjYTViNzRkMGIifV0=\",\"install_path\":\"/opt/kubernetes/patches/kube-controller-manager+json.json\"},{\"url\":\"data:application/json;base64,W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL2NvbnRhaW5lcnMvMC9pbWFnZSIsInZhbHVlIjoicmVnaXN0cnkuazhzLmlvL2t1YmUtc2NoZWR1bGVyOnYxLjI5LjhAc2hhMjU2OmRhNzRhNjY2NzVkOTVlMzllYzI1ZGE1ZTcwNzI5ZGE3NDZkMGZhMGIxNWVlMGRhODcyYWM5ODA1MTliYzI4YmQifV0=\",\"install_path\":\"/opt/kubernetes/patches/kube-scheduler+json.json\"},{\"url\":\"data:application/json;base64,W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL2NvbnRhaW5lcnMvMC9pbWFnZSIsInZhbHVlIjoicmVnaXN0cnkuazhzLmlvL2V0Y2Q6My41LjEyLTBAc2hhMjU2OjQ0YThlMjRkY2JiYTM0NzBlZTFmZWUyMWQ1ZTg4ZDEyOGM5MzZlOWI1NWQ0YmM1MWZiZWY4MDg2ZjhlZDEyM2IifV0=\",\"install_path\":\"/opt/kubernetes/patches/etcd+json.json\"}]" + }, + "immutable": true, + "kind": "ConfigMap", + "metadata": { + "creationTimestamp": "2024-09-25T11:11:50Z", + "name": "k8s-components-sha256-7b73c7675df78e5753b6e0fc86a9982127fd16141837599d5ce16df6bfe6a2a0", + "namespace": "kube-system", + "resourceVersion": "356", + "uid": "6389c186-3bc8-4470-8af5-f6fed1addd69" + } +} +``` \ No newline at end of file diff --git a/docs/docs/workflows/upgrade.md b/docs/docs/workflows/upgrade.md index 7348c0dbc2..3db2ecad6b 100644 --- a/docs/docs/workflows/upgrade.md +++ b/docs/docs/workflows/upgrade.md @@ -1,6 +1,6 @@ # Upgrade your cluster -Constellation provides an easy way to upgrade all components of your cluster, without disrupting it's availability. +Constellation provides an easy way to upgrade all components of your cluster, without disrupting its availability. Specifically, you can upgrade the Kubernetes version, the nodes' image, and the Constellation microservices. You configure the desired versions in your local Constellation configuration and trigger upgrades with the `apply` command. To learn about available versions you use the `upgrade check` command.