The installation process includes preparing the cluster, provisioning the required infrastructure with OpenTofu, deploying the umbrella Helm chart, and verifying the gateway and its bundled dependencies.
This is the multi-page printable view of this section. Click here to print.
Installation
- 1: Prerequisites
- 2: Install
1 - Prerequisites
Ensure that all PPC prerequisites for AWS and PPC prerequisites for Azure are met.
Required Tools
| Tool | Version | Notes |
|---|---|---|
| OpenTofu | >= 1.10.0 | Used to provision cloud resources |
| Helm | >= 3.12 | Used to deploy the chart |
| kubectl | any | Required for validation; must be configured for the target cluster |
Required cluster prerequisites
| Prerequisite | Details |
|---|---|
| Kubernetes >= 1.27 | EKS |
| StorageClass | ebs-sc (AWS) - verify: kubectl get storageclass |
AWS — eks-pod-identity-agent addon | DaemonSet running on each node |
| AWS — Karpenter >= 1.0 | Installed in karpenter namespace (if using node isolation) |
StorageClass note: If your cluster uses different StorageClass names, override using
--set database.persistence.storageClass=<name>during Helm install.
| Prerequisite | Details |
|---|---|
| Kubernetes >= 1.27 | AKS |
| StorageClass | managed-csi-premium (Azure) - verify: kubectl get storageclass |
StorageClass note: If your cluster uses different StorageClass names, override using
--set database.persistence.storageClass=<name>during Helm install.
Configuration reference
Key values.yaml parameters
| Key | Default | Description |
|---|---|---|
cloudProvider | "" | aws |
database.auth.mlopsPassword | "" | Required on first install |
database.auth.jobstatePassword | "" | Required on first install |
database.auth.hostAuthMethod | trust | POSTGRES_HOST_AUTH_METHOD for PostgreSQL init |
database.persistence.storageClass | "" | Set per cloud: ebs-sc |
database.persistence.size | 20Gi | PVC size |
database.persistence.retentionPolicy.whenDeleted | Retain | Keep PVC on uninstall |
karpenter.enabled | true | Inject node affinity/tolerations for Karpenter nodes |
anonapp.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
anonapp.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
database.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
database.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
dask.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
dask.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
serviceaccount.name | anon-service-account | Must match Pod Identity association |
| Key | Default | Description |
|---|---|---|
cloudProvider | "" | azure |
database.auth.mlopsPassword | "" | Required on first install |
database.auth.jobstatePassword | "" | Required on first install |
database.auth.hostAuthMethod | trust | POSTGRES_HOST_AUTH_METHOD for PostgreSQL init |
database.persistence.storageClass | "" | Set per cloud: managed-csi-premium |
database.persistence.size | 20Gi | PVC size |
database.persistence.retentionPolicy.whenDeleted | Retain | Keep PVC on uninstall |
karpenter.enabled | true | Inject node affinity/tolerations for Karpenter nodes |
anonapp.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
anonapp.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
database.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
database.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
dask.affinity | {} | Injected by OpenTofu when karpenter.enabled=true |
dask.tolerations | [] | Injected by OpenTofu when karpenter.enabled=true |
serviceaccount.name | anon-service-account | Must match Pod Identity association |
Appendix: Required cloud permissions
Required AWS permissions
If you encounter an AccessDenied error during installation, request the following permissions for your IAM user or role.
IAM
| Permission | Purpose |
|---|---|
iam:CreatePolicy / iam:DeletePolicy / iam:GetPolicy | Create and manage the S3 access policy |
iam:CreateRole / iam:DeleteRole / iam:GetRole | Create and manage the Pod Identity IAM role |
iam:AttachRolePolicy / iam:DetachRolePolicy | Attach the S3 policy to the role |
EKS
| Permission | Purpose |
|---|---|
eks:DescribeCluster | Read cluster details |
eks:DescribeAddon | Verify eks-pod-identity-agent is installed |
eks:CreatePodIdentityAssociation / eks:DeletePodIdentityAssociation / eks:DescribePodIdentityAssociation | Associate the IAM role with the ServiceAccount |
S3
| Permission | Purpose |
|---|---|
s3:CreateBucket / s3:DeleteBucket | Create and manage the models bucket |
s3:PutBucketPolicy / s3:GetBucketPolicy | Apply bucket policy |
s3:PutObject / s3:GetObject / s3:DeleteObject | Read/write model files |
Required Azure permissions
If you encounter an AuthorizationFailed error during installation, request the following permissions.
| Permission | Purpose |
|---|---|
Microsoft.ManagedIdentity/userAssignedIdentities/write | Create the Managed Identity |
Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/write | Create the Federated Identity Credential for Workload Identity |
Microsoft.Storage/storageAccounts/write | Create the Storage Account |
Microsoft.Storage/storageAccounts/blobServices/containers/write | Create the blob container for models |
Microsoft.Authorization/roleAssignments/write | Assign Storage Blob Data Contributor role |
2 - Install
This project deploys the Anonymization service on Amazon EKS as part of the AI Team Edition.
Install order: prerequisites → OpenTofu infrastructure configuration → Helm deployment.
OCI registry authentication
OpenTofu OCI modules and Helm charts may require authentication. If the registry requires a login, authenticate before running tofu init or helm upgrade --install:
echo "<password>" | helm registry login <Container_Registry_Path> --username "<username>" --password-stdin
Note:
- Set
registry_auth_enabled = truefor Protegrity container registry. Set it tofalseonly for a public or pre-authenticated registry.- If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used.- Verify that you are logged in to the registry before proceeding.
Deployment Steps
Step 1 - Provision cloud resources with OpenTofu
The anonymization OpenTofu module provisions all cloud prerequisites and writes an anonymization-values.yaml file with cloud-specific Helm overrides.
AWS (EKS)
The module creates:
- S3 bucket (name provided via
bucket_namevariable — must be globally unique) - IAM role + Pod Identity association →
anon-service-accountServiceAccount EC2NodeClassandNodePool(Bottlerocket FIPS, isolated nodes)anonymization-values.yaml— Helm overrides file
Azure (AKS)
The module creates:
- Storage Account + blob container for model storage
- Managed Identity + Workload Identity federated credential →
anon-service-accountServiceAccount anonymization-values.yaml— Helm overrides file
You do not have a root module
Create a new directory with a single main.tf:
Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used.
mkdir anon-install && cd anon-install
cat > main.tf <<'EOF'
terraform {
required_version = "~> 1.10"
required_providers {
aws = { source = "registry.opentofu.org/hashicorp/aws", version = "~> 5.0" }
kubernetes = { source = "registry.opentofu.org/hashicorp/kubernetes", version = "~> 2.35" }
}
}
variable "cluster_name" {
type = string
}
variable "bucket_name" {
type = string
}
variable "chart_version" {
type = string
default = ""
}
data "aws_eks_cluster" "this" { name = var.cluster_name }
data "aws_eks_cluster_auth" "this" { name = var.cluster_name }
provider "kubernetes" {
host = data.aws_eks_cluster.this.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.this.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.this.token
}
module "anonymization" {
source = "oci://<Container_Registry_Path>/anonymization/anonymization-server/opentofu/anonymization?tag=aws-2.1.0"
cluster_name = var.cluster_name
oci_host = "<Container_Registry_Path>"
bucket_name = var.bucket_name
chart_version = var.chart_version
registry_auth_enabled = true # required for registry.protegrity.com; set false only for public/pre-authenticated registries
}
output "helm_install" { value = module.anonymization.helm_install }
output "helm_values" { value = module.anonymization.helm_values }
EOF
tofu init
tofu apply \
-var="cluster_name=<your-cluster-name>" \
-var="bucket_name=<globally-unique-bucket>" \
-var="chart_version=2.1.0"
This writes anonymization-values.yaml (S3, IAM/Pod Identity, Karpenter node isolation, affinity/tolerations already filled in).
Display both generated outputs:
tofu output
Create a new directory with a single main.tf:
Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used.
mkdir anon-install && cd anon-install
cat > main.tf <<'EOF'
terraform {
required_version = "~> 1.10"
required_providers {
azurerm = {
source = "registry.opentofu.org/hashicorp/azurerm"
version = "~> 5.7"
}
kubernetes = {
source = "registry.opentofu.org/hashicorp/kubernetes"
version = "~> 2.35"
}
}
}
variable "cluster_name" {
type = string
}
variable "resource_group_name" {
type = string
}
variable "storage_account_name" {
type = string
}
variable "chart_version" {
type = string
default = ""
}
variable "environment" {
type = string
default = "production"
}
provider "azurerm" {
features {}
resource_provider_registrations = "none"
}
data "azurerm_kubernetes_cluster" "this" {
name = var.cluster_name
resource_group_name = var.resource_group_name
}
provider "kubernetes" {
host = data.azurerm_kubernetes_cluster.this.kube_config[0].host
client_certificate = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_certificate)
client_key = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_key)
cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].cluster_ca_certificate)
}
module "anonymization" {
source = "oci://<Container_Registry_Path>/anonymization/anonymization-server/opentofu/anonymization?tag=azure-2.1.0"
cluster_name = var.cluster_name
oci_host = "<Container_Registry_Path>"
resource_group_name = var.resource_group_name
storage_account_name = var.storage_account_name
chart_version = var.chart_version
registry_auth_enabled = true # required for registry.protegrity.com; set false only for public/pre-authenticated registries
}
output "helm_install" { value = module.anonymization.helm_install }
output "helm_values" { value = module.anonymization.helm_values }
EOF
tofu init
tofu apply \
-var="cluster_name=<cluster>" \
-var="resource_group_name=<rg>" \
-var="storage_account_name=<globally-unique-name>" \
-var="chart_version=2.1.0"
This writes anonymization-values.yaml (Storage Account, Managed/Workload Identity, affinity/tolerations already filled in).
Display both generated outputs:
tofu output
Module variables
| Variable | Required | Default | Description |
|---|---|---|---|
cluster_name | yes | — | EKS cluster name |
bucket_name | yes | — | S3 bucket name for model storage (must be globally unique across all AWS accounts) |
oci_host | no | <Container_Registry_Path> | OCI registry hostname Note: If deploying from the Protegrity Container Registry, use registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. |
environment | no | production | Environment tag and S3 bucket prefix (staging or production) |
namespace | no | anon-ns | Kubernetes namespace |
registry_type | no | artifactory | Protegrity container registry or Local registry |
chart_version | no | "" | Helm chart version. When set, tofu output -raw helm_install prints a ready-to-run command. |
karpenter.enabled | no | true | Create Karpenter NodePool + EC2NodeClass |
karpenter.node_class.ami_family | no | Bottlerocket | AMI family. Bottlerocket selects FIPS AMI automatically. |
karpenter.node_class.ami_id | no | "" | Explicit AMI ID override. When set, overrides ami_family-based selection. |
karpenter.node_pool.instance_types | no | ["c5.large", ...] | EC2 instance types for Karpenter NodePool |
arch | no | amd64 | CPU architecture: amd64 |
fips | no | true | Use FIPS-validated Bottlerocket AMI. Set false to use the standard (non-FIPS) AMI. |
ami_id | no | "" | Explicit AMI ID override (highest priority). When set, bypasses both ami_family and fips selection. |
AMI selection priority:
| Priority | Condition | AMI Selected |
|---|---|---|
| 1 | ami_id is set | Exact AMI by ID (e.g. ami-0123456789abcdef0) |
| 2 | fips = true (default) | Latest bottlerocket-aws-k8s-<K8S_VER>-fips-<ARCH>-* |
| 3 | fips = false | Latest bottlerocket-aws-k8s-<K8S_VER>-<ARCH>-* |
Note: If you use
ami_id, theami_familyvalue must match the image that the AMI ID points to. The default value ofami_familyisBottlerocket.
Examples:
# Use a specific AMI (bypasses all auto-selection)
module "anonymization" {
source = "oci://..."
# ...
ami_id = "ami-0123456789abcdef0"
}
# Disable FIPS (use standard Bottlerocket AMI)
module "anonymization" {
source = "oci://..."
# ...
fips = false
}
| Variable | Required | Default | Description |
|---|---|---|---|
cluster_name | yes | — | AKS cluster name |
resource_group_name | yes | — | Azure resource group for the Managed Identity and Storage Account |
storage_account_name | yes | — | Azure Storage Account name (must be globally unique, 3-24 lowercase alphanumeric chars) |
environment | no | production | Environment tag and storage account name prefix |
namespace | no | anon-ns | Kubernetes namespace |
oci_host | no | <Container_Registry_Path> | OCI registry hostname Note: If deploying from the Protegrity Container Registry, use registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. |
registry_type | no | artifactory | Protegrity container registry or Local registry |
chart_version | no | "" | Helm chart version. When set, tofu output -raw helm_install prints a ready-to-run command. |
instance_types | no | ["Standard_D4as_v5", ...] | VM instance types for NodePool |
Note:
- Running
tofu planis optional. It lets you review the planned changes before they are applied.tofu output -raw helm_installprints a ready-to-run Helm command with the correct version and namespace.bucket_nameis a new S3 bucket name and it is created as part of this deployment.
Step2 - Deploy with Helm
The OpenTofu module writes an anonymization-values.yaml file in your working directory.
Pass it to Helm with --values. Passwords are required on first install only — they are
preserved automatically on subsequent upgrades.
Tip:
tofu output -raw helm_installprints a ready-to-run Helm command with the correct version and namespace pre-filled.
Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. Ensureharbor-secretexists in thedefaultnamespace.
export MLOPS_PASSWORD=<your-mlops-password>
export JOBSTATE_PASSWORD=<your-jobstate-password>
helm upgrade --install anonymization \
oci://<Container_Registry_Path>/anonymization/anonymization-server/helm/anonymization \
--version 2.1.0 \
--namespace anon-ns --create-namespace \
--values anonymization-values.yaml \
--set-string database.auth.mlopsPassword=$MLOPS_PASSWORD \
--set-string database.auth.jobstatePassword=$JOBSTATE_PASSWORD
On upgrade (passwords already stored in the cluster secret — omit --set):
helm upgrade anonymization \
oci://<Container_Registry_Path>/anonymization/anonymization-server/helm/anonymization \
--version <new-version> \
--namespace anon-ns \
--values anonymization-values.yaml
To rotate a password during upgrade:
helm upgrade anonymization ... \
--set-string database.auth.mlopsPassword=$NEW_MLOPS_PASSWORD
For more information about the Python SDK, refer to Python SDK Reference.
Validate installation
Note: Before proceeding, ensure your
kubectlcontext is set to the target clusterkubectl config current-context.
kubectl get pods -n anon-ns # All pods should be Running
kubectl get statefulset -n anon-ns # PostgreSQL, 1/1 ready
kubectl get deployment -n anon-ns # app, dask-scheduler, dask-worker
kubectl get hpa -n anon-ns
kubectl get nodes -l anonymization.protegrity.com/deployment=true # AWS: Karpenter nodes (if enabled) should be Ready.
kubectl get pods -n anon-ns # All pods should be Running
kubectl get statefulset -n anon-ns # PostgreSQL, 1/1 ready
kubectl get deployment -n anon-ns # app, dask-scheduler, dask-worker
kubectl get hpa -n anon-ns
Standalone Helm Install (No OpenTofu)
Use this when cloud infrastructure already exists or is managed separately.
Step 1 - Verify prerequisites
# StorageClass
kubectl get storageclass ebs-sc # AWS
# Pod Identity Agent (AWS)
kubectl get daemonset -n kube-system eks-pod-identity-agent
# Karpenter NodePool (if using node isolation)
kubectl get nodepool anonymization-cpu
kubectl get ec2nodeclass anonymization-cpu
# StorageClass
kubectl get storageclass managed-csi-premium # Azure
kubectl get nodepool anonymization-cpu
kubectl get aksnodeclass anonymization-cpu
Step 2 - Create a values override file
AWS example (my-values.yaml):
cloudProvider: aws
serviceaccount:
name: anon-service-account
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>"
storage:
enabled: true
bucketName: <your-globally-unique-bucket-name>
region: us-east-1
database:
persistence:
storageClass: ebs-sc
size: 20Gi
karpenter:
enabled: true # set false if NOT using Karpenter isolation
Azure example (my-values.yaml):
cloudProvider: azure
serviceaccount:
name: anon-service-account
annotations:
azure.workload.identity/client-id: "<MANAGED_IDENTITY_CLIENT_ID>"
storage:
enabled: true
dsn: "abfss://models@<storage_account>.dfs.core.windows.net/"
database:
persistence:
storageClass: managed-csi-premium
size: 20Gi
karpenter:
enabled: false
Step 3 - Install
Note: If deploying from the Protegrity Container Registry, use
registry.protegrity.com:9443. Specify the local registry endpoint if a local registry is used. Ensureharbor-secretexists in thedefaultnamespace.
export MLOPS_PASSWORD=<your-mlops-password>
export JOBSTATE_PASSWORD=<your-jobstate-password>
helm upgrade --install anonymization \
oci://<Container_Registry_Path>/anonymization/anonymization-server/helm/anonymization \
--version 2.1.0 \
--namespace anon-ns --create-namespace \
--values my-values.yaml \
--set-string database.auth.mlopsPassword=$MLOPS_PASSWORD \
--set-string database.auth.jobstatePassword=$JOBSTATE_PASSWORD
Next Steps
For more information about the Python SDK, refer to Python SDK Reference.
If you encounter any error during or after installation, refer to Troubleshooting.