Skip to content

Before You Begin

This page lists everything to have ready before you create a runtime plane, with the commands to set each piece up. The portal wizard (Settings → Runtime Plane) collects the same information and shows the same guidance in context.

Replace <placeholders> in the commands with your values. If you have not picked a deployment type yet, start with Deployment Options.


Kubernetes cluster

You provide a Kubernetes cluster on AWS (EKS), Azure (AKS), or Google Cloud (GKE). The wizard asks you to confirm each prerequisite before it lets you continue, and offers a Download Script that auto-verifies the CLI tools, Kubernetes version, and Metrics Server on your cluster.

Requirement Details
EKS cluster Kubernetes v1.34 or later. Nodes must be r5.2xlarge or a similar instance type with equivalent compute and memory. Node group configured with a minimum of 1 and a maximum of 10 nodes.
Terminal access A terminal with network connectivity to the EKS cluster API server and cluster-admin permissions, to create global resources such as namespaces and storage classes.
Command-line tools AWS CLI v2.12.0+, kubectl v1.34+, Helm v3.9.0+, and curl or wget. Optional: k9s for interactive cluster monitoring.
Metrics Server Must be installed and running — see below.
Outbound access The cluster must allow outbound (egress) HTTPS traffic to https://api.privaceracloud.com so the Runtime Agent can reach the control plane.

Verify terminal access

Bash
kubectl config get-contexts

Ensure the asterisk (*) is next to the correct cluster name.

Bash
kubectl auth can-i '*' '*' --all-namespaces

This must return yes. If it returns no, you do not have sufficient permissions to proceed.

Install the Metrics Server

The Kubernetes Metrics Server provides resource metrics for pods and nodes, which are essential for monitoring and autoscaling. Check whether it is already installed:

Bash
kubectl get deployment metrics-server -n kube-system

If not, install it. For EKS, specific flags are needed to handle TLS certificates:

Bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Bash
kubectl patch deployment metrics-server -n kube-system --type='json' \
  -p='[{"op": "add", "path": "/spec/template/spec/hostNetwork", "value": true}, {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}, {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-preferred-address-types=InternalIP,Hostname,ExternalIP"}]'

Verify (metrics may take 1–2 minutes to appear):

Bash
kubectl top nodes
Requirement Details
AKS cluster Kubernetes v1.34 or later. Nodes must be Standard_E8s_v3 or a similar VM size with equivalent compute and memory. Node pool configured with a minimum of 1 and a maximum of 10 nodes.
Terminal access A terminal with network connectivity to the AKS cluster API server and cluster-admin permissions.
Command-line tools Azure CLI v2.50.0+, kubectl v1.34+, Helm v3.9.0+, and curl or wget. Optional: k9s for interactive cluster monitoring.
Metrics Server Must be installed and running — see below.
Outbound access The cluster must allow outbound (egress) HTTPS traffic to https://api.privaceracloud.com so the Runtime Agent can reach the control plane.

Verify terminal access

Connect to your AKS cluster:

Bash
az aks get-credentials --resource-group <resource-group> --name <cluster-name>
Bash
kubectl config get-contexts

Ensure the asterisk (*) is next to the correct cluster name.

Bash
kubectl auth can-i '*' '*' --all-namespaces

This must return yes.

Install the Metrics Server

Check whether it is already installed:

Bash
kubectl get deployment metrics-server -n kube-system

If not, install it using the official manifest:

Bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verify (metrics may take 1–2 minutes to appear):

Bash
kubectl top nodes
Requirement Details
GKE cluster Kubernetes v1.34 or later. Both Standard and Autopilot clusters are supported. Nodes must be n2-standard-8 or a similar machine type with equivalent compute and memory. Node pool autoscaling from 1 to 10 nodes.
Terminal access A terminal with Kubernetes Engine Cluster Admin or equivalent permissions, to create global resources such as namespaces and storage classes.
Command-line tools Google Cloud SDK 450.0.0+, kubectl v1.34+, Helm v3.9.0+, and curl or wget. Optional: k9s for interactive cluster monitoring.
Metrics Server Must be installed and running — see below.
Outbound access The cluster must allow outbound (egress) HTTPS traffic to https://api.privaceracloud.com so the Runtime Agent can reach the control plane.

Verify terminal access

Connect to your GKE cluster:

Bash
gcloud container clusters get-credentials <cluster-name> --zone <zone> --project <project-id>
Bash
kubectl config get-contexts

Ensure the asterisk (*) is next to the correct cluster name.

Bash
kubectl auth can-i '*' '*' --all-namespaces

This must return yes.

Install the Metrics Server

Check whether it is already installed:

Bash
kubectl get deployment metrics-server -n kube-system

If not, install it using the official manifest:

Bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verify (metrics may take 1–2 minutes to appear):

Bash
kubectl top nodes

You provide a Kubernetes cluster on AWS (Amazon EKS). The wizard asks you to confirm each prerequisite before it lets you continue, and offers a Download Script that auto-verifies the CLI tools, Kubernetes version, and Metrics Server on your cluster.

Requirement Details
EKS cluster Kubernetes v1.34 or later. Nodes must be r5.2xlarge or a similar instance type with equivalent compute and memory. Node group configured with a minimum of 1 and a maximum of 10 nodes.
Terminal access A terminal with network connectivity to the EKS cluster API server and cluster-admin permissions, to create global resources such as namespaces and storage classes.
Command-line tools AWS CLI v2.12.0+, kubectl v1.34+, Helm v3.9.0+, and curl or wget. Optional: k9s for interactive cluster monitoring.
Metrics Server Must be installed and running — see below.
AWS Load Balancer Controller Installed on the cluster — see DNS and ingress.
OIDC provider (IRSA) The cluster's OpenID Connect provider must be associated with IAM — see Cloud permissions.

Verify terminal access

Bash
kubectl config get-contexts

Ensure the asterisk (*) is next to the correct cluster name.

Bash
kubectl auth can-i '*' '*' --all-namespaces

This must return yes. If it returns no, you do not have sufficient permissions to proceed.

Install the Metrics Server

The Kubernetes Metrics Server provides resource metrics for pods and nodes, which are essential for monitoring and autoscaling. Check whether it is already installed:

Bash
kubectl get deployment metrics-server -n kube-system

If not, install it. For EKS, specific flags are needed to handle TLS certificates:

Bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Bash
kubectl patch deployment metrics-server -n kube-system --type='json' \
  -p='[{"op": "add", "path": "/spec/template/spec/hostNetwork", "value": true}, {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}, {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-preferred-address-types=InternalIP,Hostname,ExternalIP"}]'

Verify (metrics may take 1–2 minutes to appear):

Bash
kubectl top nodes

Decisions to make

These apply to both deployment types:

Decision Details
Region The cloud region where your cluster runs.
Runtime name Auto-generated, but you can personalize it. It becomes the Kubernetes namespace for the runtime plane: lowercase letters, numbers, and hyphens only; 6–44 characters. The resource names below (trust3-<runtime-name>-role and similar) derive from it.
Auto Upgrade On by default — the runtime plane follows the latest release. Turn it off if you want to pin a specific version.

Storage, database, and secrets

All optional to start with — by default, credentials are encrypted in the browser and stored in the Trust3 database, and no bucket or external database is needed. Depending on what you plan to run:

Needed when What to have ready
You plan to create connectors Persistent storage for connector workloads — on AWS, an EFS file system with the CSI driver (see the AWS tab).
You need audit logs in your own bucket (compliance) A storage bucket in the same region as your cluster.
You want credentials in your own secret store A secret in your cloud secret manager, or a Kubernetes Secret in the runtime namespace.

S3 bucket

Trust3 uses an S3 bucket to store runtime data and configuration. Create a dedicated bucket in the same AWS region as your EKS cluster. Naming rules: 3–63 characters, lowercase letters, numbers, and hyphens only; globally unique across all AWS accounts.

Bash
1
2
3
aws s3api create-bucket \
  --bucket <bucket-name> \
  --region <region>

Keep server-side encryption (SSE-S3 or SSE-KMS) enabled and leave block-public-access enabled (the default). The IAM role from Cloud permissions must have S3 access to this bucket.

Verify access:

Bash
aws s3 ls s3://<bucket-name>

EFS file system + CSI driver — needed for connector persistent storage

Create an EFS file system in the same VPC and region as your EKS cluster, with security groups allowing NFS traffic (port 2049) between the EKS nodes and the EFS mount targets. Install the AWS EFS CSI Driver.

Enable delete access point

Enable the delete access point option when installing the CSI driver, so the root volume created for a Persistent Volume in EFS is automatically deleted when you remove the PV/PVC from the cluster. Without it, deleted volumes leave data behind in EFS, increasing storage usage and costs.

Helm (values.yaml):

YAML
deleteAccessPointRootDir: true

YAML (controller args):

YAML
args:
- --delete-access-point-root-dir=true

Verify the driver:

Bash
kubectl get pods -A -l 'app.kubernetes.io/name=aws-efs-csi-driver'
Bash
kubectl get csidriver efs.csi.aws.com

Find your file system ID (fs-...):

Bash
aws efs describe-file-systems --query 'FileSystems[*].{Name:Name,Id:FileSystemId}' --output table

The EFS ID cannot be changed after setup.

Secret store options

By default, no setup is needed — credentials are encrypted in your browser with a per-runtime public key, and only your runtime can decrypt them with its private key. To use your own store instead:

Kubernetes Secret — a single secret in the runtime namespace; each connector credential is one key in its data map. If a value changes later, restart the affected connector from the portal.

Bash
1
2
3
4
kubectl create secret generic <runtime-name>-secrets \
  -n <runtime-name> \
  --from-literal=my-credential='dummy-value' \
  --dry-run=client -o yaml | kubectl apply -f -

AWS Secrets Manager — a secret in the same region as your cluster; connector credentials are keys in its JSON payload. Access is granted through the IAM role in Cloud permissions.

Bash
1
2
3
4
aws secretsmanager create-secret \
  --name <secret-name> \
  --region <region> \
  --secret-string '{}'

Blob storage — for audit logs in your own storage

You need a storage account and a blob container inside it, both in the same Azure region as your AKS cluster.

Bash
1
2
3
4
5
az storage account create \
  --name <storage-account-name> \
  --resource-group <resource-group> \
  --location <location> \
  --sku Standard_LRS
Bash
1
2
3
az storage container create \
  --name <container-name> \
  --account-name <storage-account-name>

The managed identity from Cloud permissions needs the Storage Blob Data Contributor role on this container.

Secret store options

By default, no setup is needed — credentials are encrypted in your browser and only your runtime can decrypt them. To use your own store instead:

Kubernetes Secret — same as on other clouds:

Bash
1
2
3
4
kubectl create secret generic <runtime-name>-secrets \
  -n <runtime-name> \
  --from-literal=my-credential='dummy-value' \
  --dry-run=client -o yaml | kubectl apply -f -

Azure Key Vault — create a vault in the same region as your AKS cluster; each connector credential is an individual secret in the vault. The vault name must be globally unique (3–24 characters, alphanumeric and hyphens only). If a secret changes later, restart the affected connector from the portal.

Bash
1
2
3
4
az keyvault create \
  --name <key-vault-name> \
  --resource-group <resource-group> \
  --location <location>

The managed identity from Cloud permissions needs the Key Vault Secrets User role on the vault.

GCS bucket — for audit logs in your own storage

Create a bucket in the same GCP region as your GKE cluster. Naming rules: 3–63 characters — lowercase letters, numbers, hyphens, and underscores; globally unique across all GCP projects. Uniform bucket-level access is recommended; keep public access prevention enabled.

Bash
1
2
3
4
gcloud storage buckets create gs://<bucket-name> \
  --location=<region> \
  --uniform-bucket-level-access \
  --public-access-prevention

The service account from Cloud permissions needs Storage Object Admin on this bucket.

Verify access:

Bash
gcloud storage ls gs://<bucket-name>

Secret store options

By default, no setup is needed — credentials are encrypted in your browser and only your runtime can decrypt them. To use your own store instead:

Kubernetes Secret — same as on other clouds:

Bash
1
2
3
4
kubectl create secret generic <runtime-name>-secrets \
  -n <runtime-name> \
  --from-literal=my-credential='dummy-value' \
  --dry-run=client -o yaml | kubectl apply -f -

Google Secret Manager — a secret in the same project as your GKE cluster. If a value changes later, restart the affected connector from the portal.

Bash
1
2
3
echo -n '{}' | gcloud secrets create <secret-name> \
  --data-file=- \
  --replication-policy=automatic

The service account from Cloud permissions needs Secret Manager Secret Accessor.

S3 bucket — required

Trust3 uses an S3 bucket to store runtime data and configuration. Create a dedicated bucket in the same AWS region as your EKS cluster. Naming rules: 3–63 characters, lowercase letters, numbers, and hyphens only; globally unique across all AWS accounts. The bucket name cannot be changed after setup.

Bash
1
2
3
aws s3api create-bucket \
  --bucket <bucket-name> \
  --region <region>

Keep server-side encryption (SSE-S3 or SSE-KMS) enabled and leave block-public-access enabled (the default). The IAM role from Cloud permissions must have S3 access to this bucket.

Verify access:

Bash
aws s3 ls s3://<bucket-name>

EFS file system + CSI driver — required unless you bring your own StorageClass

Create an EFS file system in the same VPC and region as your EKS cluster, with security groups allowing NFS traffic (port 2049) between the EKS nodes and the EFS mount targets. Install the AWS EFS CSI Driver.

Enable delete access point

Enable the delete access point option when installing the CSI driver, so the root volume created for a Persistent Volume in EFS is automatically deleted when you remove the PV/PVC from the cluster. Without it, deleted volumes leave data behind in EFS, increasing storage usage and costs.

Helm (values.yaml):

YAML
deleteAccessPointRootDir: true

YAML (controller args):

YAML
args:
- --delete-access-point-root-dir=true

Verify the driver:

Bash
kubectl get pods -A -l 'app.kubernetes.io/name=aws-efs-csi-driver'
Bash
kubectl get csidriver efs.csi.aws.com

Find your file system ID (fs-...):

Bash
aws efs describe-file-systems --query 'FileSystems[*].{Name:Name,Id:FileSystemId}' --output table

The EFS ID cannot be changed after setup. Alternatively, turn StorageClass provisioning off in the wizard and provide the name of an existing Kubernetes StorageClass instead.

Database — required

Trust3 services need a relational database for metadata and policy storage. Pick one:

Option Details Recommended for
Native Trust3 deploys an in-cluster database. No external database or secret needed. Data durability is tied to the cluster. Testing and staging
MySQL Amazon Aurora MySQL 3.x (MySQL 8.0 compatible), db.r6g.2xlarge (8 vCPU, 64 GB RAM) or larger, password authentication only. Production
PostgreSQL Amazon Aurora PostgreSQL 16 or later, db.r6g.2xlarge (8 vCPU, 64 GB RAM) or larger, password authentication only. Production

For an external database, provision it before you start:

Find your DB subnet group and security group. You need a DB subnet group for the cluster VPC with at least two private subnets across different availability zones, and a security group allowing inbound 3306 (MySQL) / 5432 (PostgreSQL) from the EKS node CIDR.

Bash
1
2
3
4
aws rds describe-db-subnet-groups \
  --query 'DBSubnetGroups[*].DBSubnetGroupName' \
  --output table \
  --region <region>
Bash
1
2
3
4
5
aws ec2 describe-security-groups \
  --filters Name=vpc-id,Values=<vpc-id> \
  --query 'SecurityGroups[*].[GroupId,GroupName]' \
  --output table \
  --region <region>

If you do not know your VPC ID, find it from the EKS cluster:

Bash
1
2
3
4
aws eks describe-cluster \
  --name <cluster-name> \
  --query 'cluster.resourcesVpcConfig.vpcId' \
  --output text

Provision the cluster and writer instance. Set your values, then create the cluster — PostgreSQL:

Bash
REGION="<region>"
DB_PASSWORD="<password>"
SUBNET_GROUP="<subnet-group>"
SG_ID="<security-group-id>"

aws rds create-db-cluster \
  --db-cluster-identifier trust3-db-cluster \
  --engine aurora-postgresql \
  --engine-version 16.13 \
  --master-username admin \
  --master-user-password "$DB_PASSWORD" \
  --db-subnet-group-name "$SUBNET_GROUP" \
  --vpc-security-group-ids "$SG_ID" \
  --region "$REGION"

aws rds create-db-instance \
  --db-instance-identifier trust3-db-writer \
  --db-cluster-identifier trust3-db-cluster \
  --db-instance-class db.r6g.2xlarge \
  --engine aurora-postgresql \
  --no-publicly-accessible \
  --region "$REGION"

MySQL:

Bash
REGION="<region>"
DB_PASSWORD="<password>"
SUBNET_GROUP="<subnet-group>"
SG_ID="<security-group-id>"

aws rds create-db-cluster \
  --db-cluster-identifier trust3-db-cluster \
  --engine aurora-mysql \
  --engine-version 8.0.mysql_aurora.3.12.0 \
  --master-username admin \
  --master-user-password "$DB_PASSWORD" \
  --db-subnet-group-name "$SUBNET_GROUP" \
  --vpc-security-group-ids "$SG_ID" \
  --region "$REGION"

aws rds create-db-instance \
  --db-instance-identifier trust3-db-writer \
  --db-cluster-identifier trust3-db-cluster \
  --db-instance-class db.r6g.2xlarge \
  --engine aurora-mysql \
  --region "$REGION"

Wait until the cluster status shows available (about 10 minutes), then get the writer endpoint — this is your DB_HOST:

Bash
1
2
3
4
5
aws rds describe-db-clusters \
  --db-cluster-identifier trust3-db-cluster \
  --region "$REGION" \
  --query 'DBClusters[0].Endpoint' \
  --output text

Create the database. Connect to the instance and create the database — MySQL needs charset latin1, collation latin1_swedish_ci:

Bash
psql -h "<db-host>" -p 5432 -U admin -W
SQL
CREATE DATABASE trust3_db;
Bash
mysql -h "<db-host>" -P 3306 -u admin -p
SQL
create database trust3_db character set latin1 collate latin1_swedish_ci;

Create the database secret. A secret holding the connection details as five keys — host, port, db, username, password — in whichever secret store you choose below. As a Kubernetes Secret:

Bash
1
2
3
4
5
6
7
8
9
kubectl create namespace <runtime-name>

kubectl create secret generic <secret-name> \
  -n <runtime-name> \
  --from-literal=host=<db-host> \
  --from-literal=port=<db-port> \
  --from-literal=db=trust3_db \
  --from-literal=username=<db-username> \
  --from-literal=password=<db-password>

Or in AWS Secrets Manager:

Bash
1
2
3
4
5
aws secretsmanager create-secret \
  --name <secret-name> \
  --description "External database credentials for Trust3 runtime" \
  --region <region> \
  --secret-string "{\"host\":\"<db-host>\",\"port\":\"<db-port>\",\"db\":\"trust3_db\",\"username\":\"<db-username>\",\"password\":\"<db-password>\"}"

Verify all five keys are present:

Bash
1
2
3
kubectl get secret <secret-name> \
  --namespace <runtime-name> \
  -o jsonpath='{.data}' | jq 'keys'
Bash
1
2
3
4
aws secretsmanager get-secret-value \
  --secret-id <secret-name> \
  --region <region> \
  --query SecretString --output text | jq 'keys'

Expected output: ["db","host","password","port","username"]

Secrets provider — choose where connector credentials live:

Trust3 DB (End-To-End Encrypted) — the default; no setup. Credentials are encrypted in your browser using a per-runtime public key and stored in the database running in your instance. Only your runtime can decrypt them with its private key. If the runtime is deleted or its private key is lost, encrypted credentials cannot be recovered and must be re-entered.

Kubernetes Secret — a single secret in the runtime namespace; each connector credential is one key in its data map. If a value changes later, restart the affected connector from the portal.

Bash
1
2
3
4
kubectl create secret generic <runtime-name>-secrets \
  -n <runtime-name> \
  --from-literal=my-credential='dummy-value' \
  --dry-run=client -o yaml | kubectl apply -f -

AWS Secrets Manager — a secret in the same region as your cluster; connector credentials are keys in its JSON payload. Access is granted through the IAM role in Cloud permissions.

Bash
1
2
3
4
aws secretsmanager create-secret \
  --name <secret-name> \
  --region <region> \
  --secret-string '{}'

With Kubernetes Secrets or AWS Secrets Manager, the database connection keys above must live in that same secret.


DNS and ingress

Optional to start with — needed as soon as a service must be reachable at a hostname (for example Dataserver, or a custom corporate domain for service endpoints).

AWS Load Balancer Controller

Required for managing ingress traffic: it provisions Application Load Balancers based on Kubernetes Ingress resources. Install it following the AWS Load Balancer Controller guide, then verify:

Bash
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

You should see the pods in Running state (typically 2 replicas).

Route 53 hosted zone

Trust3 uses a Route 53 hosted zone to manage DNS records for the service endpoints (for example *.trust3.yourdomain.com).

  • Automatic DNS: Trust3 creates, updates, and deletes the records for you. Requires the IAM role from Cloud permissions to have Route 53 access.
  • Manual DNS: you create the records yourself after deployment; Trust3 provides the required record values.

Find your hosted zone:

Bash
aws route53 list-hosted-zones --query "HostedZones[*].{Name:Name,Id:Id}" --output table

If you do not have a hosted zone yet, create one in Route 53 and delegate it from your parent domain's DNS — common for a subdomain like trust3.yourdomain.com.

ACM certificate

The certificate must cover the service endpoint domain (for example *.trust3.yourdomain.com) and be in the same AWS region as your EKS cluster. It can be a public certificate issued by ACM or an existing certificate imported into ACM. Find its ARN:

Bash
aws acm list-certificates --region <region>

ARN format: arn:aws:acm:<region>:<account-id>:certificate/<certificate-id>

ALB subnets — at least two subnet IDs where the Application Load Balancers will reside.

ALB group name (optional) — ingresses in the same group share one Application Load Balancer. Defaults to trust3ai.

Azure DNS zone

Trust3 uses an Azure DNS zone to manage DNS records for the service endpoints (for example *.trust3.yourdomain.com).

  • Automatic DNS: Trust3 creates, updates, and deletes the records for you. Requires the managed identity from Cloud permissions to have the DNS Zone Contributor role.
  • Manual DNS: you create the records yourself after deployment; Trust3 provides the required record values.

Find your DNS zone:

Bash
az network dns zone list --query "[].{Name:name,ResourceGroup:resourceGroup}" --output table

If you do not have one yet, create it and delegate from your parent domain's DNS:

Bash
az network dns zone create --resource-group <resource-group> --name trust3.yourdomain.com

TLS certificate (Kubernetes secret)

You need a CA-signed TLS certificate and key — a single wildcard certificate (for example *.corp.example.com) covers all Trust3 service endpoints on your domain. Have the certificate and key ready before installation, then create the TLS secret in your cluster. The secret name privacera-external-tls and the runtime namespace are fixed.

Bash
kubectl create namespace <runtime-name>

PEM format:

Bash
1
2
3
4
kubectl create secret tls privacera-external-tls \
  --cert="<cert-path>" \
  --key="<key-path>" \
  -n <runtime-name>

PFX/P12 format — conversion needs OpenSSL (check with openssl version; drop the -legacy flag on OpenSSL versions below 3.x):

Bash
1
2
3
4
5
6
7
openssl pkcs12 -legacy -in "<pfx-path>" \
  -nokeys -out chain.pem
openssl pkcs12 -legacy -in "<pfx-path>" \
  -nocerts -nodes -out key.pem

kubectl create secret tls privacera-external-tls \
  --cert=chain.pem --key=key.pem -n <runtime-name>

On certificate renewal, replace the secret:

Bash
1
2
3
4
5
kubectl create secret tls privacera-external-tls \
  --cert="<cert-path>" \
  --key="<key-path>" \
  -n <runtime-name> \
  --dry-run=client -o yaml | kubectl replace -f -

Cloud DNS managed zone

Trust3 uses a Cloud DNS managed zone to manage DNS records for the service endpoints (for example *.trust3.yourdomain.com).

  • Automatic DNS: Trust3 creates, updates, and deletes the records for you. Requires the service account from Cloud permissions to have the DNS Admin role.
  • Manual DNS: you create the records yourself after deployment; Trust3 provides the required record values.

Find your managed zone:

Bash
gcloud dns managed-zones list --format="table(name,dnsName,visibility)"

If you do not have one yet, create it and delegate from your parent domain's DNS:

Bash
1
2
3
4
5
gcloud dns managed-zones create trust3-zone \
  --dns-name="trust3.yourdomain.com." \
  --description="Trust3 managed zone" \
  --visibility=public \
  --project=<project-id>

TLS certificate (Kubernetes secret)

You need a CA-signed TLS certificate and key — a single wildcard certificate (for example *.corp.example.com) covers all Trust3 service endpoints on your domain. Have the certificate and key ready before installation, then create the TLS secret in your cluster. The secret name privacera-external-tls and the runtime namespace are fixed.

Bash
kubectl create namespace <runtime-name>

PEM format:

Bash
1
2
3
4
kubectl create secret tls privacera-external-tls \
  --cert="<cert-path>" \
  --key="<key-path>" \
  -n <runtime-name>

PFX/P12 format — conversion needs OpenSSL (check with openssl version; drop the -legacy flag on OpenSSL versions below 3.x):

Bash
1
2
3
4
5
6
7
openssl pkcs12 -legacy -in "<pfx-path>" \
  -nokeys -out chain.pem
openssl pkcs12 -legacy -in "<pfx-path>" \
  -nocerts -nodes -out key.pem

kubectl create secret tls privacera-external-tls \
  --cert=chain.pem --key=key.pem -n <runtime-name>

On certificate renewal, replace the secret:

Bash
1
2
3
4
5
kubectl create secret tls privacera-external-tls \
  --cert="<cert-path>" \
  --key="<key-path>" \
  -n <runtime-name> \
  --dry-run=client -o yaml | kubectl replace -f -

All required.

AWS Load Balancer Controller

Required for managing ingress traffic: it provisions Application Load Balancers based on Kubernetes Ingress resources. Install it following the AWS Load Balancer Controller guide, then verify:

Bash
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

You should see the pods in Running state (typically 2 replicas).

Route 53 hosted zone

Trust3 uses a Route 53 hosted zone to manage DNS records for all service endpoints (for example *.trust3.yourdomain.com). The domain name you enter in the wizard must match the hosted zone name.

  • Automatic DNS (default): Trust3 creates, updates, and deletes the records for you. Requires the IAM role from Cloud permissions to have Route 53 access.
  • Manual DNS: you create the records yourself after deployment; Trust3 provides the required record values.

Find your hosted zone:

Bash
aws route53 list-hosted-zones --query "HostedZones[*].{Name:Name,Id:Id}" --output table

If you do not have a hosted zone yet, create one in Route 53 and delegate it from your parent domain's DNS — common for a subdomain like trust3.yourdomain.com.

ACM certificate

The certificate must cover the service endpoint domain (for example *.trust3.yourdomain.com) and be in the same AWS region as your EKS cluster. It can be a public certificate issued by ACM or an existing certificate imported into ACM. Find its ARN:

Bash
aws acm list-certificates --region <region>

ARN format: arn:aws:acm:<region>:<account-id>:certificate/<certificate-id>

ALB subnets — at least two subnet IDs where the Application Load Balancers will reside.

ALB group name (optional) — ingresses in the same group share one Application Load Balancer. Defaults to trust3ai.


Cloud permissions

Optional to start with — a cloud identity becomes required as soon as the runtime plane touches a cloud service (your own bucket, your own secret manager, or automatic DNS). The wizard's Cloud Permissions step shows the same commands with your values filled in.

Create an IAM role named trust3-<runtime-name>-role that Trust3 services assume through the cluster's OIDC provider (IRSA). You can use an existing role if the trust relationship and policy match.

Create the role

Set your EKS cluster name, then create the role with the OIDC trust policy:

Bash
K8S_CLUSTER_NAME="<cluster-name>"

OIDC_URL=$(aws eks describe-cluster --name "$K8S_CLUSTER_NAME" \
  --query "cluster.identity.oidc.issuer" --output text | sed 's|https://||')

ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)

OIDC_ARN="arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_URL}"

TRUST_POLICY=$(cat <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Federated": "${OIDC_ARN}"},
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringLike": {
        "${OIDC_URL}:aud": "sts.amazonaws.com",
        "${OIDC_URL}:sub": "system:serviceaccount:<runtime-name>:*"
      }
    }
  }]
}
EOF
)

aws iam create-role \
  --role-name "trust3-<runtime-name>-role" \
  --assume-role-policy-document "$TRUST_POLICY"

Retrieve the role ARN (this is what you enter in the wizard):

Bash
1
2
3
aws iam get-role \
  --role-name "trust3-<runtime-name>-role" \
  --query "Role.Arn" --output text

OIDC provider not associated?

If your EKS cluster does not have an OIDC provider associated with IAM, create one first — see the AWS IRSA documentation:

Bash
eksctl utils associate-iam-oidc-provider --cluster <cluster-name> --approve

Attach the permissions policy

Attach one inline policy named Trust3PermissionsPolicy. Include only the statements for the services you configured — Secrets Manager (your own secret store), S3 (your own bucket), Route 53 (automatic DNS):

Bash
POLICY_DOC=$(cat <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:<region>:*:secret:<secret-name>-*",
        "arn:aws:secretsmanager:<region>:*:secret:<secret-name>"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::<bucket-name>",
        "arn:aws:s3:::<bucket-name>/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "route53:*",
      "Resource": [
        "arn:aws:route53:::hostedzone/<hosted-zone-id>"
      ]
    }
  ]
}
EOF
)

aws iam put-role-policy \
  --role-name "trust3-<runtime-name>-role" \
  --policy-name Trust3PermissionsPolicy \
  --policy-document "$POLICY_DOC"

Trust relationship for an existing role

If you reuse an existing role, set its trust policy — replace <oidc-arn> and <oidc-url> with your cluster's OIDC provider values:

JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "<oidc-arn>"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "<oidc-url>:aud": "sts.amazonaws.com",
                    "<oidc-url>:sub": "system:serviceaccount:<runtime-name>:*"
                }
            }
        }
    ]
}

Apply it — put the JSON above in a TRUST_POLICY variable, then:

Bash
1
2
3
aws iam update-assume-role-policy \
  --role-name "trust3-<runtime-name>-role" \
  --policy-document "$TRUST_POLICY"

Find your OIDC values:

Bash
aws eks describe-cluster --name <cluster-name> --query "cluster.identity.oidc.issuer" --output text

Remove https:// from the output to get <oidc-url>; the matching <oidc-arn> is arn:aws:iam::<account-id>:oidc-provider/<oidc-url>.

Create a User-Assigned Managed Identity named trust3-<runtime-name>-identity and a federated credential so Kubernetes service accounts in the runtime namespace can authenticate as it via Workload Identity. You can use an existing identity if the configuration matches.

Create the managed identity

Bash
1
2
3
4
az identity create \
  --resource-group <resource-group> \
  --name trust3-<runtime-name>-identity \
  --location <location>

Retrieve the Client ID (this is what you enter in the wizard):

Bash
1
2
3
4
az identity show \
  --resource-group <resource-group> \
  --name trust3-<runtime-name>-identity \
  --query clientId -o tsv

Create the federated identity credential

Find your AKS OIDC issuer URL:

Bash
az aks show --resource-group <resource-group> --name <cluster-name> --query "oidcIssuerProfile.issuerUrl" --output tsv
Bash
1
2
3
4
5
6
7
az identity federated-credential create \
  --name "trust3-<runtime-name>-federated" \
  --identity-name "trust3-<runtime-name>-identity" \
  --resource-group <resource-group> \
  --issuer "<aks-oidc-issuer-url>" \
  --subject "system:serviceaccount:<runtime-name>:<runtime-name>-sa" \
  --audiences "api://AzureADTokenExchange"

Workload Identity not enabled on your AKS cluster?

Enable it first — see the AKS Workload Identity documentation:

Bash
az aks update --resource-group <resource-group> --name <cluster-name> --enable-oidc-issuer --enable-workload-identity

Role assignments

Assign only the roles for the services you configured:

Storage Blob Data Contributor — when using your own blob container:

Bash
1
2
3
4
az role assignment create \
  --assignee "<managed-identity-client-id>" \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container-name>"

DNS Zone Contributor — when using automatic DNS management:

Bash
1
2
3
4
az role assignment create \
  --assignee "<managed-identity-client-id>" \
  --role "DNS Zone Contributor" \
  --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/dnszones/<dns-zone-name>"

Key Vault Secrets User — when using Azure Key Vault as the secret store:

Bash
1
2
3
4
az role assignment create \
  --role "Key Vault Secrets User" \
  --assignee <managed-identity-client-id> \
  --scope $(az keyvault show --name <key-vault-name> --query id -o tsv)

Create a GCP service account named trust3-<runtime-name>-sa and bind it to the runtime's Kubernetes service account via Workload Identity. You can use an existing service account if the email and bindings match.

Create the service account

Bash
1
2
3
gcloud iam service-accounts create trust3-<runtime-name>-sa \
  --display-name="Trust3 Service Account for <runtime-name>" \
  --project=<project-id>

Retrieve the service account email (this is what you enter in the wizard — format trust3-<runtime-name>-sa@<project-id>.iam.gserviceaccount.com):

Bash
1
2
3
gcloud iam service-accounts list \
  --filter="name:trust3-<runtime-name>-sa" \
  --project=<project-id>

Workload Identity binding — always required when using the service account:

Bash
1
2
3
4
gcloud iam service-accounts add-iam-policy-binding trust3-<runtime-name>-sa@<project-id>.iam.gserviceaccount.com \
  --project=<project-id> \
  --role="roles/iam.workloadIdentityUser" \
  --member="serviceAccount:<project-id>.svc.id.goog[<runtime-name>/<runtime-name>-sa]"

Workload Identity not enabled on your GKE cluster?

Enable it first — see the GKE Workload Identity documentation:

Bash
1
2
3
gcloud container clusters update <cluster-name> \
  --workload-pool=<project-id>.svc.id.goog \
  --region=<region>

Role bindings

Grant only the roles for the services you configured:

Storage Object Admin (roles/storage.objectAdmin) — when using your own GCS bucket:

Bash
1
2
3
gcloud storage buckets add-iam-policy-binding gs://<bucket-name> \
  --member="serviceAccount:trust3-<runtime-name>-sa@<project-id>.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

DNS Administrator (roles/dns.admin) — when using automatic DNS management:

Bash
1
2
3
gcloud projects add-iam-policy-binding <project-id> \
  --member="serviceAccount:trust3-<runtime-name>-sa@<project-id>.iam.gserviceaccount.com" \
  --role="roles/dns.admin"

Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) — when using Google Secret Manager as the secret store:

Bash
1
2
3
gcloud projects add-iam-policy-binding <project-id> \
  --member="serviceAccount:trust3-<runtime-name>-sa@<project-id>.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Required — S3 and DNS access are always configured on Self-Managed. Create an IAM role named trust3-<runtime-name>-role that Trust3 services assume through the cluster's OIDC provider (IRSA). You can use an existing role if the trust relationship and policy match. The wizard's Cloud Permissions step shows the same commands with your values filled in.

Create the role

Set your EKS cluster name, then create the role with the OIDC trust policy:

Bash
K8S_CLUSTER_NAME="<cluster-name>"

OIDC_URL=$(aws eks describe-cluster --name "$K8S_CLUSTER_NAME" \
  --query "cluster.identity.oidc.issuer" --output text | sed 's|https://||')

ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)

OIDC_ARN="arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_URL}"

TRUST_POLICY=$(cat <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Federated": "${OIDC_ARN}"},
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringLike": {
        "${OIDC_URL}:aud": "sts.amazonaws.com",
        "${OIDC_URL}:sub": "system:serviceaccount:<runtime-name>:*"
      }
    }
  }]
}
EOF
)

aws iam create-role \
  --role-name "trust3-<runtime-name>-role" \
  --assume-role-policy-document "$TRUST_POLICY"

Retrieve the role ARN (this is what you enter in the wizard):

Bash
1
2
3
aws iam get-role \
  --role-name "trust3-<runtime-name>-role" \
  --query "Role.Arn" --output text

OIDC provider not associated?

If your EKS cluster does not have an OIDC provider associated with IAM, create one first — see the AWS IRSA documentation:

Bash
eksctl utils associate-iam-oidc-provider --cluster <cluster-name> --approve

Attach the permissions policy

Attach one inline policy named Trust3PermissionsPolicy. The S3 and Route 53 statements are always needed on Self-Managed; include the Secrets Manager statement only when AWS Secrets Manager is your secret store:

Bash
POLICY_DOC=$(cat <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:<region>:*:secret:<secret-name>-*",
        "arn:aws:secretsmanager:<region>:*:secret:<secret-name>"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::<bucket-name>",
        "arn:aws:s3:::<bucket-name>/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "route53:*",
      "Resource": [
        "arn:aws:route53:::hostedzone/<hosted-zone-id>"
      ]
    }
  ]
}
EOF
)

aws iam put-role-policy \
  --role-name "trust3-<runtime-name>-role" \
  --policy-name Trust3PermissionsPolicy \
  --policy-document "$POLICY_DOC"

Trust relationship for an existing role

If you reuse an existing role, set its trust policy — replace <oidc-arn> and <oidc-url> with your cluster's OIDC provider values:

JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "<oidc-arn>"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "<oidc-url>:aud": "sts.amazonaws.com",
                    "<oidc-url>:sub": "system:serviceaccount:<runtime-name>:*"
                }
            }
        }
    ]
}

Apply it — put the JSON above in a TRUST_POLICY variable, then:

Bash
1
2
3
aws iam update-assume-role-policy \
  --role-name "trust3-<runtime-name>-role" \
  --policy-document "$TRUST_POLICY"

Find your OIDC values:

Bash
aws eks describe-cluster --name <cluster-name> --query "cluster.identity.oidc.issuer" --output text

Remove https:// from the output to get <oidc-url>; the matching <oidc-arn> is arn:aws:iam::<account-id>:oidc-provider/<oidc-url>.


At deploy time

The portal shows the API key and private key for the runtime plane only once, together with the generated install commands (for Self-Managed, this includes the platform-bundle download). Have a secure place ready to store them before you start.

After running the install commands, verify all pods come up in Running state:

Bash
kubectl get pods -n <runtime-name>