This section covers preparing the environment and deploying the Protegrity Provisioned Cluster PPC on Microsoft Azure.
This is the multi-page printable view of this section. Click here to print.
Installation
1 - Prerequisites
Microsoft Azure Resource Providers
The following Microsoft Azure resource providers are registered.
Microsoft.ContainerServiceMicrosoft.NetworkMicrosoft.ComputeMicrosoft.StorageMicrosoft.KeyVaultMicrosoft.ManagedIdentity
Creating a Storage Account in Azure
An Azure Storage Account is required to store cluster backup data. The following steps guide you through creating the storage account. They also cover configuring the required blob container, provisioning a Key Vault, and assigning the necessary permissions.
1. Creating the Storage Account
Create an Azure Storage Account to serve as the backend for cluster backup and restore operations using Velero.
To create a storage account, perform the following steps:
- Sign in to the Azure portal.
- Navigate to Home > Storage accounts, then select Create.
- On the Basics tab, provide the required details:
- Subscription: The Azure subscription to bill for this resource.
- Resource group: The logical container that groups related Azure resources.
- Storage account name: A globally unique name using only lowercase letters and numbers.
- Region: The Azure datacenter location where the storage account will be hosted.
- Primary service: The primary Azure service that will use this storage account (e.g., Blob Storage, Azure Files).
- Performance tier: Choose Standard for general-purpose workloads or Premium for low-latency requirements.
- Redundancy option: The replication strategy for your data (e.g., LRS, GRS, ZRS).
- Keep the default values for the remaining tabs unless a specific project requirement applies.
- On the Review + create tab, review the configuration, then select Create.
- After deployment completes, select Go to resource to open the newly created storage account.
Note: A blob container named
veleromust be created inside the storage account before installation. If the container does not exist, the installation will fail when the deployment attempts to access it.
2. Creating a container inside the storage account
Create a blob container named velero within the storage account. This container is used by Velero to store backup snapshots.
To create a container inside the storage account, perform the following steps:
- Navigate to Home > Storage accounts, then select the required storage account.
- In the left pane, under Data storage, select Containers.
- Select Add Container.
- In the New container pane, enter
veleroas the container name. - Set the anonymous access level to Private (no anonymous access).
- Select Create, and verify that the
velerocontainer appears in the container list.
3. Creating a Key Vault
Create an Azure Key Vault to securely store the encryption keys used during cluster deployment.
To create a Key Vault, perform the following steps:
- Navigate to Home > Key vaults, then select Create.
- Fill out the required details in the Basics section.
- Leave the Access configuration, Networking, and Tags sections at their default values.
- Select Review + create, then select Create.
4. Assigning the Key Vault Administrator role
The Key Vault Administrator role must be assigned to the identity performing the installation. This role is required to create, update, and manage secrets, certificates, and keys. Those items are stored in the Key Vault used during deployment. Without this permission, the installation may fail.
Verifying current role assignments
To verify current role assignments, perform the following steps:
- Navigate to Home > Key vaults, then select the key vault.
- In the left pane, select Access control (IAM), then select View my access.
- Confirm whether the Key Vault Administrator role is already assigned.
Adding the Key Vault Administrator role
To add the Key Vault Administrator role, perform the following steps:
- In Access control (IAM), select Add role assignment.
- Search and select Key Vault Administrator.
- Under Members, add the required members.
- Leave Conditions unchanged, then select Review + assign.
- Verify that the Key Vault Administrator role is now listed for the selected key vault.
5. Adding Keys to the Key Vault
Generate an encryption key inside the Key Vault. This key is referenced during cluster installation to encrypt storage and other sensitive resources.
To add keys to the Key Vault, perform the following steps:
- Navigate to Home > Key vaults, then select the key vault.
- In the left pane, select Objects > Keys, then select Generate/Import.
- Provide the required key details and complete key generation.
Note: For the Key Vault keys, only RSA keys are supported.
Note the values for the following. They are required during cluster installation.
- Storage account name
- Key vault
- Key name
Permissions to deploy AKS
Update the following custom role permissions.
Before you begin
- Identify the resource group where the AKS cluster will be created.
- Ensure that a custom role is already created in the subscription or resource group.
- Complete this configuration before starting the AKS installation process.
To update the permission for the custom role, perform the following steps:
Navigate to the required resource group in the Azure portal.
Open Access control (IAM) for the selected resource group.
Locate the existing custom role.
Select the custom role and click Edit.
Select JSON and click Edit.
Update the role by adding the following permissions:
{
"id": "/subscriptions/<SUBSCRIPTION-ID>/providers/Microsoft.Authorization/roleDefinitions/<ROLE-DEFINITION-ID>",
"properties": {
"roleName": "<ROLE-NAME>",
"description": "",
"assignableScopes": [
"/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RG-Name>"
],
"permissions": [
{
"Actions": [
"Microsoft.Authorization/roleAssignments/read",
"Microsoft.Authorization/roleAssignments/write",
"Microsoft.Authorization/roleDefinitions/read",
"Microsoft.Authorization/roleDefinitions/write",
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write",
"Microsoft.KeyVault/vaults/read",
"Microsoft.KeyVault/vaults/write",
"Microsoft.ManagedIdentity/userAssignedIdentities/assign/action",
"Microsoft.ManagedIdentity/userAssignedIdentities/read",
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Storage/locations/checknameavailability/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/write",
"Microsoft.Storage/storageAccounts/blobServices/read",
"Microsoft.Storage/storageAccounts/blobServices/write",
"Microsoft.Storage/storageAccounts/fileServices/read",
"Microsoft.Storage/storageAccounts/fileServices/write",
"Microsoft.Storage/storageAccounts/listKeys/action",
"Microsoft.Storage/storageAccounts/read",
"Microsoft.Storage/storageAccounts/write",
"Microsoft.Network/privateDnsZones/read",
"Microsoft.Network/privateDnsZones/A/read",
"Microsoft.Network/privateDnsZones/A/write",
"Microsoft.Network/privateDnsZones/write",
"Microsoft.Network/privateDnsZones/join/action",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks/read",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks/write",
"Microsoft.ContainerService/managedClusters/listClusterUserCredential/action",
"Microsoft.ContainerService/managedClusters/agentPools/read",
"Microsoft.ContainerService/managedClusters/agentPools/write",
"Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/write",
"Microsoft.KeyVault/vaults/read"
],
"notActions": [],
"dataActions": [],
"notDataActions": []
}
]
}
}
- Click Save after updating the permissions.
- Click Review + update to finalise the changes.
Jump Box or Local Machine
A jump box serves as a secure, controlled access point for executing installation commands and managing cluster resources. It ensures that all operations originate from a trusted environment with direct network access to the PPC cluster. This avoids connectivity issues that may arise from local machines with restricted network paths or inconsistent tooling.
Use a dedicated Debian or Red Hat jump box created in Microsoft Azure. Do not use a jump box hosted on any other cloud.
The jump box must be provisioned in the same Azure region where the PPC cluster will be deployed. This ensures proper connectivity and access to regional resources.
For example, if the PPC cluster is deployed in
eastus, the jump box must also be created ineastus. Placing the jump box in a different region, such aswesteurope, may result in network access failures. It may also cause latency issues when connecting to cluster endpoints.
Microsoft Azure Region
For automated installation
Identify the Azure region where the cluster is to be deployed.
The deployment region is automatically detected from the resource group’s location during the bootstrap process. Ensure that the resource group is created in the intended deployment region before running the installer.
All resources must be in the same region.For more information about Microsoft Azure resources, refer to Microsoft Azure Resource IDs from Infrastructure Team.
For component-based installation
Identify the Azure region where the cluster is to be deployed.
Region must be specified as azure_location in the terraform.tfvars file during the 00_backup_storage and 02_aks_cluster stages.
All resources must be in the same region.For more information about Microsoft Azure resources, refer to Microsoft Azure Resource IDs from Infrastructure Team.
Microsoft Azure Resource IDs from Infrastructure Team
Deployment Resource Group
Before proceeding with the installation, identify the Azure Resource Group where the cluster is to be deployed.
- For automated deployment, specify this resource group name at the input prompt when running the
./bootstrap.shscript. - For component-based deployment, set the
resource_group_namefield in theterraform.tfvarsfiles, wherever required.
The following resources are provisioned within the resource group specified during deployment.
| Stage | Resources Created |
|---|---|
| 00_Backup Storage | Storage Account, Key Vault, Key Vault Key, Blob Container |
| 01_Identity | RBAC Role Assignments (references existing UAMIs; no new resources created) |
| 02_AKS Cluster | AKS Cluster, Federated Credentials |
| 03_Node Pool | AKS User Node Pool |
| 04_AKS Addons | Storage Classes, Cluster Add-ons |
| 05_Helm Releases | Kubernetes Namespaces, Secrets, Helm Charts |
Pre-existing Resources
The following resources must be provisioned by the IT team before installation.
They can reside in any resource group in the same region. The installer references each resource by its entire Azure resource ID.
Ensure the deploying identity, such as, service principal or managed identity, has the appropriate permissions on these resources.
| Resource | Description | Variable in terraform.tfvars | Example Resource ID |
|---|---|---|---|
| AKS User-Assigned Managed Identity | Identity used by the AKS cluster to interact with Azure resources such as Private DNS Zones and Virtual Networks. | uami_id | /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id-aks-applianceframeworkMust have Private DNS Zone and VNet custom role permissions. For more information, refer to AKS User-Assigned Managed Identity Permissions. |
| Velero User-Assigned Managed Identity | Identity used by Velero to access Azure Blob Storage for cluster backup and restore operations. | velero_uami_id | /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id-aks-velero |
| OpenSearch User-Assigned Managed Identity | Identity used by OpenSearch to access required Azure resources for log storage and indexing. | opensearch_uami_id | /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id-aks-opensearch |
| Virtual Network / Subnet | The subnet within an existing Virtual Network where all AKS cluster nodes are placed. | subnet_id | /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/<vnet>/subnets/<subnet> |
| Private DNS Zone | The pre-existing private DNS zone used for resolving internal AKS API server endpoints within the Virtual Network. | private_dns_zone_id | /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.Network/privateDnsZones/privatelink.eastus.azmk8s.io |
AKS User-Assigned Managed Identity Permissions
The AKS User-Assigned Managed Identity (id-aks-applianceframework) must be granted a custom role with the following permissions. Grant these permissions on the resource group that contains the Private DNS Zone and Virtual Network. These permissions enable AKS to manage private DNS records and join virtual networks during cluster operations.
To configure the User-Assigned Managed Identity, perform the following steps. Use a custom Azure role that contains the permissions required for AKS deployment and management operations within the specified resource group.
1. Creating a Custom Role
- In the Azure portal, navigate to Resource Groups.
- Select the resource group that contains the AKS resources.
- Open Access Control (IAM).
- Select Add > Add custom role.
- Provide a name and description for the custom role.
- Select JSON and add the following permissions.
{
"Name": "<ROLE-NAME>",
"Description": "",
"AssignableScopes": [
"/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RESOURCE-GROUP>"
],
"Actions": [
"Microsoft.Network/privateDnsZones/read",
"Microsoft.Network/privateDnsZones/A/read",
"Microsoft.Network/privateDnsZones/A/write",
"Microsoft.Network/privateDnsZones/A/delete",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks/read",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks/write",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks/delete",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/privateDnsZones/write",
"Microsoft.Network/virtualNetworks/join/action"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": []
}
- Review the permissions and create the custom role.
Note: These permissions are required when using a private AKS cluster with a pre-existing Private DNS Zone (private_dns_zone_id). Without them, cluster provisioning and DNS resolution will fail.
2. Assigning the custom role to the Managed Identity
On the Azure portal, navigate to Managed Identities.
Select Create.
Specify the following:
- Subscription
- Resource group
- Managed identity name
- Region
Select Review + Create and then Create.
Wait for the User-Assigned Managed Identity (UAMI) to be provisioned.
Open the newly created User-Assigned Managed Identity.
Select Azure role assignments.
Select Add role assignment.
Set the scope to the target resource group.
Select the custom role created in the previous section.
Assign the role to the User-Assigned Managed Identity.
Verify that the role assignment appears under the managed identity’s role assignments.
Zone Requirements
The cluster requires a minimum of two availability zones for high availability. Three-zone cluster deployments are supported and recommended for production.
| No. of Zones | Supported | Notes |
|---|---|---|
| 1 | No | Installation fails. |
| 2 | Yes | Minimum requirement for High Availability. |
| 3 | Yes | Recommended for production environments. |
Ensure the following requirements are met before deploying:
| Requirement | Detail |
|---|---|
| Region support | The target Azure region must support availability zones. |
| VM SKU availability | The chosen VM size must be available in all the specified zones. |
The bootstrap script does not prompt for zone selection, it uses the default three zone configuration.
The default zone configuration is ["1", "2", "3"]. Not all Azure regions support three availability zones, and not all VM SKUs are available in every zone. Using a zone that does not support your VM SKU causes cluster creation to fail.
To verify the zone that is supported in the required region for PPC deployment, run the following command:
# List availability zones for your region
az account list-locations \
--query "[?name=='<region>'].availabilityZoneMappings[].logicalZone" \
-o table
Replace <region> with your Azure region, for example eastus.
| No. of Zones in the Output | Description |
|---|---|
empty or none | Select a different region. At least two zones are required for deploying PPC successfully. |
| Two | Update the value of system_node_pool_zones and node_pool_zones in the terraform.tfvars files for 02_aks_cluster and 03_node_pool modules |
| Three | No action is required |
Perform the following steps to modify the number of zones
Navigate to
iac/azure/cluster/modules.Enter the value of the supported zones in both
terraform.tfvarsfiles for02_aks_clusterand03_node_poolmodules.# 02_aks_cluster/terraform.tfvars system_node_pool_zones = ["<value of supported zone 1>", "<value of supported zone 2>"] # adjust to the zones your region supports # 03_node_pool/terraform.tfvars node_pool_zones = ["<value of supported zone 1>", "<value of supported zone 2>"] # must match system_node_pool_zones exactlywhere
<value of supported zone 1> and <value of supported zone 2>are the supported zones in the required Azure region.For more information on editing the
02_aks_cluster, and03_node_poolmodules, refer to Manual component-based installation.
Node pool sizing
The step [1b] Select Node Architecture in the bootstrap script prompts to select the node architecture interactively during deployment.
For arm64 and amd64, the following are the default system and user node pool configurations.
amd64 (x86-64)
| Node Pool | VM Size | vCPUs | Memory |
|---|---|---|---|
| System | Standard_D2as_v5 | 2 | 8 GB |
| User | Standard_D8as_v5 | 8 | 32 GB |
arm64
| Node Pool | VM Size | vCPUs | Memory |
|---|---|---|---|
| System | Standard_D2ps_v5 | 2 | 8 GB |
| User | Standard_D8ps_v5 | 8 | 32 GB |
Before creating the cluster, verify that your target Azure region provides the required availability zones. Also confirm that your subscription can launch the required VM sizes in those zones.
# System node pool SKU
az vm list-skus \
--subscription <subscription ID> \
--location <region>\
--size <VM Size>\
--output table
where
subscription IDis the subscription ID for the Microsoft Azure account.<region>is the name of the region where PPC is to be deployed.<VM Size>is one of the supported amd64 or arm64 VM sizes listed above. Run the command once for each size. Ensure that the access to launch both, system and user node pool, are available.
A sample output is as follows:
ResourceType Locations Name Zones Restrictions
--------------- ----------- ---------------- ------- --------------
virtualMachines eastus Standard_D8as_v5 1,2,3 NotAvailableForSubscription type: Zone, locations: eastus zones: 3,1
where,
- Zones are the availability zones in which the VM size can be deployed. At least two zones must be available. If the
Zonescolumn is empty, then the region does not offer availability zones for that size. In such scenarios, select a different region. - Restrictions If the value is
None, no action is required. If any restriction is listed, take the relevant action before proceeding. For example, choose a different region, or request access or increase quota.
AKS cluster tier
The sku_tier setting controls the AKS API server uptime SLA, available node capacity, and supported features.
| Tier | Uptime SLA | Notes |
|---|---|---|
Free | No SLA | Suitable for development and testing only |
Standard | 99.9% (99.95% with Availability Zones) | Recommended for production |
Premium | 99.9% (99.95% with Availability Zones) + LTS | Required if long-term support is needed |
Set sku_tier = "Standard" for all production deployments. Use "Premium" if your organization requires long-term support (LTS) guarantees.
In 02_aks_cluster/terraform.tfvars, edit the following value:
sku_tier = "Standard"
For more information on editing the 02_aks_cluster module, refer to Manual component-based installation.
2 - Preparing for PPC deployment
The PCT is a pre-packaged deployment archive. It contains the infrastructure-as-code scripts, Helm charts, and bootstrap tooling. These are required to provision a PPC on your target cloud platform. It automates the creation of the Kubernetes cluster, networking, identity configuration, and installation of Protegrity microservices. Download and extract the PCT on your jump box before starting the deployment process.
Note: If there is an existing cluster from a previous install, clean up your local registry on the jump box. Also clean up any existing clusters by running
./bootstrap.sh --cloud azure destroyfrom/deploymentbefore proceeding.
During installation, the system may prompt for the system password and require sign-in to Microsoft Azure. If the Azure CLI is not already logged in, the bootstrap script automatically runs az login --use-device-code. A device-code prompt similar to the following appears.
[YYYY-MM-DD HH:MM:SS] Azure CLI not logged in. Triggering az login...
To sign in, use a web browser to open the page https://login.microsoft.com/device and enter the code XXXXXXXX to authenticate.
To sign-in to Microsoft Azure, perform the following steps:
- Open the displayed URL in a browser, and enter the code shown in the terminal.
- Complete the SSO sign-in and follow the on-screen instructions.
- After successful authentication, the script continues automatically.
To download and extract PCT, perform the following steps:
Log in to the My.Protegrity portal.
Navigate to Product Management > Explore Products > AI Team Edition > Platform Installation.
From the Actions column for Protegrity Provisioned Cluster, click the Download Product icon. This downloads the PPC 1.2 archive.
Create a
deployment_120directory on the jumpbox.mkdir deployment_120 && cd deployment_120Copy the PCT to the
deployment_120directory on the jump box.Extract the PCT.
tar -xvf PPC-K8S-ALL_1.2.0.x.tarNote: For more information about the PCT, refer to My.Protegrity or the release notes.
3 - Deploying PPC
This section provides the steps to deploy the Protegrity Provisioned cluster (PPC) cluster. Review the prerequisites and choose the installation method that best fits your environment before you begin.
The PPC cluster can be deployed using one of the following methods:
Automated script-based installation: This method requires the
bootstrap.shscript to deploy the PPC cluster. The script installs the required software and dependencies, prompts to provide the required information, and deploys the cluster automatically.Manual component-based installation: This method requires to perform the deployment of each component to install the PPC cluster. The configuration files are edited to provide the required information and then deploy the cluster.
In-cluster deployment: This method is intended for users who already have an AKS cluster provisioned and managed outside of the PPC installer. Instead of creating a new cluster, the installer deploys PPC components onto the existing cluster. Cluster details must be provided to the installer, which uses them during Stage 05 to configure and deploy the PPC Helm charts.
Note: A PPC can be deployed in regions where minimum two zones are present.
3.1 - Automated script-based installation
Before you begin
Ensure that all the required resources are in the same resource-group. If the resources are in different resource groups, then ensure to move the resources to the same group before proceeding for PPC deployment.
The repository provides a bootstrap script that automatically installs or updates the following tools on the jump box:
- Azure CLI - Required to communicate with your Microsoft Azure account.
- Helm - Required to manage Kubernetes packages.
- jq - Required to parse JSON.
- kubectl - Required to communicate with the Kubernetes cluster.
- OpenTofu - Required to manage infrastructure as code.
- oras: Required to pull non‑container, generic OCI artifacts from the registry that are not handled by standard container tooling.
Using a Standard Deployment
By default, the PCT is configured to deploy a cluster using secure settings. To deploy a standard cluster, the configuration files must be modified accordingly. For the additional configurations, refer to Configuring for a Standard Deployment.
Architecture Selection
The step [1b] Select Node Architecture in the bootstrap script prompts to select the node architecture interactively during deployment.
- amd64 (x86-64)
| Node Pool | VM Size | vCPUs | Memory |
|---|---|---|---|
| System | Standard_D2as_v5 | 2 | 8 GB |
| User | Standard_D8as_v5 | 8 | 32 GB |
- arm64
| Node Pool | VM Size | vCPUs | Memory |
|---|---|---|---|
| System | Standard_D2ps_v5 | 2 | 8 GB |
| User | Standard_D8ps_v5 | 8 | 32 GB |
The bootstrap script prompts you to select the node architecture interactively during deployment (step 1b).
Deploying the PPC
The bootstrap script prompts for variables to be set to complete the deployment. Run the following command and follow the instructions on the screen:
./bootstrap.sh --cloud azure
The script prompts for the following variables.
Enter AKS Cluster Name
The following characters are allowed:
- Lowercase letters:
a-z - Numbers:
0-9 - Hyphens:
-
The following characters are not allowed:
- Uppercase letters:
A-Z - Underscores:
_ - Spaces
- Any special characters such as:
/ ? * + % ! @ # $ ^ & ( ) = [ ] { } : ; , . - Leading or trailing hyphens
- The cluster name must be 40 characters or fewer
Note: Ensure that the cluster name does not exceed 40 characters. Cluster names longer than this limit can cause the bootstrap script to fail in subsequent installation steps. If the installation fails because the cluster name exceeds the 40-character limit, correct the name and re-run the script.
- Correction: Choose a cluster name with 40 characters or fewer.
- Retry: Execute the installation command again with the updated name. The script will automatically handle the update and proceed with the bootstrap process.
After the cluster name is accepted, the script prompts you to select the node architecture.
[1b] Select Node Architecture
[1b] Select Node Architecture 1) amd64 (x86_64) — e.g. Standard_D8as_v5 2) arm64 (ARM/Ampere) — e.g. Standard_D8ps_v5Enter
1to selectamd64or2to selectarm64.Note: Select
amd64for standard Intel/AMD 64-bit environments. Selectarm64for ARM-based environments such as AWS Graviton instances.- Lowercase letters:
Querying for available Resource Groups
The script queries for the available Resource Groups.
Enter the Resource Group name from the table []
The script then automatically detects the location and subscription ID of the resource group.
Enter UAMI Resource ID
Provide the complete Azure resource ID for the UAMI used by AKS in the following format:
/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<identity-name>The UAMI client ID is detected automatically.
Enter AKS Subnet Resource ID
Provide the complete resource ID of the pre-existing subnet used for AKS nodes in the following format:
/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>Enter Private DNS Zone Resource ID
Provide the Private DNS zone ID used by the AKS private cluster in the following format:
/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/privateDnsZones/privatelink.<region>.azmk8s.ioThe script attempts to automatically detect network settings:
- Virtual network address space
- Service CIDR
- DNS service IP
- Pod CIDR
If the detection fails, then default values configured in the
terraform.tfvarsfile are used.Enter FQDN [name.domain.com]
This is the Fully Qualified Domain Name for the ingress.
Warning: Ensure that the FQDN does not exceed 50 characters and only the following characters are used:
- Lowercase letters:
a-z - Numbers:
0-9 - Special characters:
- .
- Lowercase letters:
Storage Account and Key Vault provisioning
Choose whether to use existing resources or create resources:
1) Use existing 2) Provision new via TofuEnter 1 if an encrypted Storage Account and Key Vault are already provisioned for this cluster. The installer prompts for the Storage Account name, Key Vault name, backup container, Key Vault key name, and the Velero UAMI Resource ID.
Enter 2 to allow the installer to create a Storage Account and Key Vault with the
velerocontainer, thepty-backup-keyencryption key, and a Velero UAMI automatically. Only the new resource names are required.a. Enter new Storage Account Name - Enter the Storage Account name. It must be globally unique, 3-24 chars, lowercase letters and digits only. b. Enter Blob Container Name - The default container isvelero. Leave blank to use the default container.c. Enter new Key Vault Name - Enter the Key Vault name. It supports only alphanumeric and hyphen characters.
Enter Velero UAMI Resource ID (required)
Enter the resource ID of the dedicated Velero User-Assigned Managed Identity (UAMI) in the format:
/subscriptions/<subscription-id>/resourceGroups/<velero-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<name>The script automatically validates the UAMI and detects the UAMI Client ID.
Enter OpenSearch UAMI Resource ID (required)
Enter the resource ID of the OpenSearch Velero User-Assigned Managed Identity (UAMI) in the format:
/subscriptions/<subscription-id>/resourceGroups/<opensearch-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<name>The script automatically validates the UAMI and detects the UAMI Client ID.
Enter Image Registry Endpoint
Enter
<Container_Registry_Path>, the container registry endpoint from where the container images are retrieved.Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used.Expected format:
<hostname>[:port].Do not include ‘https://’
Enter Registry Username
Enter the username for the registry mentioned in the previous step. Leave this entry blank if the registry does not require authentication.
Enter Registry Password or Access Token
Enter Password or Access Token for the registry.
Input is masked with
*characters. Press Enter to keep the current value.Leave this entry blank if the registry does not require authentication.
Enter Owner Email (for cluster tagging)
Enter email address in the format name@domain.tld. This email is used for the cluster ‘Owner’ tag and the platform owner contact.
Note: The cluster creation process can take 10-15 minutes.
If the session is terminated during installation due to network issues, power outage, and so on, then the installation stops. To restart the installation, run the script again:
# Navigate to setup directory ./bootstrap.sh --cloud azure
After the bootstrap script is completed, verify the cluster and workloads using the following commands:
# Confirm nodes are Ready
kubectl get nodes
# Confirm PPC workloads are Running
kubectl get pods -A
Configuring for a Standard Deployment
Note: The following instructions are optional and only required for configuring a standard PPC deployment on Azure. Skip these steps if you have already installed the secure settings.
By default, the PCT is configured to deploy a cluster using secure settings. To deploy a standard cluster, the configuration files must be modified.
The following files require changes:
| File | Setting | Value |
|---|---|---|
deployment/iac/azure/cluster/modules/02_aks_cluster/terraform.tfvars | fips_enabled | false |
deployment/iac/azure/cluster/modules/03_node_pool/terraform.tfvars | fips_enabled | false |
For a standard PPC deployment on Azure AKS, perform the following steps:
Ensure that you have downloaded and extracted the PCT. For more information, refer to Preparing for PPC deployment.
Update the settings in the AKS Cluster Module.
a. Navigate to the 02_aks_cluster module.
cd iac/azure/cluster/modules/02_aks_cluster/
b. Edit the terraform.tfvars file. Locate the fips_enabled parameter and set it to false.
fips_enabled = false
c. Save the file and exit the editor.
- Update the settings in the Node Pool Module.
a. Navigate to the 03_node_pool module.
cd iac/azure/cluster/modules/03_node_pool/
b. Edit the terraform.tfvars file. Locate the fips_enabled parameter and set it to false.
fips_enabled = false
c. Save the file and exit the editor.
- After completing all these configuration changes, proceed to deploy the cluster.
Note: The steps provided here update the security settings during installation. When following the installation method, do not revert or overwrite the values configured in this section. Keep
fips_enabledset tofalsein02_aks_clusterand03_node_pool.
3.2 - Manual component-based installation
This section is intended for enterprise customers who need full control over each stage of the AKS cluster deployment. Use this path when individual infrastructure stages must be reviewed or approved separately. Also use it when integration with an existing CI/CD pipeline is required. Use it when corporate change-management controls prevent running an all-in-one automated script. Each stage is self-contained and can be executed by different teams on the same jump box.
Review the Deploying PPC section to override settings for high availability, data safety, and security compliance before running tofu apply.
Note: If you are performing a standard deployment, ensure you completed Configuring PPC for a Standard Deployment before proceeding. Do not revert
fips_enabledtotruewhen performing the following steps.
Deploying PPC using component-based installation
To install PPC, complete the following steps in order. Each step is described in detail in the sections below.
| Step | Action | Description |
|---|---|---|
| # | Before you begin | Reviews the required access, permissions, and values to collect before installation. |
| 1 | Preparing a jump box | Prepares a jump box with network access to the AKS cluster and private API server endpoint. |
| 2 | Authenticating with Azure CLI | Authenticates with Azure using az login. Verifies access to the target subscription, resource group, managed identities, subnet, and private DNS zone. |
| 3 | Downloading and extracting the release PCT | Downloads and extracts the PPC release archive on the jump box. |
| 4 | Installing required tools | Installs the required CLI tools on the jump box using ./bootstrap-scripts/setup-devtools-azure.sh. |
| 5 | Provisioning backup storage and key vault | (Skip if using existing resources) Provisions a new Azure Storage Account, Blob container, Key Vault, and encryption key. These store PPC backup data and are created with the 00_backup_storage Terraform module. |
| 6 | Filling in each module’s terraform.tfvars | Configures and applies five Terraform modules in sequence to provision all PPC infrastructure components. |
| 6a | 01_identity module | Creates RBAC role assignments for the pre-existing User-Assigned Managed Identities (UAMIs) required by AKS, Velero, and OpenSearch. |
| 6b | 02_aks_cluster module | Provisions the private AKS cluster with a system node pool. It configures networking (Azure CNI Overlay and Cilium) and enables Workload Identity. It also creates federated identity credentials for Velero and OpenSearch. |
| 6c | 03_node_pool module | Creates a user node pool for application workloads with the specified VM size, architecture, and availability zone configuration. |
| 6d | 04_aks_addons module | Creates default and backup Kubernetes storage classes using Azure Managed Disks (Premium LRS). Removes the built-in default storage class annotation. |
| 6e | 05_helm_releases module | Deploys all PPC platform Helm charts including Velero, NFA/Eclipse, Insight, Reloader, and Envoy Gateway. This step may take 15–20 minutes. |
| 7 | Verifying the installation | Confirms all cluster nodes are in Ready state, and all pods are in Running state. |
Before you begin
Ensure to have the following prerequisites before proceeding with the installation.
Access and permissions
| Requirement | Details |
|---|---|
| Azure RBAC | Contributor and User Access Administrator on the target subscription or resource group. |
| Jump box | Debian or Red Hat VM in Azure with internet access to pull the release archive. |
Required Roles
The Azure principal must have AKS cluster admin access.
The required Azure RBAC Roles are listed in the following table:
| Role | Scope | Used by |
|---|---|---|
| Contributor | Resource group | Create AKS cluster, node pool, storage account, Key Vault |
| User Access Administrator | Resource group | Create role assignments (module 01) |
| Storage Blob Data Contributor | Backup storage account | Access state files in backend, upload module 00 state |
| Key Vault Administrator | Key Vault | Create Key Vault and keys (module 00) |
| AKS Cluster Admin | AKS cluster | Kubernetes API access for Helm, kubectl operations (modules 04, 05) |
Deployment Resource Group
All resources created by the installer are provisioned in a single Azure resource group. Specify this group using resource_group_name in each terraform.tfvars file. This resource group must exist before running the installer.
The following resources are created inside this resource group.
| Stage | Resources Created |
|---|---|
| 00_Backup Storage | Storage Account, Key Vault, Key Vault Key, Blob Container |
| 01_Identity | RBAC Role Assignments. References existing UAMIs, no new resources created. |
| 02_AKS Cluster | AKS Cluster, Federated Credentials |
| 03_Node Pool | AKS User Node Pool |
| 04_AKS Addons | Storage Classes, Cluster Add-ons |
| 05_Helm Releases | Kubernetes Namespaces, Secrets, Helm Charts |
Values to collect before starting
Gather the following values before populating each stage terraform.tfvars in Step 5.
| Value | Description | Example |
|---|---|---|
| Cluster name | Name of the AKS cluster to create or manage. | my-aks-cluster |
| Resource group | Azure resource group containing the AKS cluster and related resources. | <resource-group-name> |
| Azure subscription ID | Unique identifier of the Azure subscription used for deployment. | <subscription-id> |
| Azure region | Azure region where the cluster and resources are deployed. | eastus |
| UAMI resource ID | Full resource ID of the user-assigned managed identity for AKS appliance framework workloads. | /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<user-assigned-managed-identity-name> |
| AKS subnet resource ID | Full resource ID of the virtual network subnet where AKS nodes are deployed. | /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name> |
| Private DNS zone resource ID | Full resource ID of the private DNS zone used for AKS private cluster name resolution. | /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/privateDnsZones/privatelink.eastus.azmk8s.io |
| Storage account name | Azure Storage Account used for Velero backups and Terraform remote state. | existing name or provisioned in Step 4 |
| Backup container name | Blob container within the storage account used by Velero for cluster backups. | velero |
| Key Vault name | Azure Key Vault that holds the backup encryption key. | existing name or provisioned in Step 4 |
| Key Vault key name | Name of the encryption key inside the Key Vault used by Velero. | pty-backup-key |
| Velero UAMI resource ID | Full resource ID of the user-assigned managed identity for Velero backup and restore operations. | /subscriptions/<subscription-id>/resourceGroups/<velero-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<velero-managed-identity-name> |
| OpenSearch UAMI resource ID | Full resource ID of the user-assigned managed identity for OpenSearch workload identity. | /subscriptions/<subscription-id>/resourceGroups/<opensearch-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<opensearch-managed-identity-name> |
| Ingress FQDN | Fully qualified domain name used by the ingress controller to expose cluster services externally. | myapp.example.com |
| Image registry endpoint | Endpoint of the container image registry from which cluster images are pulled. Note: If deploying from the Protegrity Container Registry, use registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. | <Container_Registry_Path> |
| Registry username & password | Credentials for authenticating with the container image registry. | provided by the team |
Optional: Using a Standard Deployment
By default, the PCT is configured to deploy a cluster using secure settings. To deploy a standard cluster, the configuration files must be modified accordingly. For the additional configurations, refer to Configuring for a Standard Deployment.
Deploying PPC
To deploy PPC using component-based installation, perform the following 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. Authenticating with Azure CLI
To authenticate with the Azure CLI on the jump box, run the following command:
az login
az account show
Note: CLI login using Single Sign-On (SSO) is not supported. Use
az login --use-device-codeor authenticate as a Service Principal.
Ensure the target subscription, resource group, managed identities, subnet, and private DNS zone are accessible before continuing.
3. Downloading and extracting the release PCT
To download and extract the PCT, refer to Preparing for PPC deployment.
4. Installing required tools
To install the required tools from the extracted PPC release archive, run the following command:
./bootstrap-scripts/setup-devtools-azure.sh
| Tool Name | Description | Minimum Required Version |
|---|---|---|
| OpenTofu | Open-source Terraform fork used to provision and manage infrastructure | OpenTofu v1.11.5 |
| Azure CLI | Command-line tool for managing Azure resources | 2.90.0 |
| kubectl | Kubernetes command-line tool for interacting with the cluster | v1.37.1 |
| Helm | Kubernetes package manager for deploying Helm charts | v3.22.0+g144ca65 |
| skopeo | Tool for inspecting and copying container images between registries | skopeo version 1.9.3 |
| jq | Lightweight command-line JSON processor | jq-1.6 |
| bc | Arbitrary-precision calculator used in shell scripts | bc 1.07.1 |
| ssh-keygen | Tool for generating SSH key pairs used for secure access | OpenSSH_9.2p1 Debian-2+deb12u10, OpenSSL 3.0.20 7 Apr 2026 |
| oras | OCI Registry As Storage client for pushing and pulling artifacts | 1.3.4 |
| cmctl | Command-line tool for managing cert-manager resources | v2.6.1 |
5. Provisioning backup storage and key vault
This is an optional step.
Note: Skip this step if an Azure Storage Account, backup container, Key Vault, and key already exist for this cluster. Note these values. They will be needed in next steps.
- Navigate to the
00_backup_storagedirectory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/00_backup_storage"
- Open
terraform.tfvarsand fill in the required values.
resource_group_name = "<resource-group-name>"
aks_cluster_name = "<cluster-name>"
storage_account_name = "<storage-account-name>"
storage_container_name = "velero"
key_vault_name = "<key-vault-name>"
key_name = "pty-backup-key"
azure_subscription_id = "<subscription-id>"
azure_location = "<region>" # e.g. eastus
Save the file and exit the editor.
To apply the terraform configuration, run the following command:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
- Note the Storage Account, container, Key Vault, and key values for future steps.
6. Filling in each module’s terraform.tfvars
Each module under iac/azure/cluster/modules/ contains its own terraform.tfvars file. There is no single shared configuration file. The terraform.tfvars file in every module must be updated before running the deployment.
Verify that the following values are the same across all modules:
resource_group_nameaks_cluster_nameazure_subscription_idstorage_account_namestorage_container_name
01_identity module
This stage creates RBAC role assignments for the pre-existing User-Assigned Managed Identities (UAMIs) required by AKS, Velero, and OpenSearch.
| Resource | Purpose |
|---|---|
| Managed Identity Operator role | Allows AKS to assign the UAMI to nodes. |
| Virtual Machine Contributor role | Allows AKS to manage VMs in the node resource group. |
| Disk Snapshot Contributor role | Allows Velero to create and manage disk snapshots. |
| Storage Blob Data Contributor (Velero) | Allows Velero to read/write backup blobs. |
| Key Vault Crypto User role | Allows Velero to encrypt/decrypt backups with the Key Vault key. |
| Storage Blob Data Contributor (OpenSearch) | Allows OpenSearch to store snapshot data in blob storage. |
To update the 01_identity module, perform the following steps:
a. Navigate to the iac/azure/cluster/modules/01_identity/ directory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/01_identity/"
b. Edit the terraform.tfvars file to provide the required values.
# -------------------------------------------------
# Common (backend + provider — same value in all stages)
# -------------------------------------------------
resource_group_name = "<resource-group-name>" # e.g. "aks-rg-prod"
aks_cluster_name = "<cluster-name>" # e.g. "prod-aks-cluster"
azure_subscription_id = "<subscription-id>" # e.g. "1e9ef7b6-cdc4-4a6b-98f7-a408ac1e19e0"
storage_account_name = "<storage-account-name>" # e.g. "myclusterstateaccount"
storage_container_name = "velero"
# -------------------------------------------------
# Pre-existing managed identities (provided by IT)
# -------------------------------------------------
uami_id = "</subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<user-assigned-managed-identity-name>>"
velero_uami_id = "</subscriptions/<subscription-id>/resourceGroups/<velero-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<velero-managed-identity-name>>" # required
opensearch_uami_id = "</subscriptions/<subscription-id>/resourceGroups/<opensearch-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<opensearch-managed-identity-name>>" # required
# -------------------------------------------------
# Key Vault (leave empty to skip KV role assignment)
# -------------------------------------------------
key_vault_name = "<key-vault-name>" # e.g. "my-key-vault"
c. Save the file and exit the editor.
d. To initialize, plan, and apply the changes, run the following commands:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
e. To verify the resources created in this stage, run the following commands:
Retrieve the Principal ID of the AKS User-Assigned Managed Identity (UAMI):
az identity show \
--ids "<uami-resource-id>" \
--query principalId \
--output tsv
Use the returned Principal ID to verify the role assignments:
az role assignment list \
--assignee "<aks-uami-principal-id>" \
--output table
Retrieve the Principal ID of the Velero UAMI:
az identity show \
--ids "<velero-uami-resource-id>" \
--query principalId \
--output tsv
Use the returned Principal ID to verify the role assignments:
az role assignment list \
--assignee "<velero-uami-principal-id>" \
--output table
Retrieve the Principal ID of the OpenSearch UAMI:
az identity show \
--ids "<opensearch-uami-resource-id>" \
--query principalId \
--output tsv
Use the returned Principal ID to verify the role assignments:
az role assignment list \
--assignee "<opensearch-uami-principal-id>" \
--output table
02_aks_cluster module
This stage provisions the private AKS cluster with a system node pool. It configures networking using Azure CNI Overlay and Cilium, and enables Workload Identity. It also creates federated identity credentials for Velero and OpenSearch.
| Resource | Purpose |
|---|---|
| AKS cluster | Private Kubernetes control plane with OIDC issuer and Workload Identity enabled. |
| System node pool | 2-node pool for core Kubernetes components, such as, CoreDNS, metrics-server, and so on. |
| Federated credential (Velero) | Allows the Velero service account to authenticate as the Velero UAMI. |
| Federated credential (OpenSearch) | Allows the OpenSearch service account to authenticate as the OpenSearch UAMI. |
| Kubeconfig context | Auto-configures kubectl access to the new cluster. |
To update the 02_aks_cluster module, perform the following steps:
a. Navigate to the iac/azure/cluster/modules/02_aks_cluster/ directory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/02_aks_cluster/"
Note (standard deployment): If you are deploying a standard cluster, ensure
fips_enabledremainsfalse. For more information, refer to Configuring PPC for a Standard Deployment. Do not change this value totrue.
b. Edit the terraform.tfvars file to provide the required values.
# -------------------------------------------------
# Common (backend + provider — same value in all stages)
# -------------------------------------------------
resource_group_name = "<resource-group-name>" # e.g. "aks-rg-prod"
aks_cluster_name = "<cluster-name>" # e.g. "prod-aks-cluster"
azure_subscription_id = "<subscription-id>" # e.g. "1e9ef7b6-cdc4-4a6b-98f7-a408ac1e19e0"
storage_account_name = "<storage-account-name>" # e.g. "myclusterstateaccount"
storage_container_name = "velero"
# -------------------------------------------------
# Identity (UAMI for kubelet and federated credentials)
# -------------------------------------------------
uami_id = "</subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<user-assigned-managed-identity-name>>" # full UAMI resource ID (same as Stage 01)
velero_uami_id = "</subscriptions/<subscription-id>/resourceGroups/<velero-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<velero-managed-identity-name>>" # full Velero UAMI resource ID (for federated credential)
opensearch_uami_id = "</subscriptions/<subscription-id>/resourceGroups/<opensearch-resource-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<opensearch-managed-identity-name>>" # full OpenSearch UAMI resource ID (for federated credential)
# -------------------------------------------------
# Cluster
# -------------------------------------------------
azure_location = "<region>" # e.g. "eastus" (auto-detected from resource group)
subnet_id = "</subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>>" # e.g. "/subscriptions/.../subnets/snet-aks-applianceframework"
private_dns_zone_id = "</subscriptions/<subscription-id>/resourceGroups/<dns-resource-group>/providers/Microsoft.Network/privateDnsZones/privatelink.eastus.azmk8s.io>" # e.g. "/subscriptions/.../privateDnsZones/privatelink.eastus.azmk8s.io"
# -------------------------------------------------
# Networking (service CIDR + DNS IP)
# -------------------------------------------------
service_cidr = "<10.0.0.0/16>" # auto-derived by updatevartf.sh (non-overlapping with the VNet)
dns_service_ip = "<10.220.0.10>" # auto-derived: the .10 host of the chosen service_cidr
pod_cidr = "<10.0.0.0/16>" # auto-derived: non-overlapping with the VNet and service_cidr
# -------------------------------------------------
# System node pool
# -------------------------------------------------
architecture = "amd64" # amd64 or arm64
system_node_pool_vm_size = "" # leave empty to auto-select based on architecture
system_node_pool_node_count = 2
system_node_pool_disk_size_gb = 50
system_node_pool_os_sku = "AzureLinux"
system_node_pool_zones = ["1", "2", "3"]
fips_enabled = true # set false for a non-FIPS node OS image (immutable)
# -------------------------------------------------
# Ownership / tagging
# -------------------------------------------------
owner_email = "<name@domain.tld>" # optional; blank = auto-detect from the Azure CLI identity
c. Save the file and exit the editor.
d. To initialize, plan, and apply the changes, run the following commands:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
e. To verify the resources created in this stage, run the following commands:
# Confirm the AKS cluster is in Succeeded state
az aks show --name <cluster-name> --resource-group <resource-group> \
--query "{Name:name, State:provisioningState, Version:kubernetesVersion, Fqdn:privateFqdn}" \
--output table
A sample output is displayed below:
Name State Version Fqdn
---------------- --------- --------- -----------------------------------------------
<cluster-name> Succeeded 1.35 <cluster-name>.privatelink.<region>.azmk8s.io
# Verify kubectl can reach the cluster
kubectl get nodes # expect 2 system nodes in Ready state
# Verify federated credentials exist
az identity federated-credential list \
--identity-name <velero-uami-name> \
--resource-group <velero-uami-resource-group> --output table
az identity federated-credential list \
--identity-name <opensearch-uami-name> \
--resource-group <opensearch-uami-resource-group> --output table
03_node_pool module
This stage creates a user-managed node pool for application workloads. Node Auto Provisioning (NAP) handles autoscaling; no cluster autoscaler is configured on this pool.
| Resource | Purpose |
|---|---|
| User node pool (userpool) | Worker nodes for NFA platform, Insight, and other application pods. |
To update the 03_node_pool module, perform the following steps:
a. Navigate to the iac/azure/cluster/modules/03_node_pool/ directory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/03_node_pool/"
Note (standard deployment): If you are deploying a standard cluster, ensure
fips_enabledremainsfalseas configured in Configuring PPC for a Standard Deployment. Do not change this value totrue.
b. Edit the terraform.tfvars file to provide the required values.
# -------------------------------------------------
# Common (backend + provider — same value in all stages)
# -------------------------------------------------
resource_group_name = "<resource-group-name>" # e.g. "aks-rg-prod"
aks_cluster_name = "<cluster-name>" # e.g. "prod-aks-cluster"
azure_subscription_id = "<subscription-id>" # e.g. "1e9ef7b6-cdc4-4a6b-98f7-a408ac1e19e0"
storage_account_name = "<storage-account-name>" # e.g. "myclusterstateaccount"
storage_container_name = "velero"
# -------------------------------------------------
# Node pool
# -------------------------------------------------
subnet_id = "</subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>>" # same subnet as AKS nodes (Stage 02)
architecture = "amd64" # amd64 or arm64
vm_size = "" # leave empty for architecture default
node_pool_disk_size_gb = 120
node_pool_desired_size = 3
node_pool_zones = ["1", "2", "3"]
fips_enabled = true # set false for a non-FIPS node OS image (immutable)
c. Save the file and exit the editor.
d. To initialize, plan, and apply the changes, run the following commands:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
Expected time for this stage is approximately 5 to 10 minutes for node pool provisioning.
e. To verify the resources created in this stage, run the following commands:
# Confirm the user node pool exists and is Succeeded
az aks nodepool show --cluster-name <cluster-name> \
--resource-group <resource-group> --name userpool \
--query "{Name:name, State:provisioningState, Count:count, VmSize:vmSize, OsSku:osSku}" \
--output table
A sample output is displayed below:
Name State Count VmSize OsSku
-------- --------- ------- ---------- ----------
userpool Succeeded <count> <vm-size> AzureLinux
# Verify all nodes are Ready (system + user nodes)
kubectl get nodes -o wide
# Confirm user pool nodes have the expected label
kubectl get nodes -l agentpool=userpool
04_aks_addons module
This stage creates the default and backup Kubernetes storage classes using Azure Managed Disks (Premium LRS). It also removes the built-in default storage class annotation.
| Resource | Purpose |
|---|---|
| ebs-sc storage class | Default storage class, such as, expandable, Premium LRS, WaitForFirstConsumer. |
| ebs-bkp storage class | Backup storage class used by Velero for PVC snapshots. |
| Remove built-in default SC | Ensures only ebs-sc is marked as the cluster default. |
To update the 04_aks_addons module, perform the following steps:
a. Navigate to the iac/azure/cluster/modules/04_aks_addons/ directory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/04_aks_addons/"
b. Edit the terraform.tfvars file to provide the required values.
# -------------------------------------------------
# Common (backend + provider — same value in all stages)
# -------------------------------------------------
resource_group_name = "<resource-group-name>" # e.g. "aks-rg-prod"
aks_cluster_name = "<cluster-name>" # e.g. "prod-aks-cluster"
azure_subscription_id = "<subscription-id>" # e.g. "1e9ef7b6-cdc4-4a6b-98f7-a408ac1e19e0"
storage_account_name = "<storage-account-name>" # e.g. "myclusterstateaccount"
storage_container_name = "velero"
# -------------------------------------------------
# Storage classes (must match Stage 05's terraform.tfvars)
# -------------------------------------------------
storage_class_name = "<storage-class-name>"
backup_storage_class_name = "<backup-storage-class-name>"
c. Save the file and exit the editor.
d. To initialize, plan, and apply the changes, run the following commands:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
e. To verify the resources created in this stage, run the following commands:
# List storage classes and confirm ebs-sc is the default
kubectl get storageclass
# Verify ebs-sc details
kubectl describe storageclass ebs-sc
# Confirm the built-in 'default' storage class is no longer the default
kubectl get storageclass default -o jsonpath='{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}'
# expected output: empty or "false"
A sample output is displayed below:
storage_class_names = {
"backup" = "ebs-bkp"
"default" = "ebs-sc"
}
05_helm_releases module
This stage deploys all application Helm charts and configures Velero backup with the Azure plugin. It also bootstraps the NFA platform and Insight analytics stack.
| Resource | Purpose |
|---|---|
| Velero Helm release | Backup and disaster recovery with Azure Blob Storage and disk snapshots. |
| NFA / Eclipse Helm release | Main platform stack, such as, API Gateway, cert-manager, Keycloak, services. |
| Insight Helm release | Log aggregation and analytics, such as, Dashboards, Fluentd, OpenSearch. |
| Reloader Helm release | Auto-restarts workloads on ConfigMap or Secret changes. |
| Envoy Gateway Helm release | API gateway and ingress proxy. |
| VolumeSnapshotClass | CSI snapshot class (csi-azure-vsc) for Azure Disk snapshots. |
| Namespaces & registry secrets | Creates namespaces with image-pull secrets for the private registry. |
To update the 05_helm_releases module, perform the following steps:
a. Navigate to the iac/azure/cluster/modules/05_helm_releases/ directory.
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/azure/cluster/modules/05_helm_releases/"
b. Run the following commands and note the values:
# Get the Velero Client ID
az identity show \
--name <velero-managed-identity-name> \
--resource-group <resource-group-name> \
--query clientId \
-o tsv
# Get the OpenSearch Client ID
az identity show \
--name <opensearch-managed-identity-name> \
--resource-group <resource-group-name> \
--query clientId \
-o tsv
c. Edit the terraform.tfvars file to provide the required values.
Important: The value for
harbor_secretfield must always beharbor-secret.
Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used.
# -------------------------------------------------
# Common (backend + provider — same value in all stages)
# -------------------------------------------------
resource_group_name = "<resource-group-name>" # e.g. "aks-rg-prod"
aks_cluster_name = "<cluster-name>" # e.g. "prod-aks-cluster"
azure_subscription_id = "<subscription-id>" # e.g. "1e9ef7b6-cdc4-4a6b-98f7-a408ac1e19e0"
storage_account_name = "<storage-account-name>" # e.g. "myclusterstateaccount"
storage_container_name = "velero"
check_prev_stage = true # set false to skip verifying Stage 04 was applied before Stage 05
# -------------------------------------------------
# Storage classes (must match Stage 04's terraform.tfvars)
# -------------------------------------------------
storage_class_name = "<storage-class-name>"
backup_storage_class_name = "<backup-storage-class-name>"
# -------------------------------------------------
# Networking
# -------------------------------------------------
subnet_id = "</subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>>" # same subnet as Stages 02/03 (for VNet address space lookup)
pod_cidr = "" # optional override; empty = auto-detected from the live AKS network profile
architecture = "amd64" # amd64 or arm64
node_os = "AzureLinux_FIPS" # should mirror stage-03 user node pool os_sku + fips_enabled
node_pool_name = "<node-pool-name>" # must match node_pool_name in Stage 03's terraform.tfvars
# -------------------------------------------------
# Registry
# -------------------------------------------------
global_image_reg = "<Container_Registry_Path>"
harbor_secret = "harbor-secret"
ingress_fqdn = "<FQDN>" # e.g. "apps.example.com"
# -------------------------------------------------
# Ownership / tagging
# -------------------------------------------------
owner_email = "<name@domain.tld>" # optional; blank = auto-detect from the Azure CLI identity
# -------------------------------------------------
# CLI users (enrolled via bootstrap.sh access add-cli-user)
# -------------------------------------------------
cli_user_public_keys = {} # e.g. { "jane.doe" = "ssh-rsa AAAA... jane.doe@host" } — on FIPS clusters only RSA (>=2048 bits) and ECDSA keys are accepted, not Ed25519/DSA
# cli_user_public_keys is an optional map of additional CLI users
# who should be granted SSH access to the cluster. Add entries
# as username-to-public-key pairs, for example: {"jane.doe" = "ssh-rsa AAAA... jane.doe@host"}
# This is used to enroll additional users through bootstrap.sh access add-cli-user.
# On FIPS-enabled clusters, only RSA keys with a minimum length of 2048 bits
# and ECDSA keys are accepted. Ed25519 and DSA keys are not supported.
# -------------------------------------------------
# Restore / backup
# -------------------------------------------------
restore = false # set to true to restore from a previous backup
backup_name = "authnz-postgresql-schedule-backup" # Velero backup name used when restore = true
insight_backup_name = "" # Insight Velero backup name (K8s resources only); leave empty to auto-resolve latest
# -------------------------------------------------
# Workload Identity
# -------------------------------------------------
velero_uami_client_id = "<velero_uami_client_id>" # client ID of the Velero UAMI
opensearch_uami_client_id = "<opensearch_uami_client_id>" # client ID of the OpenSearch UAMI
c. Save the file and exit the editor.
d. This step must be performed only if registry needs an authentication. Do not put them in the tfvars file.
To enter registry credentials using the environment variables, run the following commands:
export TF_VAR_username="<registry-username>"
export TF_VAR_password="<registry-password>"
e. To initialize, plan, and apply the changes, run the following commands:
tofu init
tofu plan # review the proposed changes before applying
tofu apply # when prompted with "Enter a value:", type "yes"
Expected time for this stage is approximately 15 to 20 minutes.
f. To verify the resources created in this stage, run the following commands:
# Confirm all Helm releases are deployed
helm list -A
# Verify Velero is running
kubectl get pods -n pty-backup-recovery
# Verify NFA platform pods
kubectl get pods -A
# Verify Insight pods
kubectl get pods -n pty-insight
# Verify Envoy Gateway
kubectl get pods -n api-gateway
# Verify VolumeSnapshotClass exists
kubectl get volumesnapshotclass
# Check all pods across the cluster are healthy
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded
# Confirm the ingress gateway has an IP
kubectl get gateway -A
A sample output is displayed below:
nfa_release_status = "deployed"
user_svc_private_key = <sensitive>
velero_release_status = "deployed"
All the nodes must be in the Ready state. All the pods must be in the Running or Completed state.
Verifying the installation
To verify the installation, run the following command:
kubectl get nodes
kubectl get pods -A
Configuring for a Standard Deployment
Note: The following instructions are optional and only required for configuring a standard PPC deployment on Azure. Skip these steps if you have already installed the secure settings.
By default, the PCT is configured to deploy a cluster using secure settings. To deploy a standard cluster, the configuration files must be modified.
The following files require changes:
| File | Setting | Value |
|---|---|---|
deployment/iac/azure/cluster/modules/02_aks_cluster/terraform.tfvars | fips_enabled | false |
deployment/iac/azure/cluster/modules/03_node_pool/terraform.tfvars | fips_enabled | false |
For a standard PPC deployment on Azure AKS, perform the following steps:
Ensure that you have downloaded and extracted the PCT. For more information, refer to Preparing for PPC deployment.
Update the settings in the AKS Cluster Module.
a. Navigate to the 02_aks_cluster module.
cd iac/azure/cluster/modules/02_aks_cluster/
b. Edit the terraform.tfvars file. Locate the fips_enabled parameter and set it to false.
fips_enabled = false
c. Save the file and exit the editor.
- Update the settings in the Node Pool Module.
a. Navigate to the 03_node_pool module.
cd iac/azure/cluster/modules/03_node_pool/
b. Edit the terraform.tfvars file. Locate the fips_enabled parameter and set it to false.
fips_enabled = false
c. Save the file and exit the editor.
- After completing all these configuration changes, proceed to deploy the cluster.
Note: The steps provided here update the security settings during installation. When following the installation method, do not revert or overwrite the values configured in this section. Keep
fips_enabledset tofalsein02_aks_clusterand03_node_pool.
3.3 - 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.