From a88a731576184e3c5ee8527741c4a0cdaa4e9b24 Mon Sep 17 00:00:00 2001 From: Adrian Stobbe Date: Thu, 16 Nov 2023 17:03:24 +0100 Subject: [PATCH] docs: add Terraform module (#2560) Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com --- docs/docs/workflows/create.md | 218 ++---------------------- docs/docs/workflows/terraform-module.md | 151 ++++++++++++++++ docs/sidebars.js | 5 + 3 files changed, 166 insertions(+), 208 deletions(-) create mode 100644 docs/docs/workflows/terraform-module.md diff --git a/docs/docs/workflows/create.md b/docs/docs/workflows/create.md index da8068b9e..605413cac 100644 --- a/docs/docs/workflows/create.md +++ b/docs/docs/workflows/create.md @@ -35,218 +35,20 @@ constellation create *create* stores your cluster's state in a [`constellation-terraform`](../architecture/orchestration.md#cluster-creation-process) directory in your workspace. - - - -Terraform allows for an easier GitOps integration as well as meeting regulatory requirements. -Since the Constellation CLI also uses Terraform under the hood, you can reuse the same Terraform files. - -:::info -Familiarize with the [Terraform usage policy](../reference/terraform.md) before manually interacting with Terraform to create a cluster. -Please also refrain from changing the Terraform resource definitions, as Constellation is tightly coupled to them. -::: - -Download the Terraform files for the selected CSP from the [GitHub repository](https://github.com/edgelesssys/constellation/tree/main/terraform/infrastructure). - -Find the image reference for your CSP and region, execute: - -```bash -CONSTELL_VER=vX.Y.Z -curl -s https://cdn.confidential.cloud/constellation/v2/ref/-/stream/stable/$CONSTELL_VER/image/info.json | jq -``` - -From the list, select the `reference` for your CSP / Attestation combination and save it in the `IMAGE_REF` environment variable. - -Create a `terraform.tfvars` file. -There, define all needed variables found in `variables.tf` using the values from the `constellation-config.yaml`. - - - - -```bash -echo "name = \"$(yq '.name' constellation-conf.yaml)\"" >> terraform.tfvars -echo "debug = $(yq '.debugCluster' constellation-conf.yaml)" >> terraform.tfvars -echo "custom_endpoint = \"$(yq '.customEndpoint' constellation-conf.yaml)\"" >> terraform.tfvars -echo "node_groups = { - control_plane_default = { - role = \"$(yq '.nodeGroups.control_plane_default.role' constellation-conf.yaml)\" - zone = \"$(yq '.nodeGroups.control_plane_default.zone' constellation-conf.yaml)\" - instance_type = \"$(yq '.nodeGroups.control_plane_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.control_plane_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.control_plane_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.control_plane_default.initialCount' constellation-conf.yaml)\" - } - worker_default = { - role = \"$(yq '.nodeGroups.worker_default.role' constellation-conf.yaml)\" - zone = \"$(yq '.nodeGroups.worker_default.zone' constellation-conf.yaml)\" - instance_type = \"$(yq '.nodeGroups.worker_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.worker_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.worker_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.worker_default.initialCount' constellation-conf.yaml)\" - } -}" >> terraform.tfvars -echo "iam_instance_profile_control_plane = \"$(yq '.provider.aws.iamProfileControlPlane' constellation-conf.yaml)\"" >> terraform.tfvars -echo "iam_instance_profile_worker_nodes = \"$(yq '.provider.aws.iamProfileWorkerNodes' constellation-conf.yaml)\"" >> terraform.tfvars -echo "region = \"$(yq '.provider.aws.region' constellation-conf.yaml)\"" >> terraform.tfvars -echo "zone = \"$(yq '.provider.aws.zone' constellation-conf.yaml)\"" >> terraform.tfvars -echo "ami = \"$(yq '.provider.aws.zone' constellation-conf.yaml)\"" >> terraform.tfvars -echo "enable_snp = $(yq '.attestation | has("awsSEVSNP")' constellation-conf.yaml)" >> terraform.tfvars -terraform fmt terraform.tfvars -``` - - - - -```bash -echo "name = \"$(yq '.name' constellation-conf.yaml)\"" >> terraform.tfvars -echo "debug = $(yq '.debugCluster' constellation-conf.yaml)" >> terraform.tfvars -echo "custom_endpoint = \"$(yq '.customEndpoint' constellation-conf.yaml)\"" >> terraform.tfvars -echo "image_id = \"$IMAGE_REF\"" >> terraform.tfvars -echo "node_groups = { - control_plane_default = { - role = \"$(yq '.nodeGroups.control_plane_default.role' constellation-conf.yaml)\" - zones = [ \"$(yq '.nodeGroups.worker_default.zone' constellation-conf.yaml)\" ] - instance_type = \"$(yq '.nodeGroups.control_plane_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.control_plane_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.control_plane_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.control_plane_default.initialCount' constellation-conf.yaml)\" - } - worker_default = { - role = \"$(yq '.nodeGroups.worker_default.role' constellation-conf.yaml)\" - zones = [ \"$(yq '.nodeGroups.worker_default.zone' constellation-conf.yaml)\" ] - instance_type = \"$(yq '.nodeGroups.worker_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.worker_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.worker_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.worker_default.initialCount' constellation-conf.yaml)\" - } -}" >> terraform.tfvars -echo "location = \"$(yq '.provider.azure.location' constellation-conf.yaml)\"" >> terraform.tfvars -echo "create_maa = $(yq '.attestation | has("azureSEVSNP")' constellation-conf.yaml)" >> terraform.tfvars -echo "confidential_vm = $(yq '.attestation | has("azureSEVSNP")' constellation-conf.yaml)" >> terraform.tfvars -echo "secure_boot = $(yq '.provider.azure.secureBoot' constellation-conf.yaml)" >> terraform.tfvars -echo "resource_group = \"$(yq '.provider.azure.resourceGroup' constellation-conf.yaml)\"" >> terraform.tfvars -echo "user_assigned_identity = \"$(yq '.provider.azure.userAssignedIdentity' constellation-conf.yaml)\"" >> terraform.tfvars -terraform fmt terraform.tfvars -``` - - - - -```bash -echo "name = \"$(yq '.name' constellation-conf.yaml)\"" >> terraform.tfvars -echo "debug = $(yq '.debugCluster' constellation-conf.yaml)" >> terraform.tfvars -echo "custom_endpoint = \"$(yq '.customEndpoint' constellation-conf.yaml)\"" >> terraform.tfvars -echo "image_id = \"$IMAGE_REF\"" >> terraform.tfvars -echo "node_groups = { - control_plane_default = { - role = \"$(yq '.nodeGroups.control_plane_default.role' constellation-conf.yaml)\" - zone = \"$(yq '.nodeGroups.control_plane_default.zone' constellation-conf.yaml)\" - instance_type = \"$(yq '.nodeGroups.control_plane_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.control_plane_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.control_plane_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.control_plane_default.initialCount' constellation-conf.yaml)\" - } - worker_default = { - role = \"$(yq '.nodeGroups.worker_default.role' constellation-conf.yaml)\" - zone = \"$(yq '.nodeGroups.worker_default.zone' constellation-conf.yaml)\" - instance_type = \"$(yq '.nodeGroups.worker_default.instanceType' constellation-conf.yaml)\" - disk_size = \"$(yq '.nodeGroups.worker_default.stateDiskSizeGB' constellation-conf.yaml)\" - disk_type = \"$(yq '.nodeGroups.worker_default.stateDiskType' constellation-conf.yaml)\" - initial_count = \"$(yq '.nodeGroups.worker_default.initialCount' constellation-conf.yaml)\" - } -}" >> terraform.tfvars -echo "project = \"$(yq '.provider.gcp.project' constellation-conf.yaml)\"" >> terraform.tfvars -echo "region = \"$(yq '.provider.gcp.region' constellation-conf.yaml)\"" >> terraform.tfvars -echo "zone = \"$(yq '.provider.gcp.zone' constellation-conf.yaml)\"" >> terraform.tfvars -terraform fmt terraform.tfvars -``` - - - - -Initialize and apply Terraform to create the configured infrastructure: - -```bash -terraform init -terraform apply -``` - -The Constellation [apply step](#the-apply-step) requires the already created `constellation-config.yaml` and the `constellation-state.yaml`. -Create the `constellation-state.yaml` using the output from the Terraform state and the `constellation-conf.yaml`: - - - - -```bash -yq eval '.version ="v1"' --inplace constellation-state.yaml -yq eval ".infrastructure.initSecret =\"$(terraform output initSecret | jq -r | tr -d '\n' | hexdump -ve '/1 "%02x"' && echo '')\"" --inplace constellation-state.yaml -yq eval ".infrastructure.clusterEndpoint =\"$(terraform output out_of_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.inClusterEndpoint =\"$(terraform output in_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.ipCidrNode =\"$(terraform output ip_cidr_nodes | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.uid =\"$(terraform output uid | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.name =\"$(terraform output name | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.apiServerCertSANs =$(terraform output -json api_server_cert_sans)" --inplace constellation-state.yaml -``` - - - - -:::info - - If the enforcement policy is set to `MAAFallback` in `constellation-config.yaml`, a manual update to the MAA provider's policy is necessary. - You can apply the update with the following commands, where `` is the version of Constellation that should be set up. (e.g. `v2.12.0`) - - ```bash - git clone --branch https://github.com/edgelesssys/constellation - cd constellation/hack/maa-patch - go run . $(terraform output attestationURL | jq -r) - ``` - -::: - -```bash -yq eval '.version ="v1"' --inplace constellation-state.yaml -yq eval ".infrastructure.initSecret =\"$(terraform output initSecret | jq -r | tr -d '\n' | hexdump -ve '/1 "%02x"' && echo '')\"" --inplace constellation-state.yaml -yq eval ".infrastructure.clusterEndpoint =\"$(terraform output out_of_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.inClusterEndpoint =\"$(terraform output in_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.ipCidrNode =\"$(terraform output ip_cidr_nodes | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.uid =\"$(terraform output uid | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.name =\"$(terraform output name | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.apiServerCertSANs =$(terraform output -json api_server_cert_sans)" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.resourceGroup =\"$(terraform output resource_group | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.subscriptionID =\"$(terraform output subscription_id | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.networkSecurityGroupName =\"$(terraform output network_security_group_name | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.loadBalancerName =\"$(terraform output loadbalancer_name | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.userAssignedIdentity =\"$(terraform output user_assigned_identity_client_id | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.azure.attestationURL =\"$(terraform output attestationURL | jq -r)\"" --inplace constellation-state.yaml -``` - - - - -```bash -yq eval '.version ="v1"' --inplace constellation-state.yaml -yq eval ".infrastructure.initSecret =\"$(terraform output initSecret | jq -r | tr -d '\n' | hexdump -ve '/1 "%02x"' && echo '')\"" --inplace constellation-state.yaml -yq eval ".infrastructure.clusterEndpoint =\"$(terraform output out_of_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.inClusterEndpoint =\"$(terraform output in_cluster_endpoint | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.ipCidrNode =\"$(terraform output ip_cidr_nodes | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.uid =\"$(terraform output uid | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.name =\"$(terraform output name | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.apiServerCertSANs =$(terraform output -json api_server_cert_sans)" --inplace constellation-state.yaml -yq eval ".infrastructure.gcp.projectID =\"$(terraform output project | jq -r)\"" --inplace constellation-state.yaml -yq eval ".infrastructure.gcp.ipCidrPod =\"$(terraform output ip_cidr_pods | jq -r)\"" --inplace constellation-state.yaml -``` - - - -Self-managed infrastructure allows for managing the cloud resources necessary for a Constellation cluster separate from the Constellation CLI. +Self-managed infrastructure allows for more flexibility in the setup, by separating the infrastructure setup from the Constellation cluster management. This provides flexibility in DevOps and can meet potential regulatory requirements. +It's recommended to use Terraform for infrastructure management, but you can use any tool of your choice. -To self-manage the infrastructure of your cluster, download the Terraform files for the selected CSP from the [Constellation GitHub repository](https://github.com/edgelesssys/constellation/tree/main/terraform/infrastructure). -They contain a minimum configuration for the resources necessary to run a Constellation cluster on the corresponding CSP. From this base, you can now add, edit, or substitute resources per your own requirements with the infrastructure +:::info + + When using Terraform, you can use the [Terraform module](./terraform-module.md) for ease of use to manage the entire Constellation cluster. + +::: + +You can refer to the Terraform files for the selected CSP from the [Constellation GitHub repository](https://github.com/edgelesssys/constellation/tree/main/terraform/infrastructure) for a minimum Constellation cluster configuration. From this base, you can now add, edit, or substitute resources per your own requirements with the infrastructure management tooling of your choice. You need to keep the essential functionality of the base configuration in order for your cluster to function correctly. @@ -266,7 +68,7 @@ management tooling of your choice. You need to keep the essential functionality Make sure all necessary resources are created, e.g., through checking your CSP's portal and retrieve the necessary values, aligned with the outputs (specified in `outputs.tf`) of the base configuration. -Fill these outputs into the corresponding fields of the `constellation-state.yaml` file. For example, fill the IP or DNS name your cluster can be reached at into the `.Infrastructure.ClusterEndpoint` field. +Fill these outputs into the corresponding fields of the `Infrastructure` block inside the `constellation-state.yaml` file. For example, fill the IP or DNS name your cluster can be reached at into the `.Infrastructure.ClusterEndpoint` field. Continue with [initializing your cluster](#the-apply-step). diff --git a/docs/docs/workflows/terraform-module.md b/docs/docs/workflows/terraform-module.md new file mode 100644 index 000000000..e0534b9f5 --- /dev/null +++ b/docs/docs/workflows/terraform-module.md @@ -0,0 +1,151 @@ +# Use the Terraform module +You can manage a Constellation cluster through Terraform. +The module package is available as part of the [GitHub release](https://github.com/edgelesssys/constellation/releases/). It consists of a convenience module for each cloud service provider (`{csp}-constellation`) that combines the IAM (`infrastructure/{csp}/iam`), infrastructure (`infrastructure/{csp}`), and constellation (`constellation-cluster`) modules. + +## Prerequisites +- a Linux / Mac operating system +- a Terraform installation of version `v1.4.4` or above + +## Quick setup +The convenience module allows setting up a Constellation cluster with a single module. It's easiest to consume the module through a remote source, as shown below. +This allows to upgrade the cluster to a newer Constellation version by simply updating the module source. + +:::caution + +In the current release of the module, `terraform apply` creates files such as `constellation-conf.yaml`, `constellation-state.yaml` , `constellation-admin.conf`, `constellation-mastersecret.json`, and a directory `constellation-terraform"` containing backups. Make sure to check in these files in your version control when using GitOps. +The files are deleted on `terraform destroy`. + +::: + +1. Create a directory (workspace) for your Constellation cluster. + ```bash + mkdir constellation-workspace + cd constellation-workspace + ``` + +1. Create a `main.tf` file to call the CSP specific Constellation module. + + + + + + ``` + module "azure-constellation" { + source = "https://github.com/edgelesssys/constellation/releases/download//terraform-module.zip//terraform-module/azure-constellation" // replace with a Constellation version, e.g., v2.13.0 + name = "constell" + location = "northeurope" + service_principal_name = "az-sp" + resource_group_name = "constell-rg" + node_groups = { + control_plane_default = { + role = "control-plane" + instance_type = "Standard_DC4as_v5" + disk_size = 30 + disk_type = "Premium_LRS" + initial_count = 3 + }, + worker_default = { + role = "worker" + instance_type = "Standard_DC4as_v5" + disk_size = 30 + disk_type = "Premium_LRS" + initial_count = 2 + } + } + } + ``` + + + + + + ``` + module "aws-constellation" { + source = "https://github.com/edgelesssys/constellation/releases/download//terraform-module.zip//terraform-module/aws-constellation" // replace with a Constellation version, e.g., v2.13.0 + name = "constell" + zone = "us-east-2c" + name_prefix = "example" + node_groups = { + control_plane_default = { + role = "control-plane" + zone = "us-east-2c" + instance_type = "m6a.xlarge" + disk_size = 30 + disk_type = "gp3" + initial_count = 3 + }, + worker_default = { + role = "worker" + zone = "us-east-2c" + instance_type = "m6a.xlarge" + disk_size = 30 + disk_type = "gp3" + initial_count = 2 + } + } + } + ``` + + + + + + ``` + module "gcp-constellation" { + source = "https://github.com/edgelesssys/constellation/releases/download//terraform-module.zip//terraform-module/gcp-constellation" // replace with a Constellation version, e.g., v2.13.0 + name = "constell" + project = "constell-proj" // replace with your project id + service_account_id = "constid" + zone = "europe-west2-a" + node_groups = { + control_plane_default = { + role = "control-plane" + zone = "europe-west2-a" + instance_type = "n2d-standard-4" + disk_size = 30 + disk_type = "pd-ssd" + initial_count = 3 + }, + worker_default = { + role = "worker" + zone = "europe-west2-a" + instance_type = "n2d-standard-4" + disk_size = 30 + disk_type = "pd-ssd" + initial_count = 2 + } + } + } + ``` + + + + +3. Initialize and apply the module. + ```bash + terraform init + terraform apply + ``` + +## Custom setup +If you need to separate IAM and cluster management or need custom infrastructure, you can also call the submodules individually. +Look at the respective convenience module (`{csp}-constellation`) for how you can structure the module calls. +The submodules are: +- `constellation-cluster`: manages the Constellation cluster +- `fetch-image`: translates the Constellation image version to the image ID of the cloud service provider +- `infrastructure/{csp}`: contains the cluster infrastructure resources +- `infrastructure/iam/{csp}`: contains the IAM resources used within the cluster + +## Cluster upgrades +:::tip +For general information on cluster upgrades, see [Upgrade your cluster](./upgrade.md). +::: + +Using a [remote address as module source](https://developer.hashicorp.com/terraform/language/modules/sources#fetching-archives-over-http) as shown in [Quick setup](#quick-setup) is recommended because it simplifies the upgrade process. For [local paths as module source](https://developer.hashicorp.com/terraform/language/modules/sources#local-paths), you would need to manually overwrite the Terraform files in the Terraform workspace. The steps for the remote source setup are as follows: + +1. Update the `` variable inside the `source` field of the module. +2. Upgrade the Terraform module and provider dependencies and apply the Constellation upgrade. + ```bash + terraform init -upgrade + terraform apply + ``` diff --git a/docs/sidebars.js b/docs/sidebars.js index e194ba844..09f1ce668 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -195,6 +195,11 @@ const sidebars = { label: 'Use persistent storage', id: 'workflows/storage', }, + { + type: 'doc', + label: 'Use the Terraform module', + id: 'workflows/terraform-module', + }, // { // type: 'doc', // label: 'Use Azure trusted launch VMs',