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.sh script 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.
1 - Automated script-based installation
Complete the steps provided in this section to deploy PPC in Microsoft Azure Kubernetes Service (AKS).
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.
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_v5
Enter 1 to select amd64 or 2 to select arm64.
Note: Select amd64 for standard Intel/AMD 64-bit environments. Select arm64 for ARM-based environments such as AWS Graviton instances.
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:
The 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.tfvars file 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: - .
Storage Account and Key Vault provisioning
Choose whether to use existing resources or create resources:
1) Use existing
2) Provision new via Tofu
Enter 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 velero container, the pty-backup-key encryption 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 is velero. 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:
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 Readykubectl get nodes
# Confirm PPC workloads are Runningkubectl 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.
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_enabled set to false in 02_aks_cluster and 03_node_pool.
2 - Manual component-based installation
Complete the steps provided in this section to update the configuration files and deploy PPC in Microsoft Azure Kubernetes Service (AKS).
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_enabled to true when 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.
(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.
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.
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.
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-code or authenticate as a Service Principal.
Ensure the target subscription, resource group, managed identities, subnet, and private DNS zone are accessible before continuing.
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_storage directory.
exportPPC_DEPLOY_DIR=<path to PPC deployment directory>
cd"$PPC_DEPLOY_DIR/iac/azure/cluster/modules/00_backup_storage"
Open terraform.tfvars and fill in the required values.
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_name
aks_cluster_name
azure_subscription_id
storage_account_name
storage_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.
exportPPC_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.
exportPPC_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_enabled remains false. For more information, refer to Configuring PPC for a Standard Deployment. Do not change this value to true.
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_cidrpod_cidr="<10.0.0.0/16>"# auto-derived: non-overlapping with the VNet and service_cidr# -------------------------------------------------# System node pool# -------------------------------------------------architecture="amd64"# amd64 or arm64system_node_pool_vm_size=""# leave empty to auto-select based on architecturesystem_node_pool_node_count=2system_node_pool_disk_size_gb=50system_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 stateaz 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 clusterkubectl get nodes # expect 2 system nodes in Ready state
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.
exportPPC_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_enabled remains false as configured in Configuring PPC for a Standard Deployment. Do not change this value to true.
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 Succeededaz 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 labelkubectl 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.
exportPPC_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 defaultkubectl get storageclass
# Confirm the built-in 'default' storage class is no longer the defaultkubectl get storageclass default -o jsonpath='{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}'# expected output: empty or "false"
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.
exportPPC_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 IDaz identity show \
--name <velero-managed-identity-name> \
--resource-group <resource-group-name> \
--query clientId \
-o tsv
# Get the OpenSearch Client IDaz 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_secret field must always be harbor-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 profilearchitecture="amd64"# amd64 or arm64node_os="AzureLinux_FIPS"# should mirror stage-03 user node pool os_sku + fips_enablednode_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 backupbackup_name="authnz-postgresql-schedule-backup"# Velero backup name used when restore = trueinsight_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:
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.
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_enabled set to false in 02_aks_cluster and 03_node_pool.
3 - In-cluster deployment
Complete the steps provided in this section to deploy PPC onto an existing Azure Kubernetes Service (AKS) cluster using 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.
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 Contributor on the subnet and Private DNS Zone Contributor on 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.
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-code or 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 ...
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_cidr must 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 podCidr indicates 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.
Note: Registry credentials are passed as environment variables (TF_VAR_username and TF_VAR_password) and are not set directly in terraform.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.
Note: Bash variable names cannot contain hyphens. Use $RESOURCE_GROUP, not $RESOURCE-GROUP. The subject strings must be exact.
7.5 Node architecture
Check the architecture of the cluster nodes:
kubectl get nodes -L kubernetes.io/arch
Set architecture in 05_helm_releases/terraform.tfvars to match the kubernetes.io/arch values:
architecture="arm64" # For *ps_v5 (Arm) VM sizes; use "amd64"(default)for*as_v5/x86sizes.
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.
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.
Add the following variables to terraform.tfvars before allowing Stage 05 to apply.
run_readiness_check=truecheck_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 plan or tofu apply, review all values in terraform.tfvars and 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 Readykubectl get nodes
# Confirm pods are Runningkubectl 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.
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 create command addresses all of these immutable requirements.