In-cluster deployment
Setting Up an AKS Cluster for PPC
This is the in-cluster deployment guide for Azure. The Azure Kubernetes Service (AKS) cluster and supporting Azure resources are provisioned by the user. The PPC installer then runs only Stage 05 (Helm releases) to deploy the application. The infrastructure is provisioned outside the installer. The cluster must therefore meet the specifications mentioned here.
Follow the prerequisites below and make sure every item matches how the cluster is created.
Deploying PPC using In-Cluster Deployment (AKS)
To deploy PPC, complete the following steps in order. Each step is described in detail in the sections below.
| Step | Action | Description |
|---|---|---|
| # | Before you begin | Confirms that the existing cluster, permissions, identities, storage, and installer inputs meet the prerequisites. |
| 1 | Preparing a jump box | Creates or identifies a jump box with network access to the AKS API server. |
| 2 | Downloading and extracting the release archive | Gets the PPC release archive onto the jump box. |
| 3 | Installing required tools | Installs the CLI tools needed to configure and deploy PPC. |
| 4 | Logging in to Azure CLI | Authenticates with Azure and selects the target subscription. |
| 5 | Configuring AKS access | Retrieves AKS credentials for kubectl and Helm. |
| 6 | Verifying cluster connectivity | Confirms that the jump box can reach the cluster and that nodes are ready. |
| 7 | Gathering values for terraform.tfvars | Collects cluster-specific values, including storage classes, network settings, registry credentials, federated credentials, and node architecture. |
| 8 | Updating terraform.tfvars | Sets the values required by the 05_helm_releases module. |
| 9 | Running the readiness check | Validates the environment and identifies issues to resolve before deployment. |
| 10 | Applying the OpenTofu configuration | Applies the configuration to deploy PPC Helm charts onto the AKS cluster. |
Before you begin
Prerequisites checklist
Before deployment, confirm that the environment meets all the prerequisites below. The installer’s readiness check validates applicable requirements before Stage 05.
Access & permissions
Verify that the required permissions are in place at each Azure scope:
| Azure scope | Required permission | Purpose |
|---|---|---|
| Resource group containing the cluster | Contributor or Owner. | Create the storage account, cluster, node pool, and identities. |
| Resource group, storage account, and Key Vault | Owner, User Access Administrator, or Role Based Access Control Administrator. | Create role assignments and federated credentials. |
| Key Vault | Key Vault Administrator or Key Vault Crypto Officer | Create the encryption key in an RBAC-enabled vault. |
| AKS subnet (VNet) | Grant the AKS identity Network Contributor; the operator needs Network Contributor, Owner, or User Access Administrator to assign it. | Allow the AKS identity to join the subnet and create the private cluster. |
| Private DNS zone | Grant the AKS identity Private DNS Zone Contributor. The operator needs that role, Owner, or User Access Administrator to assign it. | Allow the AKS identity to manage records for the private cluster. |
Network scopes are the most common blocker. The subnet and private DNS zone are often owned by IT in a different resource group or subscription. Ask the scope owner to assign
Network Contributoron the subnet andPrivate DNS Zone Contributoron the DNS zone. Assign both roles to the AKS managed identity. Without both, the private cluster creation fails.
Backup storage
| Requirement | Details |
|---|---|
| Backup container | Create the backup container (velero) in the storage account. |
| Storage account type | Use StorageV2 / blob, not Azure Files, and keep hierarchical namespace Off. Otherwise, backups fail. |
| Customer-managed key (if required) | Configure a Key Vault with an RSA-2048 key and CMK encryption. The storage account identity needs Key Vault Crypto Service Encryption User on the vault. |
Identities and RBAC
| Identity or value | Required role or configuration | Scope |
|---|---|---|
| AKS identity | Managed Identity Operator and Virtual Machine Contributor. | Resource group |
| AKS identity | Network Contributor. | AKS subnet |
| AKS identity | Private DNS Zone Contributor. | Private DNS zone; required for a private cluster |
| Velero identity | Disk Snapshot Contributor. | Resource group |
| Velero identity | Storage Blob Data Contributor. | Storage account |
| Velero identity | Key Vault Crypto User. | Key Vault |
| OpenSearch identity | Storage Blob Data Contributor. | Storage account |
| Velero and OpenSearch identities | Capture valid client IDs in UUID format. | - |
AKS cluster
| Requirement | Expected configuration |
|---|---|
| Cluster availability | Cluster exists and is reachable. |
| Cluster access | Cluster is private. |
| Identity integration | OIDC issuer and Workload Identity are enabled. |
| Networking | Azure CNI Overlay + Cilium; this is immutable and required by NAP. |
| Node Auto Provisioning | Enabled in Auto mode. |
| Authentication | Local accounts with Kubernetes RBAC; otherwise kubectl may return Forbidden. |
| Secrets Store CSI driver | Key Vault Secrets Store CSI driver addon is enabled. |
| Availability zones | Node pools span at least two availability zones. |
| System node pool | Has the CriticalAddonsOnly=true:NoSchedule taint, at least 2 nodes, and an adequate VM size. |
| Node architecture | Every node pool uses the same architecture (amd64 or arm64), matching architecture in 05_helm_releases/terraform.tfvars. Refer to Step 7.5. |
| Federated credentials | Velero and OpenSearch credentials use this cluster’s OIDC issuer. |
| Network ranges | Set pod_cidr, service_cidr, and dns_service_ip; ranges must not overlap the VNet, and pod_cidr must match the cluster network profile. |
| Platform namespaces | Do not pre-create PPC platform namespaces. |
Application node pool
| Requirement | Expected configuration |
|---|---|
| Application pool | User mode, Succeeded state, at least 3 nodes, adequate VM size, name matching node_pool_name, and no CriticalAddonsOnly taint. |
| Node architecture | Matches the system node pool and architecture in 05_helm_releases/terraform.tfvars. Refer to Step 7.5. |
Storage class
| Requirement | Expected configuration |
|---|---|
| PPC storage classes | The classes set in storage_class_name and backup_storage_class_name exist on the cluster. |
For an externally provisioned cluster, both StorageClasses required by PPC must exist before installation. Stage 05 provisions volumes using the classes named in the installer’s storage_class_name and backup_storage_class_name. Otherwise, readiness check fails and deployment cannot proceed.
| Option | General class (storage_class_name) | Backup class (backup_storage_class_name) | Guidance |
|---|---|---|---|
| Create dedicated classes | pty-sc | pty-bkp | Prefer reclaimPolicy: Retain for the backup class. Built-in Azure classes use Delete, which is unsafe for backup volumes. |
| Reuse existing classes | An existing class on the cluster | An existing class on the cluster | Both class names must match StorageClasses present on the cluster. |
Install inputs (tfvars)
| Input | Requirement |
|---|---|
subnet_id | Set to a valid subnet resource ID. |
ingress_fqdn | Set to a real, valid FQDN. |
global_image_reg | Set to a reachable container registry endpoint: <Container_Registry_Path>.Note: If deploying from the Protegrity Container Registry, use registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. |
| Private registry credentials | If the registry is private, set harbor_secret and provide TF_VAR_username / TF_VAR_password. |
Deploying PPC
After all prerequisites are met, deploy PPC by following these steps.
1. Preparing a jump box
Create a jump box or use an existing one that has network access to the AKS cluster. The jump box must be able to access the private AKS API server endpoint.
2. Downloading and extracting the release archive
To download and extract the PCT, refer to Preparing for PPC deployment.
3. Installing required tools
To install the required tools from the extracted PPC release archive, run the following command:
./bootstrap-scripts/setup-devtools-azure.sh
The script installs the following tools:
| Tool | Description |
|---|---|
| OpenTofu | Open-source Terraform fork used to provision and manage infrastructure. |
| Azure CLI | Command-line tool for managing Azure resources. |
| kubectl | Kubernetes command-line tool for interacting with the cluster. |
| Helm | Kubernetes package manager for deploying Helm charts. |
| skopeo | Tool for inspecting and copying container images between registries. |
| jq | Lightweight command-line JSON processor. |
| bc | Arbitrary-precision calculator used in shell scripts. |
| ssh-client | SSH client for secure remote access. |
| oras | OCI Registry As Storage client for pushing and pulling artifacts. |
| cmctl | Command-line tool for managing cert-manager resources. |
4. Logging in to Azure CLI
To authenticate with the Azure CLI, use the device code flow.
az login --use-device-code
Note: CLI login using Single Sign-On (SSO) is not supported. Use
az login --use-device-codeor authenticate as a Service Principal.
If more than one subscription is available, select the target subscription.
az account set --subscription <SUBSCRIPTION-ID>
5. Configuring AKS access
To retrieve the AKS credentials and configure kubectl to communicate with the cluster, run the following command:
az aks get-credentials --resource-group "<resource-group>" --name "<cluster-name>" --overwrite-existing
6. Verifying cluster connectivity
To confirm that the jump box can reach the cluster API, run the following commands:
kubectl get pods -A
kubectl get nodes
All nodes should be listed and in Ready state before proceeding.
7. Gathering values for terraform.tfvars
Complete each of the following sub-steps to populate terraform.tfvars with the required cluster-specific values.
7.1 Storage class
List the existing storage classes on the cluster and update both the storage_class_name and backup_storage_class_name values in terraform.tfvars.
kubectl get sc -A
Review the output and select only storage classes that already exist in the cluster.
storage_class_name: Choose the storage class that will be used by PPC application workloads. This must match an existing storage class on the cluster.backup_storage_class_name: Choose the storage class used for backup-related volumes, such as Velero backup data. This must also match an existing storage class on the cluster.
For example, if the output shows the following:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-csi-premium disk.csi.azure.com Delete WaitForFirstConsumer true ...
managed-csi-premium-v2 disk.csi.azure.com Delete WaitForFirstConsumer true ...
then set the values as follows:
storage_class_name = "managed-csi-premium-v2"
backup_storage_class_name = "managed-csi-premium"
Note: Use only storage classes that are visible in the cluster output. If the selected storage class is not present, PPC deployment may fail. The workload or backup storage class is unavailable.
7.2 Pod CIDR
Retrieve the pod CIDR for the cluster and update the pod_cidr value in terraform.tfvars.
az aks show --resource-group <RESOURCE-GROUP> --name <CLUSTER-NAME> --query "networkProfile.podCidr" -o tsv
This cluster uses the required Azure CNI Overlay and Cilium networking (refer to the AKS cluster prerequisites). The command returns a populated pod CIDR, for example, 10.244.0.0/16. Set pod_cidr in terraform.tfvars to that exact value.
Note:
pod_cidrmust match the cluster’s network profile and must not overlap the VNet, service CIDR, or node subnet ranges.
Important: If this command returns an empty value, the cluster is not using Azure CNI Overlay. Overlay is a required, immutable prerequisite for PPC (NAP depends on it). An empty
podCidrindicates the cluster was built with the wrong network configuration. Do not substitute the node subnet CIDR. Recreate the cluster with Azure CNI Overlay and Cilium as described in the AKS cluster prerequisites.
7.3 Registry credentials
When using an authenticated private registry, set harbor_secret to harbor-secret in terraform.tfvars. Export the container registry credentials before running tofu apply. Otherwise, the apply fails while pulling PPC images and charts. Leave harbor_secret empty for an unauthenticated registry.
export TF_VAR_username="<REGISTRY-USERNAME>"
export TF_VAR_password="<REGISTRY-PASSWORD>"
Note: Registry credentials are passed as environment variables (
TF_VAR_usernameandTF_VAR_password) and are not set directly interraform.tfvars.
7.4 Federated credentials
Set the cluster context variables and retrieve the OIDC issuer URL. Then create the Velero and OpenSearch federated credentials against this cluster’s issuer.
export CLUSTER_NAME=<CLUSTER-NAME>
export RESOURCE_GROUP=<RESOURCE-GROUP>
ISSUER="$(az aks show -g "$RESOURCE_GROUP" -n "$CLUSTER_NAME" --query "oidcIssuerProfile.issuerUrl" -o tsv)"
az identity federated-credential create \
--name "velero-workload-identity-$CLUSTER_NAME" \
--identity-name "<VELERO-MANAGED-IDENTITY-NAME>" \
--resource-group "$RESOURCE_GROUP" \
--issuer "$ISSUER" \
--subject "system:serviceaccount:pty-backup-recovery:backup-recovery-utility" \
--audiences "api://AzureADTokenExchange"
az identity federated-credential create \
--name "opensearch-workload-identity-$CLUSTER_NAME" \
--identity-name "<OPENSEARCH-MANAGED-IDENTITY-NAME>" \
--resource-group "$RESOURCE_GROUP" \
--issuer "$ISSUER" \
--subject "system:serviceaccount:pty-insight:opensearch-cluster-master" \
--audiences "api://AzureADTokenExchange"
Note: Bash variable names cannot contain hyphens. Use
$RESOURCE_GROUP, not$RESOURCE-GROUP. Thesubjectstrings must be exact.
7.5 Node architecture
- Check the architecture of the cluster nodes:
kubectl get nodes -L kubernetes.io/arch
- Set
architecturein05_helm_releases/terraform.tfvarsto match thekubernetes.io/archvalues:
architecture = "arm64" # For *ps_v5 (Arm) VM sizes; use "amd64" (default) for *as_v5 / x86 sizes.
All node pools must use the same architecture. For example, Standard_D2ps_v5 system nodes and Standard_D8ps_v5 application nodes require architecture = "arm64". Readiness check 13 uses this value to select the minimum VM sizes. Leaving the default amd64 value on an arm64 cluster causes the VM size check to fail.
8. Updating terraform.tfvars
To update the terraform.tfvars file, perform the following steps:
- Navigate to the Helm releases module directory.
cd iac/azure/cluster/modules/05_helm_releases
- After completing Steps 7.1 through 7.5, set the following variables in
05_helm_releases/terraform.tfvars.
| Variable | Description | Configured in |
|---|---|---|
aks_cluster_name | AKS cluster. | Step 5 |
architecture | Node architecture of the AKS node pools: amd64 (default) or arm64. | Step 7.5 |
azure_subscription_id | Azure subscription ID. | Step 4 |
backup_storage_class_name | Storage class used for backup volumes. | Step 7.1 |
node_pool_name | AKS user node pool name. | Application node pool |
opensearch_uami_client_id | Client or Object ID of the OpenSearch user-assigned managed identity. | Identities and RBAC |
pod_cidr | Pod network CIDR range. | Step 7.2 |
resource_group_name | Azure resource group containing the cluster. | Step 5 |
storage_account_name | Azure storage account used by Velero for backups. | Backup storage |
storage_class_name | Existing storage class on the cluster. | Step 7.1 |
storage_container_name | Azure Blob Storage container used by Velero for backups. Defaults to velero. | Backup storage |
velero_uami_client_id | Client or Object ID of the Velero user-assigned managed identity. | Identities and RBAC |
subnet_id | The full subnet resource ID. | Install inputs |
ingress_fqdn | The application hostname (a real, resolvable FQDN). | Install inputs |
global_image_reg | Container registry host: <Container_Registry_Path>.Note: Registry credentials are passed as environment variables ( TF_VAR_username and TF_VAR_password) as configured in Step 7.3. They are not set directly in terraform.tfvars. | Install inputs |
harbor_secret | Only if the registry needs to be authenticated | Install inputs |
- Add the following variables to
terraform.tfvarsbefore allowing Stage 05 to apply.
run_readiness_check = true
check_prev_stage = false
These variables ensure that PPC performs a readiness check on the existing AKS environment. They skip the previous automated stage validation, since those resources were created outside the installer.
- Save the file and exit the editor.
9. Running the readiness check
Run the readiness check script and review any reported errors. Resolve all errors before proceeding to the next step.
To run the readiness check, run the following command:
./bootstrap-scripts/readiness-helm-azure.sh
10. Applying the OpenTofu configuration
To initialize and apply the OpenTofu configuration to deploy all PPC Helm charts onto the cluster, perform the following steps:
- Navigate to the Helm releases module directory.
cd iac/azure/cluster/modules/05_helm_releases
Important: Before running
tofu planortofu apply, review all values interraform.tfvarsand confirm that they match the target environment.
- To initialize, plan, and apply the OpenTofu configuration to deploy all PPC Helm charts onto the cluster, run the following commands:
tofu init
tofu plan # Review the planned resources that will be created.
tofu apply # When prompted with "Enter a value:", type "yes".
- To verify the resources created in this stage, run the following commands:
# Confirm nodes are Ready
kubectl get nodes
# Confirm pods are Running
kubectl get pods -A
Readiness checklist
Each readiness check maps to one or more prerequisite sections. Use this table to confirm that all applicable requirements are met. Do this before running the check.
| # | Readiness check | Prerequisites |
|---|---|---|
| 1 | azure_subscription_id valid + matches active CLI | Step 4: Logging in to Azure CLI; Install inputs |
| 2 | AKS cluster exists and is reachable | AKS cluster |
| 3 | OIDC issuer + Workload Identity enabled | AKS cluster |
| 4 | Node pools span ≥ 2 availability zones | AKS cluster; Application node pool |
| 5 | Application user node pool exists and is ready | Application node pool |
| 6 | Required storage classes exist (general + backup) | Storage class |
| 7 | Federated credentials for Velero + OpenSearch | AKS cluster |
| 8 | System pool tainted CriticalAddonsOnly; user pool not | AKS cluster; Application node pool |
| 9 | Container exists + Storage Blob Data Contributor on UAMIs | Backup storage; Identities and RBAC |
| 10 | pod_cidr valid + matches cluster | AKS cluster; Install inputs |
| 11 | global_image_reg set, well-formed, reachable | Install inputs |
| 12 | Node Auto Provisioning (NAP) enabled | AKS cluster |
| 13 | Node pool count + VM size minimums | AKS cluster; Application node pool; Step 7.5: Node architecture |
| 14 | subnet_id valid + Network Contributor on it | Identities and RBAC; Install inputs |
| 15 | ingress_fqdn set and a valid FQDN | Install inputs |
| 16 | Key Vault Secrets Store CSI driver addon enabled | AKS cluster |
| 17 | AKS cluster is private | AKS cluster |
| 18 | velero_uami_client_id / opensearch_uami_client_id valid UUIDs | Identities and RBAC; Install inputs |
| 19 | harbor_secret → registry creds set + reachable | Install inputs |
| 20 | Platform namespaces don’t already exist | AKS cluster |
Common problems
| Problem | Cause or action |
|---|---|
Backups fail with a 403 / AuthorizationPermissionMismatch | The Velero or OpenSearch identity is missing Storage Blob Data Contributor on the storage account. |
| Cannot enable customer-managed key | The storage account identity lacks Key Vault Crypto Service Encryption User, or the role assignment has not propagated. Wait for propagation and retry. |
| Private cluster fails to create | The AKS identity lacks Network Contributor on the subnet or Private DNS Zone Contributor on the cross-subscription DNS zone. |
kubectl says Forbidden | The cluster uses Entra ID authentication, but the identity running kubectl has not been granted cluster-admin access. Use Local accounts with Kubernetes RBAC. |
| Two default storage classes | The built-in default StorageClass is still marked as default. |
| Install fails because a namespace already exists | PPC namespaces must not be pre-created: api-gateway, pty-loginui, pty-admin, cert-manager, karpenter, pty-insight, pty-backup-recovery, cli, reloader, and email-service. |
If the readiness check fails
The readiness check is read-only and validates the applicable requirements in the prerequisite checklist. Use the table below to find a fix for each failure. Settings marked immutable cannot be changed after cluster creation; recreate the cluster with the correct settings described in AKS cluster.
| Readiness failure | Fix | Immutable? |
|---|---|---|
| AKS cluster is PUBLIC | Recreate with --enable-private-cluster. Refer to AKS cluster. | Yes. Recreate. |
System pool missing CriticalAddonsOnly taint | Recreate the system pool with the taint. Refer to AKS cluster. | Yes. Recreate. |
| OIDC / Workload Identity disabled | Recreate with --enable-oidc-issuer --enable-workload-identity | Yes. Recreate. |
| Wrong network (not CNI Overlay + Cilium) | Recreate with the networking flags. Refer to AKS cluster. | Yes. Recreate. |
NAP not enabled (mode=Manual) | az aks update -g $RG -n $CLUSTER --node-provisioning-mode Auto (requires Overlay+Cilium) | No |
| Secret Store CSI driver not enabled | az aks enable-addons -g $RG -n $CLUSTER --addons azure-keyvault-secrets-provider | No |
Node pool userpool not found | Set node_pool_name in tfvars to the actual pool name, or add the pool. Refer to Application node pool. | No |
Storage class pty-sc/pty-bkp not found | Create them, or set storage_class_name/backup_storage_class_name to an existing class. Refer to Storage class. | No |
| Federated credential missing | Create credentials for Velero and OpenSearch against the cluster OIDC issuer. Refer to AKS cluster. | No |
Storage Blob Data Contributor not assigned | Assign the role to both UAMIs at the storage-account scope. Refer to Identities and RBAC. | No |
subnet_id / pod_cidr not set | Set them in tfvars | No |
Node pool VM size below the minimum for architecture amd64 (cluster uses arm64 *ps_v5 sizes) | Set architecture = "arm64" in 05_helm_releases/terraform.tfvars to match the node pools. Refer to Step 7.5. | No |
| System/app pool too few nodes or VM too small | Scale or recreate the pool. System ≥ 2 nodes, and app ≥ 3 nodes. | No |
Note: A public cluster with disabled OIDC or Workload Identity, incorrect networking, and a missing system-pool taint require cluster recreation. Configure these correctly in AKS cluster before creating the cluster. A correctly configured
az aks createcommand addresses all of these immutable requirements.
Feedback
Was this page helpful?