This section covers preparing the environment, deploying the Protegrity Provisioned Cluster PPC on AWS, and installing features and protectors.
This is the multi-page printable view of this section. Click here to print.
Installation
1 - Prerequisites
Jump box
PPC is deployed and managed from a dedicated EC2 instance, referred to as the jump box.
A newly provisioned EC2 instance must be used as the jump box for PPC deployment.
The jump box must be provisioned in the same AWS region where the PPC cluster is deployed. This ensures proper connectivity and access to regional resources.
Supported operating systems: RHEL 10, Debian 12, or Debian 13.
Note: Ensure to retain the original jump box used for installation. A snapshot of the jump box must be maintained to prevent data loss.
AWS Account Details
A valid AWS account where Amazon EKS is to be deployed.
The AWS account ID and AWS region must be identified in advance, as all resources are provisioned in the selected region.
Virtual Private Cloud (VPC)
- An existing VPC must be available in the target AWS region.
- The VPC should be configured to support Amazon EKS workloads.
Subnet Requirements
- At least two private subnets must be available.
- Subnets must be distributed across two or more Availability Zones (AZs).
Zone Requirements
The cluster requires a minimum of two availability zones for high availability. It is required to have two zones available while deploying a PPC.
| Zones | Supported | Notes |
|---|---|---|
| 1 | No | Installation fails. |
| 2 | Yes | Minimum requirement for High Availability. |
Zones are derived from the private subnets which are provided. Each subnet maps to exactly one availability zone. During the installation, the bootstrap script validates that the selected subnets are in different Availability Zones.
Note: Zones cannot be changed after cluster creation.
Network requirements for shared VPC
Before installing, confirm with the network team that the selected subnet AZ IDs are enabled on the Transit Gateway attachment and that the egress firewall allows the subnet CIDRs. At least two selected AZs must have working egress. For more information, refer to EKS system node group stuck in CREATING.
Service Quotas
Verify that the AWS account has sufficient service quotas to support the deployment. At a minimum, ensure adequate limits for the following:
- EC2 instances based on node group size and instance types.
- VPC and networking limits, including subnets, route tables, and security groups.
- Elastic IP addresses and Load balancers.
If required, request quota increases through the AWS Service Quotas console before proceeding.
Service Control Policies (SCPs)
The AWS account must not have SCPs that restrict required permissions. In particular, SCPs must not block the following actions:
- eks:*
- ec2:*
- iam:PassRole
Restrictive SCPs may prevent successful cluster creation and resource provisioning.
Required IAM roles and permissions
This section describes the IAM roles and permissions required to deploy and manage PPC on Amazon EKS. Review and set up these roles before starting the installation.
IAM Roles
Contact the IT team to create the necessary IAM roles with the following permissions to create and manage AWS EKS resources. The IAM role names in the table link to AWS documentation about each role, and the policy names link to the AWS managed policy reference pages.
| IAM Role | Required Policies |
|---|---|
| Amazon EKS cluster IAM Role Manages the Kubernetes cluster. | - AmazonEKSBlockStoragePolicy - AmazonEKSClusterPolicy - AmazonEKSComputePolicy - AmazonEKSLoadBalancingPolicy - AmazonEKSNetworkingPolicy - AmazonEKSVPCResourceController - AmazonEKSServicePolicy - AmazonEBSCSIDriverPolicy |
| Amazon EKS node IAM Role Communicates with the node. | - AmazonEBSCSIDriverPolicy - AmazonEC2ContainerRegistryReadOnly - AmazonEKS_CNI_Policy - AmazonEKSWorkerNodePolicy - AmazonSSMManagedInstanceCore |
These policies are managed by AWS. For more information about AWS managed policies, refer to AWS managed policies for Amazon Elastic Kubernetes Service in the AWS documentation.
AWS IAM Permissions
The AWS IAM user or role to install PPC must have permissions to create and manage Amazon EKS clusters and the required supporting AWS resources.
EC2 Permissions
| Category | Required Permissions |
|---|---|
| Networking & VPC | ec2:DescribeVpcs ec2:DescribeSubnets ec2:DescribeVpcAttribute ec2:DescribeTags ec2:DescribeNetworkInterfaces |
| Security Groups | ec2:DescribeSecurityGroups ec2:DescribeSecurityGroupRules ec2:CreateSecurityGroup ec2:DeleteSecurityGroup ec2:AuthorizeSecurityGroupIngress ec2:AuthorizeSecurityGroupEgress ec2:RevokeSecurityGroupIngress ec2:RevokeSecurityGroupEgress |
| Launch Templates | ec2:DescribeLaunchTemplates ec2:DescribeLaunchTemplateVersions ec2:CreateLaunchTemplate ec2:DeleteLaunchTemplate |
| Instances | ec2:RunInstances |
| Tagging | ec2:CreateTags ec2:DeleteTags |
EKS Permissions
| Category | Required Permissions |
|---|---|
| Cluster Management | eks:CreateCluster eks:DescribeCluster |
| Node Groups | eks:CreateNodegroup eks:DescribeNodegroup |
| Add-ons | eks:CreateAddon eks:DescribeAddon eks:DescribeAddonVersions eks:DeleteAddon eks:ListAddons |
| Pod Identity Associations | eks:CreatePodIdentityAssociation eks:DescribePodIdentityAssociation eks:DeletePodIdentityAssociation eks:ListPodIdentityAssociations |
| Tagging | eks:TagResource |
IAM Permissions
| Category | Required Permissions |
|---|---|
| Roles & Policies | iam:CreateRole iam:DeleteRole iam:TagRole iam:GetRole iam:ListRoles iam:AttachRolePolicy iam:DetachRolePolicy iam:ListRolePolicies iam:ListAttachedRolePolicies |
| Policies | iam:CreatePolicy iam:DeletePolicy iam:TagPolicy iam:GetPolicy iam:GetPolicyVersion iam:ListPolicyVersions |
| Instance Profiles | iam:CreateInstanceProfile iam:DeleteInstanceProfile iam:TagInstanceProfile iam:GetInstanceProfile iam:AddRoleToInstanceProfile iam:RemoveRoleFromInstanceProfile iam:ListInstanceProfilesForRole |
| Service-linked Role | iam:CreateServiceLinkedRole |
AWS S3 Permissions
| Required Permissions |
|---|
| s3:ListBucket |
| s3:PutEncryptionConfiguration |
| s3:GetEncryptionConfiguration |
| s3:PutBucketVersioning |
| s3:GetObjectTagging |
| s3:ListBucketVersions |
| s3:DeleteObjectVersion |
KMS Permissions
| Required Permissions |
|---|
| kms:CreateKey |
| kms:PutKeyPolicy |
| kms:GetKeyPolicy |
Applying the IAM Roles and Permissions using JSON
The roles and permissions are updated using the JSONs.
From the AWS Console, navigate to IAM > Policies > Create policy > JSON, and create the following JSONs.
Note: Before using the provided JSON, replace the
AWS_ACCOUNT_IDandREGIONvalues with those of the account and region where the resources are being deployed.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOnlyAccess",
"Effect": "Allow",
"Action": [
"eks:DescribeClusterVersions",
"ec2:DescribeInstances",
"ec2:DescribeVolumes",
"s3:ListAllMyBuckets",
"iam:ListUsers",
"ec2:RunInstances",
"ec2:DescribeInstances",
"ec2:DescribeVolumes",
"ec2:CreateKeyPair",
"ec2:DescribeImages"
],
"Resource": "*"
},
{
"Sid": "ScopedS3AndKMS",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:PutEncryptionConfiguration",
"s3:GetEncryptionConfiguration",
"kms:CreateKey",
"kms:PutKeyPolicy",
"kms:GetKeyPolicy"
],
"Resource": [
"arn:aws:s3:::*",
"arn:aws:kms:*:<AWS_ACCOUNT_ID>:key/*"
]
},
{
"Sid": "SelfServiceIAM",
"Effect": "Allow",
"Action": [
"iam:ListSSHPublicKeys",
"iam:ListServiceSpecificCredentials",
"iam:GetLoginProfile",
"iam:ListAccessKeys",
"iam:CreateAccessKey"
],
"Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:user/${aws:username}"
},
{
"Sid": "EC2KeyPairPermission",
"Effect": "Allow",
"Action": [
"ec2:CreateKeyPair",
"ec2:DescribeKeyPairs"
],
"Resource": [
"*"
]
}
]
}
- Creating EC2 Service Policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyEC2Instances",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringLike": {
"ec2:InstanceType": [
"p*",
"g*",
"inf*",
"trn*",
"x*",
"u-*",
"z*",
"mac*"
]
}
}
},
{
"Sid": "ReadOnlyDescribeListEC2RegionRestricted",
"Effect": "Allow",
"Action": [
"ec2:DescribeVpcs",
"ec2:DescribeSubnets",
"ec2:DescribeVpcAttribute",
"ec2:DescribeTags",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSecurityGroupRules",
"ec2:DescribeLaunchTemplates",
"ec2:DescribeLaunchTemplateVersions",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeAccountAttributes"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"<REGION>"
]
}
}
},
{
"Sid": "EC2LifecycleAndSecurity",
"Effect": "Allow",
"Action": [
"ec2:CreateSecurityGroup",
"ec2:DeleteSecurityGroup",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:RevokeSecurityGroupIngress",
"ec2:RevokeSecurityGroupEgress",
"ec2:CreateLaunchTemplate",
"ec2:DeleteLaunchTemplate",
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": [
"arn:aws:ec2:*:*:security-group/*",
"arn:aws:ec2:*:*:launch-template/*",
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:network-interface/*",
"arn:aws:ec2:*:*:subnet/*",
"arn:aws:ec2:*:*:vpc/*",
"arn:aws:ec2:*:*:image/*",
"arn:aws:ec2:*:*:volume/*",
"arn:aws:ec2:*:*:snapshot/*"
]
}
]
}
- Creating EKS Service Policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOnlyDescribeListEKSVersionsRegionRestricted",
"Effect": "Allow",
"Action": [
"eks:DescribeAddonVersions"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"<REGION>"
]
}
}
},
{
"Sid": "ReadOnlyDescribeListEKS",
"Effect": "Allow",
"Action": [
"eks:DescribeCluster",
"eks:DescribeAddon",
"eks:DescribePodIdentityAssociation",
"eks:DescribeNodegroup",
"eks:ListAddons",
"eks:ListPodIdentityAssociations"
],
"Resource": [
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:cluster/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:nodegroup/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:addon/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:podidentityassociation/*"
]
},
{
"Sid": "EKSLifecycleAndTag",
"Effect": "Allow",
"Action": [
"eks:CreateCluster",
"eks:UpdateClusterVersion",
"eks:UpdateClusterConfig",
"eks:CreateNodegroup",
"eks:UpdateNodegroupConfig",
"eks:UpdateNodegroupVersion",
"eks:DeleteNodegroup",
"eks:CreateAddon",
"eks:UpdateAddon",
"eks:DeleteAddon",
"eks:CreatePodIdentityAssociation",
"eks:DeletePodIdentityAssociation",
"eks:TagResource",
"eks:ListClusters"
],
"Resource": [
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:cluster/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:nodegroup/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:addon/*",
"arn:aws:eks:*:<AWS_ACCOUNT_ID>:podidentityassociation/*"
]
},
{
"Sid": "AllowEKSNodegroupSLR",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:CreateServiceLinkedRole"
],
"Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/aws-service-role/eks-nodegroup.amazonaws.com/AWSServiceRoleForAmazonEKSNodegroup"
},
{
"Sid": "EKSDeleteClusterV6",
"Effect": "Allow",
"Action": "eks:DeleteCluster",
"Resource": "arn:aws:eks:*:<AWS_ACCOUNT_ID>:cluster/*"
}
]
}
- Creating IAM Service Policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAdminPolicyAttachment",
"Effect": "Deny",
"Action": [
"iam:AttachRolePolicy",
"iam:PutRolePolicy"
],
"Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*",
"Condition": {
"ArnLike": {
"iam:PolicyARN": [
"arn:aws:iam::aws:policy/AdministratorAccess",
"arn:aws:iam::aws:policy/PowerUserAccess",
"arn:aws:iam::aws:policy/*FullAccess"
]
}
}
},
{
"Sid": "DenyInlinePolicyEscalation",
"Effect": "Deny",
"Action": [
"iam:PutRolePolicy",
"iam:PutUserPolicy",
"iam:PutGroupPolicy"
],
"Resource": "*"
},
{
"Sid": "ReadOnlyDescribeListIAMScoped",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:ListRolePolicies",
"iam:ListAttachedRolePolicies",
"iam:ListInstanceProfilesForRole",
"iam:GetInstanceProfile",
"iam:GetPolicy",
"iam:GetPolicyVersion",
"iam:ListPolicyVersions",
"iam:ListAccessKeys"
],
"Resource": [
"arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*",
"arn:aws:iam::<AWS_ACCOUNT_ID>:instance-profile/eks-*",
"arn:aws:iam::<AWS_ACCOUNT_ID>:policy/eks-*"
]
},
{
"Sid": "ReadOnlyDescribeListUnavoidableStar",
"Effect": "Allow",
"Action": "iam:ListRoles",
"Resource": "*"
},
{
"Sid": "IAMLifecycleRolesPoliciesInstanceProfiles",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:TagRole",
"iam:CreatePolicy",
"iam:DeletePolicy",
"iam:DeletePolicyVersion",
"iam:TagPolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:CreateInstanceProfile",
"iam:TagInstanceProfile",
"iam:AddRoleToInstanceProfile",
"iam:RemoveRoleFromInstanceProfile",
"iam:DeleteInstanceProfile"
],
"Resource": [
"arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*",
"arn:aws:iam::<AWS_ACCOUNT_ID>:policy/eks-*",
"arn:aws:iam::<AWS_ACCOUNT_ID>:instance-profile/eks-*"
]
},
{
"Sid": "EKSDeleteRoles",
"Effect": "Allow",
"Action": "iam:DeleteRole",
"Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks*"
},
{
"Sid": "PassRoleOnlyToEKS",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*",
"Condition": {
"StringEquals": {
"iam:PassedToService": [
"eks.amazonaws.com",
"ec2.amazonaws.com",
"eks-pods.amazonaws.com",
"pods.eks.amazonaws.com"
]
}
}
},
{
"Sid": "PassRoleForEKSPodIdentityRoles",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*-karpenter-role",
"arn:aws:iam::<AWS_ACCOUNT_ID>:role/eks-*-backup-recovery-utility-role"
]
}
]
}
- Creating KMS Service Policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "KMSCreateAndList",
"Effect": "Allow",
"Action": [
"kms:CreateKey",
"kms:ListAliases"
],
"Resource": "*"
},
{
"Sid": "KMSKeyManagementScoped",
"Effect": "Allow",
"Action": [
"kms:PutKeyPolicy",
"kms:GetKeyPolicy",
"kms:DescribeKey",
"kms:GenerateDataKey",
"kms:Decrypt",
"kms:TagResource",
"kms:UntagResource",
"kms:EnableKeyRotation",
"kms:GetKeyRotationStatus",
"kms:ListResourceTags",
"kms:ScheduleKeyDeletion",
"kms:CreateAlias",
"kms:DeleteAlias"
],
"Resource": [
"arn:aws:kms:*:<AWS_ACCOUNT_ID>:key/*",
"arn:aws:kms:*:<AWS_ACCOUNT_ID>:alias/*"
]
}
]
}
- Creating AWS S3 Service Policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3EncryptionConfigAndStateScoped",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetEncryptionConfiguration",
"s3:PutEncryptionConfiguration",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:CreateBucket",
"s3:GetBucketTagging",
"s3:GetBucketPolicy",
"s3:GetBucketAcl",
"s3:GetBucketCORS",
"s3:PutBucketTagging",
"s3:GetBucketWebsite",
"s3:GetBucketVersioning",
"s3:GetAccelerateConfiguration",
"s3:GetBucketRequestPayment",
"s3:GetBucketLogging",
"s3:GetLifecycleConfiguration",
"s3:GetReplicationConfiguration",
"s3:GetBucketObjectLockConfiguration",
"s3:DeleteBucket",
"s3:PutBucketVersioning",
"s3:ListBucketVersions",
"s3:DeleteObjectVersion",
"s3:GetObjectTagging"
],
"Resource": "arn:aws:s3:::*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"<REGION>"
],
"aws:PrincipalAccount": "<AWS_ACCOUNT_ID>"
}
}
}
]
}
Creating AWS KMS Key and AWS S3 Bucket
Amazon S3 Bucket: An Amazon S3 bucket is required to store critical data such as backups, configuration artifacts, and restore metadata used during installation and recovery workflows. Using a dedicated AWS S3 bucket helps ensure data durability, isolation, and controlled access during cluster operations.
AWS KMS Key: An AWS KMS customer‑managed key is required to encrypt data stored in the AWS S3 bucket. This ensures that sensitive data is protected at rest and allows customers to manage encryption policies, key rotation, and access control in accordance with their security requirements.
Note: The KMS key must allow access to the IAM roles used by the EKS cluster and related services.
The following section explains how to create AWS KMS Key and AWS S3 Bucket. This can be done from the AWS Web UI or using the script.
- Create a KMS key for backup bucket.
The KMS key created is referenced during installation and restore using its KMS ARN, and is validated by the installer.
Before you begin, ensure to have:
Access to the AWS account where the KMS key is created.
The KMS key can be in the same AWS account as the AWS S3 bucket, or in a different, cross‑account AWS account.
The user running the installer must have the permission
kms:DescribeKeyto describe the KMS key. If this permission is unavailable, then installation and restore fails.
The steps to create a KMS key are available at https://docs.aws.amazon.com/. Follow the KMS key creation steps, but ensure to select the following configurations.
On the Key configuration page:
Select Key type as Symmetric.
Select Key usage as Encrypt and decrypt.These settings are required for encrypting and decrypting AWS S3 objects used by backup and restore operations.
On the Key Administrative Permissions page, select the users or roles that can manage the key. The key administrators do not automatically get permission to encrypt or decrypt data unless these permissions are explicitly granted.
On the Define key usage permissions page, grant permissions to the principals that will use the key.
The user or role running the installation and restore must have the permission
kms:DescribeKeyto describe the key. This permission is mandatory because the installer validates the KMS key before proceeding. Without this, the installation or restore procedure fails, especially in cross‑account KMS scenarios.On the Edit key policy - optional page, click Edit.
The KMS key policy controls the access to the encryption key and must be applied before creating the AWS S3 bucket.
If you are using AWS SSO IAM Identity Center, ensure that the IAM role ARN specified in the KMS key policy includes the full SSO path prefix:
aws-reserved/sso.amazonaws.com/.
For example:arn:aws:iam::<ACCOUNT_ID>:role/aws-reserved/sso.amazonaws.com/<SSO_ROLE_NAME>
Omitting this path results in KMS key policy creation failures with anInvalidArnException.
The following example shows a key policy that:
Allows the PPC bootstrap user to use the KMS key for cluster creation and backup operations.
Allows the IAM role to encrypt and decrypt EKS backups.
cat > kms-key-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Id": "key-resource-policy-0",
"Statement": [
{
"Sid": "Allow KMS administrative actions only, no key usage permissions.",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<<ADMIN_AWS_ACCOUNT>>:root"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow user running bootstrap.sh script of the PPC to use the KMS key.",
"Effect": "Allow",
"Principal": {
"AWS": "<<SSO_OR_IAM_USER_ACCOUNT_ARN>>"
},
"Action": [
"kms:DescribeKey",
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncryptFrom",
"kms:ReEncryptTo",
"kms:GenerateDataKey",
"kms:GenerateDataKeyWithoutPlaintext"
],
"Resource": "*"
},
{
"Sid": "Allow backup recovery utility and EKS Node roles KMS key usage permissions, Replace <<<<CLUSTER_NAME>>>> with the name of your EKS cluster.",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<<DEPLOYMENT_AWS_ACCOUNT>>:root"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:ReEncryptFrom",
"kms:ReEncryptTo",
"kms:GenerateDataKey",
"kms:GenerateDataKeyWithoutPlaintext",
"kms:GenerateDataKeyPair",
"kms:GenerateDataKeyPairWithoutPlaintext",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"ArnLike": {
"aws:PrincipalArn": [
"arn:aws:iam::<<DEPLOYMENT_AWS_ACCOUNT>>:role/eks-<<CLUSTER_NAME>>-backup-recovery-utility-role",
"arn:aws:iam::<<DEPLOYMENT_AWS_ACCOUNT>>:role/eks-<<CLUSTER_NAME>>-node-role"
]
}
}
}
]
}
EOF
Update the values of the following based on the environment:
DEPLOYMENT_AWS_ACCOUNT- AWS account ID.CLUSTER_NAME- EKS cluster name.SSO_OR_IAM_USER_ACCOUNT_ARN- ARN of the IAM role used to run the bootstrap script. The ARN format depends on your authentication method:IAM role – Use the ARN returned by
aws sts get-caller-identity.AWS SSO (IAM Identity Center) – Convert the session ARN returned by
aws sts get-caller-identityto a full IAM role ARN before using it in the KMS key policy.If you are using AWS SSO (IAM Identity Center), the ARN returned by
aws sts get-caller-identityis a session ARN and cannot be used directly in an AWS KMS key policy. AWS KMS requires the full IAM role ARN, including theaws-reserved/sso.amazonaws.com/path. Without this, KMS key policy creation fails withInvalidArnException.
Retrieving the IAM role ARN for KMS key policy
To identify the role used to run the bootstrap script, run the following command:
aws sts get-caller-identity --query Arn --output text
IAM role: Use the returned ARN directly.
arn:aws:iam::<DEPLOYMENT_AWS_ACCOUNT>:role/your-role-nameAWS SSO (IAM Identity Center): The command returns a session ARN, which must be converted.
Do not use the session ARN:
arn:aws:sts::<<DEPLOYMENT_AWS_ACCOUNT>>:assumed-role/AWSReservedSSO_PermissionSetName_abc123/john.doe@company.comUse this converted IAM role ARN in KMS policy:
arn:aws:iam::<<DEPLOYMENT_AWS_ACCOUNT>>:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_PermissionSetName_abc123To convert:
- Replace
arn:aws:sts::witharn:aws:iam::. - Replace
assumed-role/withrole/aws-reserved/sso.amazonaws.com/. - Remove the session suffix (everything after the last /).
- Replace
Important: Before initiating restore operation, review and update the KMS key policy to reflect the restore
CLUSTER_NAME. Even if the policy was already configured for the source cluster, it must be updated for the new restore cluster. If the policy continues to reference the source cluster name, the IAM role created during restore cannot decrypt the backup data, causing the restore to fail.
After the KMS key is created, note the KMS key ARN. This KMS key ARN is required while creating the AWS S3 backup bucket.
- Create an AWS S3 Bucket encrypted with SSE‑KMS
The AWS S3 bucket encrypted with SSE‑KMS is used as a backup bucket during installation and restore.
Before you begin, ensure to have:
Access to the AWS account where the AWS S3 bucket will be created.
Permission to create AWS S3 bucket.
The user running the installer must have permission to describe the KMS key. Without this permission, installation and restore fails.
The steps to create an AWS S3 bucket are available at https://docs.aws.amazon.com/. Follow the AWS S3 bucket creation steps, but ensure to set the following configurations as mentioned below.
In the Default Encryption section:
Select Encryption type as Server-side encryption with AWS Key Management Service keys (SSE-KMS).
Select the AWS KMS key ARN. If the KMS key is in a different AWS account than the AWS S3 bucket, then the key will not appear in the AWS console dropdown. In this case, enter the KMS key ARN manually.
Enable Bucket Key.
Automatic AWS KMS Key and S3 Bucket Provisioning
When deploying PPC using the bootstrap script, the AWS S3 bucket and KMS key can be provisioned automatically during the installation process, without any separate pre-installation steps.
During the bootstrap script execution, at step 5, you are prompted to choose how to provide the AWS S3 bucket for cluster backups:
Do you want to use an existing AWS S3 bucket, or provision a new one (with KMS key)?
1) Use existing
2) Provision new via Tofu (backup-infra)
Select Option 2 - Provision new via Tofu to have the bootstrap script automatically:
- Create a new AWS KMS key.
- Create a new AWS S3 bucket encrypted with SSE-KMS.
- Associate the AWS S3 bucket with the KMS key.
At step 6, when prompted, provide a globally unique bucket name using the following naming rules:
- Lowercase letters, digits, and hyphens only.
- Between 3 and 63 characters.
- Must not already exist.
Note: The AWS S3 bucket and KMS key are created in the same AWS account using this option. For cross-account KMS configurations, follow the steps in the Using AWS Web UI tab.
Use a dedicated AWS S3 bucket per cluster for backup and restore operations to ensure data and encryption isolation. Sharing a bucket across clusters increases the risk of cross-cluster data access or decryption due to IAM misconfiguration.
Blocking Public Access to the AWS S3 Bucket
The PPC bootstrap script does not configure AWS S3 Block Public Access at the per-bucket level. This is by design because many AWS Organizations enforce AWS S3 Block Public Access through Service Control Policies (SCPs) at the account or organization level. This causes per-bucket s3:PutBucketPublicAccessBlock calls to fail with AccessDenied. AWS enabled S3 Block Public Access by default for all new accounts created after April 2023. However, verify the settings manually before proceeding.
Warning: The AWS S3 backup bucket stores highly sensitive data. Ensure that AWS S3 Block Public Access is enforced at the AWS account or organization level to prevent accidental public exposure.
Verify that AWS S3 Block Public Access is enabled at the account level before deploying PPC:
Navigate to the Amazon AWS S3 console.
Click Account and organization settings from the left navigation.
Ensure all four settings are enabled and set to On:
- Block public access to buckets and objects granted through new access control lists (ACLs)
- Block public access to buckets and objects granted through any access control lists (ACLs)
- Block public access to buckets and objects granted through new public bucket or access point policies
- Block public and cross-account access to buckets and objects through any public bucket or access point policies
If it is set to Off, then click Edit, select the check boxes, and click Save changes.
Verify that the Block Public Access settings for this account are enabled using the following command:
aws s3control get-public-access-block --account-id $(aws sts get-caller-identity --query Account --output text)All four fields
BlockPublicAcls,IgnorePublicAcls,BlockPublicPolicy,RestrictPublicBucketsshould be set totrue.
Note: To block the permissions at the bucket level, navigate to Buckets > General purpose buckets > select the bucket > Permissions > Block public access (bucket settings).
Installing or upgrading PPC in a region that does not support secure Bottlerocket AMIs
The service endpoints and the secure Bottlerocket AMI are available in a limited set of AWS regions. Regions such as eu-west-2 (London) do not offer secure endpoints for the AWS services that PPC depends on, and the secure Bottlerocket AMI is not published in every region.
To determine whether your target region supports secure Bottlerocket AMIs, use the following references:
Secure endpoints and services by region. Refer to AWS Regional Services List in the AWS official documentation for the current list of regions with secure endpoints and the services in scope.
Secure Bottlerocket AMI availability. Verify that the SSM parameter
/aws/service/bottlerocket/aws-k8s-<eks-version>-fips/<arch>/latest/image_idresolves in the target region:aws ssm get-parameter \ --region <region> \ --name "/aws/service/bottlerocket/aws-k8s-<eks-version>-fips/<arch>/latest/image_id"If the command returns
ParameterNotFound, the secure Bottlerocket AMI is not published in that region.
If secure Bottlerocket AMIs are not supported in the target region, use the standard deployment or upgrade path:
- To install PPC in a region that does not support secure Bottlerocket AMIs, refer to Configuring for a Standard Deployment in the respective section of Deploying PPC.
- To upgrade PPC in a region that does not support secure Bottlerocket AMIs, refer to Using Standard Bottlerocket AMI Deployment in the automated upgrade procedure.
Readiness check
The readiness check script validates the AWS credentials and confirms that the IAM permissions required to install PPC are available. If any required permission is missing, the script reports it and exits.
Navigate to the bootstrap-scripts directory and run the following script:
./readiness-aws.sh
After the readiness check is completed successfully, ensure to run the following checks for the selected region and architecture.
Supported Resources
While installing a cluster, the nodes are provisioned in two ways, that is, a managed node group and Karpenter. Therefore, both must be validated for the selected architecture.
Node pools overview
| Node pool | Provisioned by | Purpose |
|---|---|---|
| System pool | Managed node group | Critical add-ons only (Karpenter, CoreDNS) |
| Application pool | Karpenter | Application workloads |
System pool — default instance type
| Architecture | Default instance type |
|---|---|
| amd64 | t3.medium (2 vCPU / 4 GiB) |
| arm64 | t4g.medium (2 vCPU / 4 GiB) |
Application pool (Karpenter) — default instance type
| Architecture | Default family | Default instance type |
|---|---|---|
| amd64 | t3 | t3.2xlarge (8 vCPU / 32 GiB) |
| arm64 | t4g | t4g.2xlarge (8 vCPU / 32 GiB) |
Application pool (Karpenter) — Supported instance families
| Architecture | Supported instance families |
|---|---|
| amd64 | m5, m6i, c5, r5, t3, t3a |
| arm64 | t4g |
Availability Zones
Each instance type must be validated individually and must be available in at least 2 availability zones.
To verify the number of available availability zones on each instance type, run the following command:
REGION="<enter-your-region>" # e.g. us-east-1
INSTANCE_TYPE="<enter-instance-type>" # e.g. t3.2xlarge
aws ec2 describe-instance-type-offerings \
--region "$REGION" \
--location-type availability-zone \
--filters "Name=instance-type,Values=${INSTANCE_TYPE}" \
--query "InstanceTypeOfferings[].Location" --output table
For successfully validating the availability zones, the following output must be verified.Pass = the output lists 2 or more Availability Zones.
Validating IAM and SCP
The access to launch nodes in the required IAM and SCP is available.
To verify the required IAM and SCP access, run the following command:
REGION="<enter-your-region>" # e.g. us-east-1
ARCH="<enter-architecture>" # x86_64 for amd64, arm64 for arm64
INSTANCE_TYPE="<enter-instance-type>" # e.g. t3.2xlarge
SUBNET_ID="<enter-subnet-id>" # a private subnet in the target AZ
# Resolve a valid AMI id (public SSM parameter)
AMI_ID=$(aws ssm get-parameter --region "$REGION" \
--name "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${ARCH}" \
--query 'Parameter.Value' --output text)
# Resolve a security group from the subnet's VPC
VPC_ID=$(aws ec2 describe-subnets --region "$REGION" \
--subnet-ids "$SUBNET_ID" --query 'Subnets[0].VpcId' --output text)
SG_ID=$(aws ec2 describe-security-groups --region "$REGION" \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'SecurityGroups[0].GroupId' --output text)
# Dry-run launch (nothing is created)
aws ec2 run-instances --dry-run \
--region "$REGION" \
--instance-type "$INSTANCE_TYPE" \
--image-id "$AMI_ID" \
--subnet-id "$SUBNET_ID" \
--security-group-ids "$SG_ID"
After successful validation, a DryRunOperation: Request would have succeeded, but DryRun flag is set. message appears.
If the script fails with the UnauthorizedOperation message, then it might be blocked by IAM or an SCP.Fix the IAM or SCP, and then run the script for each subnet or AZ and instance type.
EC2 On-Demand vCPU service quota
The instance is within the EC2 On-Demand vCPU service quota for the required node count.
To verify the EC2 On-Demand vCPU service quota, run the following command:
REGION="<enter-your-region>" # e.g. us-east-1
# Quota L-1216C47A = Running On-Demand Standard (A,C,D,H,I,M,R,T,Z) instances
aws service-quotas get-service-quota \
--service-code ec2 --quota-code L-1216C47A \
--region "$REGION" --query 'Quota.Value' --output text
Note: PPC requires 28–32 vCPUs with the default node sizing. Ensure this capacity is available in addition to current account usage. Additionally, verify the available headroom in the AWS Service Quotas console and request a quota increase if required.
2 - Preparing for PPC deployment
If the jump box is already set previously, run the ./bootstrap.sh --cloud aws destroy command in the directory where the cluster is installed. This ensures that the local registry on the jump box and the clusters are cleaned up before proceeding with a new installation.
Warning: Do not install or manage multiple clusters from the same working directory. Each cluster deployment maintains its own Terraform/OpenTofu state, and reusing a directory can overwrite state files, causing loss of cluster tracking and unintended cleanup behavior.
Use a dedicated directory, and jump box, where possible, per cluster, and always verify the active kubectl context before running cleanup commands such as./bootstrap.sh --cloud aws destroy.
Log in to the My.Protegrity portal.
Navigate to Product Management > Explore Products > AI Team Edition > Platform Installation.
From the Actions column for Protegrity Provisioned Cluster, click the Download Product icon to download the PPC 1.2 archive.
Create a
deploymentdirectory on the jumpbox.mkdir deployment && cd deploymentCopy the PCT to the
deploymentdirectory on the jump box.Extract the PCT.
tar -xvf PPC-K8S-ALL_1.2.0.x.tarNote: For more information about the PCT, refer to My.Protegrity or the release notes.
3 - Deploying PPC
This section provides the steps to deploy the Protegrity Provisioned cluster (PPC) cluster. Review the prerequisites and choose the installation method that best fits your environment before you begin.
The PPC cluster can be deployed using one of the following methods:
Automated script-based installation: This method requires the
bootstrap.shscript to deploy the PPC cluster. The script installs the required software and dependencies, prompts to provide the required information, and deploys the cluster automatically.Manual component-based installation: This method requires to perform the deployment of each component to install the PPC cluster. The configuration files are edited to provide the required information and then deploy the cluster.
In-cluster deployment: This method is intended for users who already have an EKS 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.
3.1 - Automated script-based installation
Before you begin
- Before running the bootstrap as the root user on RHEL, ensure that /usr/local/bin, and the AWS CLI binary path, if applicable, is included in the $PATH. Alternatively, run the script using a non-root user, such as ec2-user, where /usr/local/bin is already part of the default PATH.
The repository provides a bootstrap script that automatically installs or updates the following software on the jump box:
- AWS CLI - Required to communicate with the AWS account.
- OpenTofu - Required to manage infrastructure as code.
- kubectl - Required to communicate with the Kubernetes cluster.
- Helm - Required to manage Kubernetes packages.
- skopeo - Required to copy and inspect container images across registries without requiring a daemon.
- jq - Required to parse JSON.
The bootstrap script also checks if you have the required permissions on AWS. It then sets up the EKS cluster and installs the microservices required for deploying the PPC.
Using Standard Bottlerocket AMI Deployment
Verify whether the secure Bottlerocket AMI is available before deciding to use the standard Bottlerocket AMI. Run the following AWS CLI command against the target region, replacing <region>, <eks-version>, and <arch> (x86_64 or arm64) with your values:
aws ssm get-parameter \
--region <region> \
--name "/aws/service/bottlerocket/aws-k8s-<eks-version>-fips/<arch>/latest/image_id"
If the command returns ParameterNotFound, then the secure Bottlerocket AMI is not published in that region, and you must complete the additional requirements. For the additional requirements, 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-based environments such as standard Intel or AMD servers)
arm64 (ARM-based environments such as AWS Graviton)
Deploying the PPC
The bootstrap script prompts for variables to be set to complete your deployment. Follow the instructions on the screen:
./bootstrap.sh --cloud aws
The script prompts for the following variables.
Enter 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
- Names longer than 31 characters (the cluster name must be 31 characters or fewer)
Note: Ensure that the cluster name does not exceed 31 characters. Cluster names longer than this limit can cause the bootstrap script to fail in subsequent installation steps. If the installation fails, specify a cluster name that is 31 characters or fewer and re-run the script. The script automatically applies the updated value and continues 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. t3, m5, c5 instances 2) arm64 (Graviton) — e.g. t4g, m7g, c7g instancesEnter
1to selectamd64or2to selectarm64.Note: Select
amd64for standard Intel/AMD 64-bit environments. Selectarm64for ARM-based environments such as AWS Graviton instances.- Lowercase letters:
Enter a VPC ID from the table
The script automatically retrieves the available VPCs. Enter the VPC ID where the cluster must be created.
Querying for subnets in VPC…
The script queries for the available VPC subnets and prompts to enter two private subnet IDs. Specify two private subnet IDs from different availability zones.
The script automatically updates the VPC CIDR block based on the VPC details.Enter FQDN
This is the Fully Qualified Domain Name (FQDN) for the ingress.
Warning: Ensure that the FQDN does not exceed 50 characters and only the following characters are used:
- Lowercase letters:
a-z - Numbers:
0-9 - Special characters:
- .
- Lowercase letters:
Select S3 Backup Bucket Option
The script prompts to choose how to provide the AWS S3 bucket encrypted with SSE‑KMS used for storing cluster backups for disaster recovery.
Do you want to use an existing S3 bucket, or provision a new one (with KMS key)? 1) Use existing 2) Provision new via Tofu (00_backup_bucket)Enter S3 bucket name
- Option 1 – Use existing: Enter the name of an existing S3 bucket in your AWS account. The bucket must already be encrypted with SSE‑KMS.
- Option 2 – Provision new via Tofu: The script uses OpenTofu (
00_backup_bucket) to create the S3 bucket and the corresponding KMS key on your behalf. Provide a globally unique bucket name when prompted:- Lowercase letters, digits, and hyphens only
- Between 3 and 63 characters
- Must not already exist
Note: Use a dedicated S3 bucket per cluster for backup and restore operations to ensure data and encryption isolation. Sharing a bucket across clusters increases the risk of cross-cluster data access or decryption due to IAM misconfiguration. Dedicated buckets with unique IAM policies eliminate this risk.
Note: During disaster management, OpenSearch restores only those snapshots that are created using the daily-insight-snapshots policy. For more information, refer to Backing up and restoring indexes.
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://’Note: The container registry endpoint must be a Fully Qualified Domain Name (FQDN). Sub-paths like,
<Container_Registry_Path>/v2/path, are not supported by the Open Container Initiative (OCI) distribution specification.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 aws
Important Information
Do not install or manage multiple clusters from the same working directory. Each cluster deployment maintains its own Terraform/OpenTofu state, and reusing a directory can overwrite state files, causing loss of cluster tracking and unintended cleanup behavior.
Use a dedicated directory, and jump box, where possible, per cluster, and always verify the active kubectl context before running cleanup commands such as
./bootstrap.sh --cloud aws destroy.
To check the active kubectl context, run the following command:kubectl config current-contextDo not delete the original cluster deployment directory, as it contains the Terraform state files required for managing the deployment.
Configuring for a Standard Deployment
Note: The following instructions are optional and only required for configuring a standard PPC deployment on AWS. Skip these steps if you have already installed the secure Bottlerocket AMIs.
By default, the PCT is configured to deploy a cluster using secure Bottlerocket AMIs. To deploy a standard cluster, the Terraform configuration files must be modified to use the standard Bottlerocket AMI types and SSM parameter paths before running the bootstrap script or the component-based installation.
For a standard PPC deployment on AWS EKS, perform the following steps:
Ensure that you have downloaded and extracted the PCT. For more information, refer to Preparing for PPC deployment.
Update the node group AMI type map in the
/03_node_group/variables.tffile.
The node_group_ami_type_map variable defines the fallback EKS AMI type used per node architecture when node_group_ami_type is not explicitly set. The secure Bottlerocket AMI defaults must be replaced with the corresponding standard Bottlerocket AMI types.
a. Navigate to /03_node_group directory.
cd iac/aws/cluster/modules/03_node_group/
b. Edit the variables.tf file to make the following changes.
Change from (secure defaults):
variable "node_group_ami_type_map" {
description = "Fallback EKS AMI type per architecture, used when node_group_ami_type is empty."
type = map(string)
default = {
amd64 = "BOTTLEROCKET_x86_64_FIPS"
arm64 = "BOTTLEROCKET_ARM_64_FIPS"
}
}
Change to (standard values):
variable "node_group_ami_type_map" {
description = "Fallback EKS AMI type per architecture, used when node_group_ami_type is empty."
type = map(string)
default = {
amd64 = "BOTTLEROCKET_x86_64"
arm64 = "BOTTLEROCKET_ARM_64"
}
}
- Update the Karpenter AMI SSM parameter path in the
/05_helm_releases/main.tffile.
The karpenter_fips_ami_ssm_parameter value specifies the AWS Systems Manager (SSM) parameter path that Karpenter uses to resolve the correct Bottlerocket AMI for worker nodes. The default path targets the secure Bottlerocket AMI. For a standard cluster, remove the -fips segment from the EKS version portion of the path.
a. Navigate to /05_helm_releases directory.
cd iac/aws/cluster/modules/05_helm_releases/
b. Edit the main.tf file to make the following changes.
Change from (secure SSM path):
karpenter_fips_ami_ssm_parameter = "/aws/service/bottlerocket/aws-k8s-${data.aws_eks_cluster.this.version}-fips/${local.karpenter_ami_arch}/latest/image_id"
Change to (standard SSM path):
karpenter_fips_ami_ssm_parameter = "/aws/service/bottlerocket/aws-k8s-${data.aws_eks_cluster.this.version}/${local.karpenter_ami_arch}/latest/image_id"
- After completing all these configuration changes, proceed to deploy the cluster.
Note: The additional requirements update the Terraform configuration files for the bootstrap script. Do not modify the
03_node_group/variables.tfor05_helm_releases/main.tffiles in the preceding installation steps. Reverting those changes will result in a secure cluster being deployed instead of a standard cluster.
3.2 - Manual component-based installation
This section is intended for enterprise customers who need full control over each stage of the EKS cluster deployment. Use this path when infrastructure stages must be reviewed or approved separately. Use it also 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. All stages must be performed from the same jump box.
Review the Deploying PPC overview and AWS prerequisites before running tofu apply.
Note: If you are performing a standard deployment, complete Configuring for a Standard Deployment before proceeding. Do not add or override
node_group_ami_typein the03_node_groupmodule’sterraform.tfvarsfile, as this will reintroduce secure Bottlerocket AMIs.
Deploying PPC using component-based installation
To deploy PPC using the component-based installation, perform the following steps
| Step | Action | Description |
|---|---|---|
| # | Before you begin | Reviews the jump box requirement and the values to decide before installation. |
| 1 | Preparing a jump box | Prepares a jump box with network access to the EKS cluster and Kubernetes API server. |
| 2 | Exporting AWS credentials | Exports AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN as environment variables to authenticate Terraform and AWS CLI operations. |
| 3 | Downloading and extracting the release PCT | Downloads and extracts the PPC release package on the jump box. |
| 4 | Installing the tools | Installs all required CLI tools (OpenTofu, AWS CLI, kubectl, Helm, and others) on the jump box, either automatically via bootstrap.sh install-tools or manually. |
| 5 | Provisioning the S3 bucket | (Skip if using an existing bucket) Provisions a new S3 bucket and KMS key for storing PPC backup data using the 00_backup_bucket Terraform module. |
| 6 | Modifying and applying terraform.tfvars files | Configures and applies five Terraform modules in sequence to provision all PPC infrastructure components. |
| 6a | 01_iam_roles module | Creates the EKS cluster IAM role, node group IAM role, and service account IAM roles required for the deployment. |
| 6b | 02_eks_cluster module | Provisions the EKS cluster, VPC security group, and networking add-ons (VPC CNI, kube-proxy). |
| 6c | 03_node_group module | Creates the EKS worker node group with the specified instance size, architecture, and subnet configuration. |
| 6d | 04_eks_addons module | Installs EKS add-ons including CoreDNS, Metrics Server, EBS CSI driver, and snapshot controller. |
| 6e | 05_helm_releases module | Deploys all PPC platform Helm charts including Karpenter, Velero, Envoy Gateway, and Insight. This step may take 15–20 minutes. |
| 7 | Verifying the installation | Confirms all cluster nodes are in Ready state, and all pods are in Running state. |
Before you begin
Ensure to have the following prerequisites before proceeding with the installation.
Values decided by user
| Value | Example |
|---|---|
| AWS credentials | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
| Cluster name | my-cluster |
| VPC ID | vpc-0abc123 |
| Two private subnet IDs | subnet-aaa, subnet-bbb |
| Ingress FQDN | myapp.example.com |
| S3 backup bucket name | my-backup-bucket (existing) or provision one in Step 5 |
| Image 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. |
| Registry username and password | Provided by organization |
Using Standard Bottlerocket AMI Deployment
By default, PPC deploys using the secure (FIPS) Bottlerocket AMI. Before choosing the standard Bottlerocket AMI, verify whether the secure AMI is available in your target region.
Run the following AWS CLI command, replacing <region>, <eks-version>, and <arch> with your values:
Architecture value: Use x86_64 for amd64 nodes, or arm64 for arm64 (Graviton) nodes. Do not use amd64, amd, or arm. The SSM parameter path must match exactly, or the lookup will fail.
EKS version value: Use the Kubernetes version with which the cluster will be created. This is the eks_cluster_version value in the 02_eks_cluster module in variables.tf file, and the default value is 1.35.
aws ssm get-parameter \
--region <region> \
--name "/aws/service/bottlerocket/aws-k8s-<eks-version>-fips/<arch>/latest/image_id"
For example, amd64 nodes, EKS 1.35, and us-east-1:
aws ssm get-parameter \
--region us-east-1 \
--name "/aws/service/bottlerocket/aws-k8s-1.35-fips/x86_64/latest/image_id"
Interpret the result as follows:
Returns an image ID: The secure Bottlerocket AMI is published in that region. Proceed with the default (secure) deployment. No additional steps are required.
Returns
ParameterNotFound: Before concluding the AMI is unavailable, verify the following:<arch>is exactlyx86_64orarm64.<eks-version>matches theeks_cluster_versionvalue in the02_eks_clustermodule (default1.35). For example,aws-k8s-1.35-fips.
Optionally, confirm which EKS versions AWS currently offers in the region. This works before any cluster exists.
aws eks describe-cluster-versions --region <region> --query "clusterVersions[].clusterVersion" --output table
If the command returns ParameterNotFound, then the secure Bottlerocket AMI is not published in that region, and you must complete the additional requirements. For the additional requirements, 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 EKS cluster. The jump box must be able to access the Kubernetes API server endpoint.
2. Exporting AWS credentials
The installation process uses Terraform to provision and manage AWS resources. These resources include VPCs, EKS clusters, IAM roles, and S3 buckets. The AWS credentials must be exported as environment variables to authenticate these operations.
Note: While using temporary credentials, such as AWS STS credentials, ensure the session token is included. Also confirm that the credentials have not expired before proceeding.
CLI login using AWS SSO (IAM Identity Center) is not supported. Export IAM user credentials or temporary STS credentials as environment variables.
If the components are installed by different users, ensure that each user must export their AWS credentials. This ensures that all the required access and permissions are available.
To export the AWS credentials, run the following commands:
export AWS_ACCESS_KEY_ID=<your-access-key-id>
export AWS_SECRET_ACCESS_KEY=<your-secret-access-key>
export AWS_SESSION_TOKEN=<your-session-token>
3. Downloading and extracting the release PCT
To download and extract the PCT, refer to Preparing for PPC deployment.
4. Installing the tools
The following tools and minimum versions are required for the component-based installation. Ensure they are installed on your jump box before proceeding, or use the bootstrap.sh install-tools command to install them automatically.
After downloading and extracting the PPC-K8S-ALL_1.2.0.x.tar as described in Preparing for PPC deployment, run the following command to install the required tools:
Note: For more information about the PCT, refer to My.Protegrity or the release notes.
./bootstrap.sh install-tools --cloud aws
Alternatively, the following tools must be installed and available on the jump box before starting.
| Tools Name | Description | Minimum Required Version |
|---|---|---|
| OpenTofu | Required to manage infrastructure as code (IaC) and provision cloud resources. | 1.11.5 |
| AWS CLI | Required to communicate with AWS and manage AWS resources. | 2.36.7 |
| kubectl | Required to communicate with and manage Kubernetes clusters. | 1.36.1 |
| Helm | Required to deploy and manage Kubernetes packages and applications. | 3.21.0 |
| skopeo | Required to inspect, copy, and transfer container images between registries. | 1.18.0 |
| jq | Required to parse, filter, and process JSON data. | 1.7 |
| bc | Required for version comparisons and resource calculations. | 1.07.1 |
| ssh-keygen | Required to generate and manage SSH keys for secure access to deployment environments. | OpenSSH_10.0p2 Debian-7+deb13u4 |
| oras | Required to pull OCI artifacts, including non-container deployment packages, from registries. | 1.3.3 |
| cmctl | Required to validate, manage, and troubleshoot cert-manager TLS certificates. | 2.5.0 |
5. Provisioning the S3 bucket
This step is required if a new S3 bucket is to be provisioned for storing the backup data. If an existing S3 bucket is to be used, note the bucket name and KMS key ARN. These values are required for the installation process. Then skip to the next step.
a. To navigate to 00_backup_bucket directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/00_backup_bucket"
b. Edit the terraform.tfvars file to provide the following information:
cluster_name = "<cluster-name>"
s3_bucket_name = "<globally-unique-bucket-name>"
kms_key_alias_name = "alias/pty-backup-<cluster-name>-key"
aws_region = "<region>"
c. 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"
After the S3 bucket is provisioned successfully, note the bucket name and KMS key ARN. These values are required during the installation process.
d. To sync the Terraform state file to the S3 bucket, run the following command:
# Navigate to the bootstrap-scripts directory
cd <package-root>/bootstrap-scripts
# Run the script to sync the backup data to the S3 bucket
./sync-backup-bucket-state-to-s3.sh
e. Verify the S3 bucket configuration and confirm the Terraform configuration and state files were uploaded. These checks confirm that the bucket is ready for backups. They also confirm that the KMS key is enabled with rotation. They further confirm that the artifacts needed to manage the bucket are stored in S3. Run the checks from the package root.
# --- Stage 00 parameters ---
export CLUSTER_NAME="<cluster-name>" # e.g. prod-eks-cluster
export REGION="<region>" # e.g. us-east-1
export BUCKET_NAME="<s3-bucket-name>" # e.g. modular-bucket
export KMS_ALIAS="<kms-key-alias>" # e.g. alias/pty-backup-<cluster-name>-key
# a. Bucket exists
aws s3api head-bucket --bucket "$BUCKET_NAME" --region "$REGION" && echo "Bucket exists"
# b. Versioning enabled
aws s3api get-bucket-versioning --bucket "$BUCKET_NAME" --region "$REGION" --output table
# c. Default encryption is KMS
aws s3api get-bucket-encryption --bucket "$BUCKET_NAME" --region "$REGION" \
--query "ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault" --output table
# d. KMS key enabled + rotation
aws kms describe-key --key-id "$KMS_ALIAS" --region "$REGION" \
--query "KeyMetadata.{KeyId:KeyId, Enabled:Enabled, State:KeyState}" --output table
KMS_KEY_ID=$(aws kms describe-key --key-id "$KMS_ALIAS" --region "$REGION" --query "KeyMetadata.KeyId" --output text)
aws kms get-key-rotation-status --key-id "$KMS_KEY_ID" --region "$REGION" --output table
# e. tfvars + state uploaded
aws s3 ls "s3://$BUCKET_NAME/infrastructure-manifest/$CLUSTER_NAME/tfvars/00_backup_bucket/" --region "$REGION"
aws s3 ls "s3://$BUCKET_NAME/infrastructure-manifest/$CLUSTER_NAME/states/" --region "$REGION"
# f. Record outputs
tofu output
The verification is complete when the bucket exists, versioning is Enabled, and encryption is aws:kms. The KMS key must be enabled with rotation. The tfvars and state files must be present in S3. Record s3_bucket_name and kms_key_arn.
6. Modifying and applying terraform.tfvars files
The iac/aws/cluster/modules/ directory contains the Terraform modules for the PPC installation. To enter details in the terraform.tfvars file, navigate to the appropriate module directory and edit the file accordingly.
After modifying the terraform.tfvars file, apply the changes.
01_iam_roles module
a. To navigate to 01_iam_roles directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/01_iam_roles"
b. Edit the terraform.tfvars file to provide the following information:
aws_region = "<region>"
eks_cluster_name = "<cluster-name>"
backup_bucket = "<s3-bucket-name>"
backup_bucket_kms_arn = "<kms-key-arn>"
c. 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"
d. Verify the IAM roles, customer-managed policies, role policy attachments, and node instance profile created by this module. The commands also confirm the module’s terraform.tfvars backup is in S3. They also display the role ARNs needed by later modules. Run them from the 01_iam_roles module directory:
# --- Stage 01 parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
export BUCKET_NAME="<s3-bucket-name>"
# a. Four IAM roles
aws iam list-roles --query "Roles[?contains(RoleName, '${CLUSTER_NAME}')].[RoleName, Arn]" --output table
# b. Customer-managed policies
aws iam list-policies --scope Local \
--query "Policies[?contains(PolicyName, '${CLUSTER_NAME}')].[PolicyName, Arn]" --output table
# c. Node role managed policies
aws iam list-attached-role-policies --role-name "eks-${CLUSTER_NAME}-node-role" \
--query "AttachedPolicies[].PolicyName" --output table
# d. Cluster role managed policies
aws iam list-attached-role-policies --role-name "eks-${CLUSTER_NAME}-cluster-role" \
--query "AttachedPolicies[].PolicyName" --output table
# e. Node instance profile
aws iam get-instance-profile --instance-profile-name "eks-${CLUSTER_NAME}-node-profile" \
--query "InstanceProfile.{Name:InstanceProfileName, Role:Roles[0].RoleName}" --output table
# f. tfvars backed up
aws s3 ls "s3://${BUCKET_NAME}/infrastructure-manifest/${CLUSTER_NAME}/tfvars/01_iam_roles/" --region "$REGION"
# g. Record role ARNs
tofu output
The verification is complete when all four roles (cluster-role, node-role, karpenter-role, and backup-recovery-utility-role) and four local policies exist. The node and cluster managed policies must be attached. The node instance profile must be linked. The terraform.tfvars file must be present in S3.
02_eks_cluster module
a. To navigate to 02_eks_cluster directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/02_eks_cluster"
b. Edit the terraform.tfvars file to provide the following information.
Note: The security group is created in AWS using the name specified by the
security_group_namevalue in this file.
Important: The security group name must follow the exact format
<cluster-name>_SG. TheSGmust be in uppercase. This value is used as the AWS Name tag on the worker security group. Protegrity components discover the security group by matching this tag value exactly. Tag values are case-sensitive. Any other format, for example, lowercase _sg or a custom name, will cause those components to fail. The security group name must also not start withSG.
aws_region = "<region>"
eks_cluster_name = "<cluster-name>"
backup_bucket = "<s3-bucket-name>"
# Important: The security group name must follow the exact format <cluster-name>_SG.
# The SG must be in uppercase. This value is used as the AWS Name tag on the worker security group.
# Protegrity components discover the security group by matching this tag value exactly.
# Tag values are case-sensitive. Any other format, for example, lowercase _sg or a custom name, will cause those components to fail.
# The security group name must also not start with SG.
# --- Networking ---
vpc_id = "<vpc-id>"
security_group_name = "<cluster-name>_SG" # Must match this format exactly
private_subnet_ids = [
"<subnet-a>",
"<subnet-b>"
]
# --- Tagging ---
owner_email = "<owner_email>"
# --- Access Entries (optional) ---
# Add IAM users/roles that need kubectl / tofu access beyond the original installer.
additional_access_entries = [
# {
# principal_arn = "<principal-arn>"
# },
]
c. 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"
d. After applying the configuration, verify the setup. Check the EKS cluster, security group, add-ons, subnet tags, and kubeconfig context by running the following commands:
# --- Stage 02 parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
export BUCKET_NAME="<s3-bucket-name>"
export SG_NAME="${CLUSTER_NAME}_SG" # worker SG name (uppercase SG)
# a. Cluster ACTIVE
aws eks describe-cluster --name "$CLUSTER_NAME" --region "$REGION" \
--query "cluster.{Name:name, Status:status, Version:version, Endpoint:endpoint}" --output table
# b. No nodes yet (expected)
kubectl get nodes # expected: No resources found (node group is Stage 03)
# c. Worker security group exists (exact name)
aws ec2 describe-security-groups --filters "Name=tag:Name,Values=${SG_NAME}" --region "$REGION" \
--query "SecurityGroups[].{Name:Tags[?Key=='Name']|[0].Value, ID:GroupId, VPC:VpcId}" --output table
# d. VPC CNI + kube-proxy ACTIVE
aws eks list-addons --cluster-name "$CLUSTER_NAME" --region "$REGION" --output table
for addon in vpc-cni kube-proxy; do
aws eks describe-addon --cluster-name "$CLUSTER_NAME" --addon-name "$addon" --region "$REGION" \
--query "addon.{Name:addonName, Status:status, Version:addonVersion}" --output table
done
# e. Subnet tags (cluster + Karpenter discovery)
aws ec2 describe-subnets --region "$REGION" \
--filters "Name=tag:kubernetes.io/cluster/${CLUSTER_NAME},Values=shared" \
--query "Subnets[].{Subnet:SubnetId, AZ:AvailabilityZone}" --output table
aws ec2 describe-subnets --region "$REGION" \
--filters "Name=tag:karpenter.sh/discovery/${CLUSTER_NAME},Values=true" \
--query "Subnets[].SubnetId" --output table
# f. kubeconfig context added
kubectl config get-contexts | grep "$CLUSTER_NAME"
# g. tfvars backed up
aws s3 ls "s3://${BUCKET_NAME}/infrastructure-manifest/${CLUSTER_NAME}/tfvars/02_eks_cluster/" --region "$REGION"
# h. Record outputs
tofu output
The verification is complete when the cluster is ACTIVE and kubectl get nodes returns No resources found. The <cluster>_SG security group must exist, and both add-ons must be ACTIVE. The required subnet tags must be present. The kubeconfig context must be added, and the terraform.tfvars file must be present in S3. Record private_subnet_ids, vpc_id, vpc_cidr_block, and worker_security_group_id.
03_node_group module
a. To navigate to 03_node_group directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/03_node_group"
b. Edit the terraform.tfvars file to provide the following information.
Note: Use the private subnet IDs from the VPC where the EKS cluster is provisioned while installing the
02_eks_clustermodule.
aws_region = "<region>"
eks_cluster_name = "<cluster-name>"
backup_bucket = "<s3-bucket-name>"
# --- System Node Group ---
node_group_name = "<node-group-name>"
private_subnet_ids = [
"<subnet-a>",
"<subnet-b>"
]
architecture = "<amd64/arm64>"
node_group_desired_size = 2
node_group_max_size = 2
node_group_min_size = 1
Note for standard deployments: If you completed the steps in Configuring for a Standard Deployment, the
node_group_ami_type_mapdefault values in variables.tf file have already been changed. The defaults are nowBOTTLEROCKET_x86_64(amd64) orBOTTLEROCKET_ARM_64(arm64). Do not add or overridenode_group_ami_typein the terraform.tfvars file. Doing so reintroduces secure Bottlerocket AMIs.
c. 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"
d. After applying the configuration, verify that the node group and worker nodes are healthy, the expected labels and taint are present, the launch template and EC2 instances exist, and the terraform.tfvars backup is in S3. Run these commands from the 03_node_group module directory:
# --- Stage 03 parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
export BUCKET_NAME="<s3-bucket-name>"
export NODE_GROUP_NAME="<node-group-name>" # e.g. modular-nodegroup_NG
# a. Node group ACTIVE
aws eks describe-nodegroup --cluster-name "$CLUSTER_NAME" --nodegroup-name "$NODE_GROUP_NAME" --region "$REGION" \
--query "nodegroup.{Name:nodegroupName, Status:status, AMIType:amiType, Instances:instanceTypes, Scaling:scalingConfig}" --output table
# b. Nodes Ready
kubectl get nodes -o wide
# c. Labels + taint
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.role}{"\t"}{.metadata.labels.nodepool-owner}{"\n"}{end}'
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.taints}{"\n"}{end}'
# d. Launch template exists (note: --launch-template-ids, NOT a filter)
aws ec2 describe-launch-templates --region "$REGION" \
--launch-template-ids "$(tofu output -raw launch_template_id)" \
--query "LaunchTemplates[].{Name:LaunchTemplateName, ID:LaunchTemplateId, Default:DefaultVersionNumber}" --output table
# Alternative by name:
# aws ec2 describe-launch-templates --region "$REGION" \
# --filters "Name=launch-template-name,Values=${NODE_GROUP_NAME}-*" \
# --query "LaunchTemplates[].{Name:LaunchTemplateName, ID:LaunchTemplateId, Default:DefaultVersionNumber}" --output table
# e. Worker EC2 instances running
aws ec2 describe-instances --region "$REGION" \
--filters "Name=tag:eks:nodegroup-name,Values=${NODE_GROUP_NAME}" "Name=instance-state-name,Values=running" \
--query "Reservations[].Instances[].{ID:InstanceId, Type:InstanceType, AZ:Placement.AvailabilityZone, State:State.Name}" --output table
# f. tfvars backed up
aws s3 ls "s3://${BUCKET_NAME}/infrastructure-manifest/${CLUSTER_NAME}/tfvars/03_node_group/" --region "$REGION"
# g. Record outputs + node OS details for Stage 05
tofu output
kubectl get nodes -o jsonpath='{.items[0].status.nodeInfo.osImage}'; echo
The verification is complete when the node group is ACTIVE and the desired number of nodes are Ready. Each node must have the role=system and nodepool-owner=ppc labels and the CriticalAddonsOnly taint. The launch template and running instances must exist. The terraform.tfvars file must be present in S3. Record node_group_name, the node architecture, and the node OS enum for Stage 05. The osImage output is informational. Do not copy it directly into node_os. For example, Bottlerocket OS 1.66.0 (aws-k8s-1.35-fips) on amd64 maps to architecture = "amd64". The same node maps to node_os = "BOTTLEROCKET_x86_64_FIPS".
04_eks_addons module
a. To navigate to 04_eks_addons directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/04_eks_addons"
b. Edit the terraform.tfvars file to provide the following information:
aws_region = "<region>"
eks_cluster_name = "<cluster-name>"
backup_bucket = "<s3-bucket-name>" #
# --- Storage classes ---
storage_class_name = "pty-sc" # default (general-purpose) StorageClass; must match Stage 05
# --- Upgrade mode only ---
# Set to "~/.kube/config" when upgrading an existing cluster;
# leave empty ("") for a fresh install.
kubeconfig_path = ""
c. 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: This stage waits for all nodes from Stage 03 to reach
Readystatus before installing add-ons.
d. After applying the configuration, verify the add-ons and related resources. Confirm that all EKS add-ons are active and that the default StorageClass settings are correct. Confirm that CoreDNS, Metrics Server, and the EBS CSI controller are running. Confirm that the Pod Identity associations exist and that the terraform.tfvars backup is in S3. Run these commands from the 04_eks_addons module directory:
# --- Stage 04 parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
export BUCKET_NAME="<s3-bucket-name>"
export STORAGE_CLASS="<storage-class-name>" # default pty-sc
# a. All add-ons ACTIVE
aws eks list-addons --cluster-name "$CLUSTER_NAME" --region "$REGION" --output table
for addon in coredns metrics-server aws-ebs-csi-driver snapshot-controller eks-pod-identity-agent; do
aws eks describe-addon --cluster-name "$CLUSTER_NAME" --addon-name "$addon" --region "$REGION" \
--query "addon.{Name:addonName, Status:status, Version:addonVersion}" --output table
done
# b. Default StorageClass exists
kubectl get storageclass
# c. StorageClass details
kubectl get storageclass "$STORAGE_CLASS" \
-o jsonpath='{.provisioner}{"\t"}{.reclaimPolicy}{"\t"}{.volumeBindingMode}{"\n"}'
# d. CoreDNS + Metrics Server running
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get pods -n kube-system -l app.kubernetes.io/name=metrics-server
# e. EBS CSI controller running
kubectl get deployment ebs-csi-controller -n kube-system \
-o jsonpath='{.status.readyReplicas}/{.status.replicas} ready{"\n"}'
kubectl get pods -n kube-system -l app=ebs-csi-controller
# f. Pod Identity associations
aws eks list-pod-identity-associations --cluster-name "$CLUSTER_NAME" --region "$REGION" \
--query "associations[].{Namespace:namespace, ServiceAccount:serviceAccount}" --output table
# g. tfvars backed up
aws s3 ls "s3://${BUCKET_NAME}/infrastructure-manifest/${CLUSTER_NAME}/tfvars/04_eks_addons/" --region "$REGION"
# h. Record outputs
tofu output
The verification is complete when all five add-ons are ACTIVE. ${STORAGE_CLASS} must be the default StorageClass with the ebs.csi.aws.com provisioner, a Retain reclaim policy, and WaitForFirstConsumer volume binding mode. CoreDNS, Metrics Server, and the EBS CSI controller must be running. Both Pod Identity associations (karpenter and backup-recovery-utility) must exist. The terraform.tfvars file must be present in S3.
05_helm_releases module
a. To navigate to 05_helm_releases directory, run the following command:
export PPC_DEPLOY_DIR=<path to PPC deployment directory>
cd "$PPC_DEPLOY_DIR/iac/aws/cluster/modules/05_helm_releases"
b. Edit the terraform.tfvars file to provide the following information.
The default node OS is BOTTLEROCKET_x86_64_FIPS. Set node_os to the platform enum, not the raw osImage string returned by kubectl. For FIPS Bottlerocket nodes, use BOTTLEROCKET_x86_64_FIPS for amd64 or BOTTLEROCKET_ARM_64_FIPS for arm64.
The following fields must be updated with environment-specific values:
| Field | Description |
|---|---|
aws_region | AWS region where the cluster is deployed. |
eks_cluster_name | Name of the EKS cluster. |
backup_bucket | Name of the S3 bucket for backups. |
backup_bucket_kms_arn | ARN of the KMS key used to encrypt the backup bucket. |
architecture | Node architecture: amd64 or arm64. |
node_os | Node OS enum matching the node architecture and FIPS status, such as BOTTLEROCKET_x86_64_FIPS. Do not use the raw kubectl osImage output. |
global_image_reg | Container image 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. |
ingress_fqdn | Fully qualified domain name for the ingress. |
owner_email | Email address of the cluster owner. |
vpc_cidr_block | CIDR block of the VPC, used to derive internal proxy CIDRs. |
The following fields have default values and must be left unchanged for a fresh installation:
| Field | Default value | Notes |
|---|---|---|
harbor_secret | "harbor-secret" | Fixed secret name; do not change. |
private_subnet_ids | [] | Populated automatically by bootstrap.sh from stage 02 state. |
restore | false | Set to true only when restoring from a backup. |
backup_name | "authnz-postgresql-schedule-backup" | Default backup schedule name; change only if restoring a custom backup. |
insight_backup_name | "" | Leave empty unless restoring an Insight backup. |
kubeconfig_path | "" | Leave empty for a fresh install; set to ~/.kube/config only for upgrades. |
is_upgrade | false | Set to true only when upgrading an existing cluster. |
skip_validations | false | Leave as false unless instructed otherwise. |
aws_region = "<region>"
eks_cluster_name = "<cluster-name>"
backup_bucket = "<s3-bucket-name>"
backup_bucket_kms_arn = "<kms-key-arn>"
storage_class_name = "<storage-class-name>"
backup_storage_class_name = "<backup-storage-class-name>"
# --- Readiness ---
architecture = "amd64"
node_os = "BOTTLEROCKET_x86_64_FIPS"
# --- Karpenter instance families (must be org SCP-approved, p-6aysnndi) ---
karpenter_instance_families = ["t3", "t4g"] # amd64: m5, m6i, c5, r5, t3, t3a; arm64: see arm64_instance_families below
arm64_instance_families = ["t4g"] # subset of karpenter_instance_families classified as arm64 (Graviton)
# --- Registry ---
global_image_reg = "<Container_Registry_Path>"
harbor_secret = "harbor-secret"
# --- Ingress ---
ingress_fqdn = "<fqdn>"
# --- Owner ---
owner_email = "<owner-email>"
# --- 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.
# --- Networking (used to derive internal proxy CIDRs) ---
vpc_cidr_block = "<cidr>"
# --- Envoy Gateway (LoadBalancer subnet discovery) ---
private_subnet_ids = []
# --- Restore ---
restore = false
backup_name = "authnz-postgresql-schedule-backup"
insight_backup_name = ""
# --- Upgrade mode only ---
# Set to "~/.kube/config" when upgrading an existing cluster;
# leave empty ("") for a fresh install.
kubeconfig_path = ""
is_upgrade = false
skip_validations = false
c. Save the file and exit the editor.
d. This step must be performed only if registry needs an authentication. Do not put them in the tfvars file.
To enter registry credentials using the environment variables, run the following commands:
export TF_VAR_username="<registry-username>"
export TF_VAR_password="<registry-password>"
e. To 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: This process may take 15–20 minutes to get completed. Karpenter nodes are provisioned on demand after the NodePool is created.
f. After applying the configuration, verify that all Helm releases are deployed. Confirm that the backup StorageClass exists and that Karpenter and Velero are running. Confirm that Envoy Gateway has provisioned a LoadBalancer and that Insight is healthy. Confirm that its bootstrap job has succeeded and that the terraform.tfvars backup is in S3. Run these commands from the 05_helm_releases module directory:
# --- Stage 05 parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
export BUCKET_NAME="<s3-bucket-name>"
export INSIGHT_NS=pty-insight
# a. All Helm releases deployed
helm list -A
# b. Backup StorageClass auto-created by this stage
kubectl get storageclass # expect pty-bkp in addition to pty-sc
# c. Karpenter running + NodePool/EC2NodeClass present
kubectl get pods -n karpenter
kubectl get nodepools
kubectl get ec2nodeclasses
# d. Velero running
kubectl get pods -n pty-backup-recovery
# e. Envoy Gateway running + LoadBalancer provisioned
kubectl get pods -n api-gateway
kubectl get svc -n api-gateway \
-o jsonpath='{range .items[?(@.spec.type=="LoadBalancer")]}{.metadata.name}{"\t"}{.status.loadBalancer.ingress[0].hostname}{"\n"}{end}'
# f. Insight pods healthy (incl. OpenSearch + Dashboards)
kubectl get pods -n "$INSIGHT_NS"
kubectl get pods -n "$INSIGHT_NS" -l app=opensearch-dashboards
# g. Insight bootstrap job succeeded (post-install hook)
kubectl get job -n "$INSIGHT_NS" initialize-opensearch-repository \
-o jsonpath='{.status.succeeded} succeeded / {.status.failed} failed{"\n"}'
# h. Cluster-wide: no unhealthy pods
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded
# i. tfvars backed up
aws s3 ls "s3://${BUCKET_NAME}/infrastructure-manifest/${CLUSTER_NAME}/tfvars/05_helm_releases/" --region "$REGION"
If the bootstrap job fails with a 403 anonymous/proxy-auth error (opendistro_security_anonymous), it indicates an OpenSearch Dashboards readiness or identity issue. It is not a node_os issue. Confirm the Dashboards pod is fully Ready, then rerun tofu apply from the 05_helm_releases module. This applies the corrected node_os and triggers a fresh post-install bootstrap attempt.
The verification is complete when all Helm releases are deployed and the pty-bkp backup StorageClass is present. Karpenter is running, and its NodePool and EC2NodeClass exist. Velero is running. Envoy Gateway is running with an external LoadBalancer address. The Insight pods, including OpenSearch Dashboards, are healthy. The initialize-opensearch-repository job has succeeded. The terraform.tfvars file is present in S3. No pods remain in a phase other than Running or Succeeded.
7. Verifying the installation
To verify the installation, run the following command:
# --- parameters ---
export CLUSTER_NAME="<cluster-name>"
export REGION="<region>"
kubectl get nodes # all Ready
kubectl get pods -A # all Running / Completed
All the nodes should be in the Ready state, and all the pods should be in the Running state.
Configuring for a Standard Deployment
Note: The following instructions are optional and only required for configuring a standard PPC deployment on AWS. Skip these steps if you have already installed the secure Bottlerocket AMIs.
By default, the PCT is configured to deploy a cluster using secure Bottlerocket AMIs. To deploy a standard cluster, the Terraform configuration files must be modified to use the standard Bottlerocket AMI types and SSM parameter paths before running the bootstrap script or the component-based installation.
For a standard PPC deployment on AWS EKS, perform the following steps:
Ensure that you have downloaded and extracted the PCT. For more information, refer to Preparing for PPC deployment.
Update the node group AMI type map in the
/03_node_group/variables.tffile.
The node_group_ami_type_map variable defines the fallback EKS AMI type used per node architecture when node_group_ami_type is not explicitly set. The secure Bottlerocket AMI defaults must be replaced with the corresponding standard Bottlerocket AMI types.
a. Navigate to /03_node_group directory.
cd iac/aws/cluster/modules/03_node_group/
b. Edit the variables.tf file to make the following changes.
Change from (secure defaults):
variable "node_group_ami_type_map" {
description = "Fallback EKS AMI type per architecture, used when node_group_ami_type is empty."
type = map(string)
default = {
amd64 = "BOTTLEROCKET_x86_64_FIPS"
arm64 = "BOTTLEROCKET_ARM_64_FIPS"
}
}
Change to (standard values):
variable "node_group_ami_type_map" {
description = "Fallback EKS AMI type per architecture, used when node_group_ami_type is empty."
type = map(string)
default = {
amd64 = "BOTTLEROCKET_x86_64"
arm64 = "BOTTLEROCKET_ARM_64"
}
}
- Update the Karpenter AMI SSM parameter path in the
/05_helm_releases/main.tffile.
The karpenter_fips_ami_ssm_parameter value specifies the AWS Systems Manager (SSM) parameter path that Karpenter uses to resolve the correct Bottlerocket AMI for worker nodes. The default path targets the secure Bottlerocket AMI. For a standard cluster, remove the -fips segment from the EKS version portion of the path.
a. Navigate to /05_helm_releases directory.
cd iac/aws/cluster/modules/05_helm_releases/
b. Edit the main.tf file to make the following changes.
Change from (secure SSM path):
karpenter_fips_ami_ssm_parameter = "/aws/service/bottlerocket/aws-k8s-${data.aws_eks_cluster.this.version}-fips/${local.karpenter_ami_arch}/latest/image_id"
Change to (standard SSM path):
karpenter_fips_ami_ssm_parameter = "/aws/service/bottlerocket/aws-k8s-${data.aws_eks_cluster.this.version}/${local.karpenter_ami_arch}/latest/image_id"
- After completing all these configuration changes, proceed to deploy the cluster.
Note: The additional requirements update the Terraform configuration files for the bootstrap script. Do not modify the
03_node_group/variables.tfor05_helm_releases/main.tffiles in the preceding installation steps. Reverting those changes will result in a secure cluster being deployed instead of a standard cluster.
3.3 - In-cluster deployment
This section is intended for users who already have an EKS cluster provisioned and managed outside of the PPC installer. In a standard PPC installation, the installer provisions the EKS cluster and the required AWS resources. In an in-cluster deployment, however, the user creates the cluster. It already exists before the PPC installation begins. Cluster information must be provided to deploy PPC onto the existing EKS cluster. Unlike the automated script-based installation or the manual component-based installation, the installer does not create these AWS resources. They must already exist before you begin.
Complete the infrastructure prerequisites outside the PPC installer first. Then use the PPC installer to deploy the PPC application Helm charts to the existing EKS cluster.
Deploying PPC using In-Cluster Deployment for EKS
To install PPC, complete the following steps in order. Each step is described in detail in the sections below.
| Step | Action | Description |
|---|---|---|
| # | Before you begin | Ensures all prerequisites, access, permissions, and values are ready before starting. |
| # | Cluster requirements for PPC deployment | Verifies that the existing cluster meets all requirements before deploying PPC. |
| 1 | Preparing a jump box | Creates or identifies a jump box with network access to the EKS cluster. |
| 2 | Downloading and extracting the release archive | Downloads and extracts the PPC release archive on the jump box. |
| 3 | Installing required tools | Installs all required CLI tools on the jump box using the setup script. |
| 4 | Configuring AWS credentials | Authenticates with AWS and configures the CLI for the target account. |
| 5 | Configuring EKS access | Retrieves EKS credentials so that kubectl and helm can reach the cluster. |
| 6 | Verifying cluster connectivity | Confirms that the jump box can communicate with the cluster API. |
| 7 | Gathering values for terraform.tfvars | Collects the cluster-specific values needed for the deployment configuration. |
| 8 | Updating terraform.tfvars | Populates the 05_helm_releases module configuration with cluster-specific values. |
| 9 | Running the readiness check | Validates the environment and resolves any reported errors before deployment. |
| 10 | Applying the OpenTofu configuration | Deploys all PPC Helm charts onto the cluster using tofu apply. |
| 11 | Common misconfigurations | Lists the most frequent configuration errors and how to correct them. |
Before you begin
Ensure the following prerequisites are met before starting the installation.
Access and permissions
The following access and permissions are required for deploying PPC.
| Requirement | Details |
|---|---|
| AWS account | Access with permission to create EKS clusters, IAM roles and policies, EC2/VPC resources, S3 buckets, KMS keys, and federated credentials. |
| Availability Zones | Access to an existing VPC with at least two subnets across two Availability Zones. |
| AWS CLI | Access to AWS CLI v2 configured for the account and with network access to the cluster. |
kubectl | Access to kubectl configured for the account and with network access to the cluster. |
| Container registry | Access to the container registry to pull PPC container images during deployment. |
| Jump box | Access to a VM or workstation with network access to the EKS cluster. |
Values needed for terraform.tfvars
The values required to populate terraform.tfvars in are collected from two sources:
Values decided by user
These are existing or user-determined values that are available before prerequisite creation begins:
| Value | Description | Field | Variable or Example |
|---|---|---|---|
| AWS account ID | Unique identifier of the AWS account. | - | <ACCOUNT_ID> |
| AWS region | AWS region where the cluster is deployed. | aws_region | us-east-1 |
| Cluster name | Name of the existing EKS cluster. | eks_cluster_name | <CLUSTER_NAME> |
| Cluster owner email | Email address of the cluster owner. | owner_email | user@example.com |
| Container image registry | Container image registry endpoint. | global_image_reg | <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. |
| Container registry credentials | Credentials for authenticating with the container image registry. | TF_VAR_username, TF_VAR_password | Provided by the team. |
| Ingress FQDN | Fully qualified domain name for the ingress. | ingress_fqdn | myapp.example.com |
| Node architecture | Node architecture of the existing cluster. | architecture | amd64 or arm64 |
| Node OS | Node OS image string. | node_os | BOTTLEROCKET_x86_64_FIPS or BOTTLEROCKET_ARM_64_FIPS |
| Storage class name | Name of the existing storage class on the cluster. | storage_class_name | pty-sc |
| Subnet IDs | IDs of the two subnets (one per Availability Zone). | private_subnet_ids | <SUBNET_ID_1>, <SUBNET_ID_2> |
| VPC CIDR | CIDR block of the VPC. | vpc_cidr_block | 10.0.0.0/16 |
| VPC ID | ID of the VPC in which the cluster is deployed. | - | vpc-0abc123 |
Values captured from created resources
These values are generated when creating the resources listed in the Cluster requirements for PPC deployment section. Record each value as you create the corresponding resource:
| Value | Source | Field | Example |
|---|---|---|---|
| Backup S3 bucket name | Created in Storage and backup section. Record the bucket name when created. | backup_bucket | eks-<CLUSTER_NAME>-backup |
| Backup bucket KMS ARN | Created in Storage and backup section. Record the KMS key ARN after creation. | backup_bucket_kms_arn | arn:aws:kms:<REGION>:<ACCOUNT_ID>:key/<KEY_ID> |
Cluster requirements for PPC deployment
Your EKS cluster is already in place. Before running tofu apply in 05_helm_releases, use this checklist. It confirms that the cluster meets all the requirements PPC deployment expects.
Note: If you are unsure whether a requirement is met, work through each item. Verify each item against your cluster configuration before running
tofu apply.
IAM - roles and policies
| No. | What must exist | Exact name required? |
|---|---|---|
| 1 | Cluster IAM role with AmazonEKSClusterPolicy, AmazonEKSNetworkingPolicy, AmazonEKSComputePolicy, AmazonEKSBlockStoragePolicy, AmazonEKSLoadBalancingPolicy, AmazonEKSVPCResourceController, AmazonEKSServicePolicy, and AmazonEBSCSIDriverPolicy (service-role) attached. | No. This is a name selected at cluster creation. |
| 2 | Node IAM role named eks-<CLUSTER_NAME>-node-role with AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryReadOnly, AmazonSSMManagedInstanceCore, and AmazonEBSCSIDriverPolicy (service-role) attached. Trust principal must be exactly ec2.amazonaws.com with no prefix or trailing space. | Yes. Stage 05 hardcodes this name. |
| 3 | Named instance profile eks-<CLUSTER_NAME>-node-profile with the node role attached. | Yes. Karpenter’s EC2NodeClass references this by name. |
| 4 | Karpenter controller role eks-<CLUSTER_NAME>-karpenter-role with two policies attached. The first is eks-<CLUSTER_NAME>-karpenter-controller-policy, which covers EC2 and SQS actions, including eks:DescribeCluster and all SQS interruption actions. The second is eks-<CLUSTER_NAME>-karpenter-passrole-policy, which covers iam:PassRole scoped to the node role and iam:ListInstanceProfiles with Resource: "*". Trust principal must be pods.eks.amazonaws.com. | Yes. |
| 5 | Backup-recovery-utility role eks-<CLUSTER_NAME>-backup-recovery-utility-role with eks-<CLUSTER_NAME>-backup-recovery-utility-policy (EBS snapshots, S3 read/write on <BACKUP_BUCKET>, KMS on <BACKUP_BUCKET_KMS_ARN>) attached. Trust principal must be pods.eks.amazonaws.com. | Yes. |
| 6 | OpenSearch S3 snapshot policy eks-<CLUSTER_NAME>-opensearch-s3-policy (S3 bucket + object access on <BACKUP_BUCKET>/insight-snapshots/*, KMS on <BACKUP_BUCKET_KMS_ARN>) attached to the node role (not the backup role). | Yes. Must be on the node role. |
EKS cluster and access
| No. | What must exist |
|---|---|
| 7 | EKS cluster active, with the eks-pod-identity-agent add-on installed and ACTIVE. |
| 8 | All seven required add-ons installed and ACTIVE: vpc-cni, kube-proxy, coredns, eks-pod-identity-agent, aws-ebs-csi-driver, snapshot-controller, metrics-server. |
| 9 | EC2_LINUX access entry for arn:aws:iam::<ACCOUNT_ID>:role/eks-<CLUSTER_NAME>-node-role auto-created by a managed node group. Verify with aws eks list-access-entries. |
| 10 | Pod Identity associations created. The karpenter namespace and karpenter service account map to the Karpenter role. The pty-backup-recovery namespace and backup-recovery-utility service account map to the backup-recovery-utility role. |
Compute: system node group
| No. | What must exist |
|---|---|
| 11 | Managed system node group using secure Bottlerocket AMI and On-Demand capacity. Use t3.medium (amd64) or equivalent, with disk >= 30 GiB. Desired, min, and max must be 2. All nodes must be in Ready state. |
| 12 | Node group Kubernetes labels: role=system, nodepool-owner=ppc |
| 13 | Node group Kubernetes taint: CriticalAddonsOnly=true:NoSchedule |
Networking
| No. | What must exist |
|---|---|
| 14 | Both subnet tags present on each of the two subnets kubernetes.io/cluster/<CLUSTER_NAME>=shared and karpenter.sh/discovery/<CLUSTER_NAME>=true. |
| 15 | Worker security group <CLUSTER_NAME>-worker-sg tagged karpenter.sh/discovery=<CLUSTER_NAME>. It needs self-referencing all-traffic ingress and open egress. It also needs tcp 1025–65535 and tcp/udp 53 ingress from the cluster SG. |
| 16 | Cluster security group has tcp 443 ingress from worker SG, and all-traffic ingress from worker SG. |
Add-on scheduling (required after tainted system node group exists)
| No. | What must exist | Details |
|---|---|---|
| 17 | Apply add-on scheduling configuration for CoreDNS, Amazon EBS CSI Driver (controller), metrics-server, and snapshot-controller. Each add-on must tolerate the CriticalAddonsOnly taint and pin to role=system nodes. Run aws eks update-addon for each. | 7.3 Add-on scheduling configuration |
Storage and backup
| No. | What must exist | Details |
|---|---|---|
| 18 | Backup S3 bucket with versioning enabled and default SSE-KMS encryption using a user-managed key. | Enabling versioning, Using SSE-KMS |
| 19 | KMS key policy on the backup key. It grants kms:Decrypt/Encrypt/ReEncrypt*/GenerateDataKey*/DescribeKey to the node role, the backup-recovery-utility role, and the deployer identity used to run tofu apply. | Key policies in AWS KMS |
| 20 | StorageClass whose name matches storage_class_name in terraform.tfvars (default: pty-sc) is present on the cluster. If using the default, create the pty-sc gp3/Retain/WaitForFirstConsumer class. Then unset the default flag on gp2. | 7.1 Storage class |
System node group taint value
Ensure that the CriticalAddonsOnly=true:NoSchedule taint is applied when creating the system node group. Apply it together with the role=system label. This taint prevents application workloads from being scheduled on the system nodes. It is required for the Add-on scheduling configuration.
Deploying PPC
To deploy PPC onto the existing EKS cluster, perform the following steps:
1. Preparing a jump box
Create a jump box or use an existing one that has network access to the EKS cluster. The jump box must be able to access the Kubernetes API server endpoint.
2. Downloading and extracting the release archive
To download and extract the PCT, refer to Preparing for PPC deployment.
3. Installing required tools
To install the required tools from the extracted release bundle, run the following command:
./bootstrap-scripts/setup-devtools-aws.sh
The script installs the following tools:
| Tool | Description |
|---|---|
| AWS CLI v2 | Command-line tool for managing AWS resources. |
| bc | Arbitrary-precision calculator used in shell scripts. |
| cmctl | Command-line tool for managing cert-manager resources. |
| Helm | Kubernetes package manager for deploying Helm charts. |
| jq | Lightweight command-line JSON processor. |
| kubectl | Kubernetes command-line tool for interacting with the cluster. |
| OpenTofu | Open-source Terraform fork used to provision and manage infrastructure. |
| oras | OCI Registry As Storage client for pushing and pulling artifacts. |
| skopeo | Tool for inspecting and copying container images between registries. |
| ssh-client | SSH client for secure remote access. |
4. Configuring AWS credentials
Configure your AWS credentials so that CLI commands authenticate as your deployer identity. Either run aws configure to set up a named profile, or export the credentials directly.
Note: AWS SSO web-based login is not supported. However, AWS IAM Identity Center temporary credentials can be exported as environment variables.
Export IAM user credentials, temporary STS credentials, or AWS IAM Identity Center temporary credentials. Include the session token, as shown below:
export AWS_ACCESS_KEY_ID="<ACCESS_KEY_ID>"
export AWS_SECRET_ACCESS_KEY="<SECRET_ACCESS_KEY>"
export AWS_SESSION_TOKEN="<SESSION_TOKEN>"
export AWS_DEFAULT_REGION="<REGION>"
Note: The
AWS_SESSION_TOKENvariable is required only when using temporary credentials, such as the STS or AWS IAM Identity Center. Omit it when using long-term IAM user credentials.
To verify that the credentials are working, run the following command:
aws sts get-caller-identity
5. Configuring EKS access
To retrieve the EKS credentials and configure kubectl to communicate with the cluster, run the following command:
aws eks update-kubeconfig --name <CLUSTER_NAME> --region <REGION>
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
Record the name of the storage class to use and update storage_class_name in terraform.tfvars.
kubectl get sc -A
Record the name of the storage class. Update only storage_class_name in terraform.tfvars with this value. Leave backup_storage_class_name set to its default value, pty-bkp, which is created by Stage 05.
Note: Create a custom storage class named
pty-sc. Use the following properties:gp3volume type,Retainreclaim policy, andWaitForFirstConsumerbinding mode. Then setstorage_class_name=pty-scinterraform.tfvars. For a quick bring-up, the console’s defaultgp2storage class may be used instead. Do not modifybackup_storage_class_name, leave it aspty-bkp.
7.2 Registry credentials
When using an authenticated private registry, set harbor_secret to harbor-secret in terraform.tfvars. Also export the container registry credentials before running tofu apply. Otherwise, the apply fails while pulling PPC images and charts. Leave harbor_secret empty for an unauthenticated registry.
export TF_VAR_username="<REGISTRY-USERNAME>"
export TF_VAR_password="<REGISTRY-PASSWORD>"
Note: Registry credentials
TF_VAR_usernameandTF_VAR_passwordare passed as environment variables and are not set directly interraform.tfvars.
7.3 Add-on scheduling configuration
After the tainted system node group is active, apply the scheduling configuration to the four Deployment-based add-ons. This lets their pods land on system nodes. Set CLUSTER_NAME and REGION, then run the following commands:
export CLUSTER_NAME=<CLUSTER-NAME>
export REGION=<REGION>
# CoreDNS
aws eks update-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name coredns \
--region "$REGION" \
--resolve-conflicts OVERWRITE \
--configuration-values '{"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists","effect":"NoSchedule"}],"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"role","operator":"In","values":["system"]}]}]}}}}'
# Amazon EBS CSI Driver (controller only)
aws eks update-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name aws-ebs-csi-driver \
--region "$REGION" \
--resolve-conflicts OVERWRITE \
--configuration-values '{"controller":{"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists","effect":"NoSchedule"}],"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"role","operator":"In","values":["system"]}]}]}}}}}'
# metrics-server
aws eks update-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name metrics-server \
--region "$REGION" \
--resolve-conflicts OVERWRITE \
--configuration-values '{"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists","effect":"NoSchedule"}],"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"role","operator":"In","values":["system"]}]}]}}}}'
# snapshot-controller
aws eks update-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name snapshot-controller \
--region "$REGION" \
--resolve-conflicts OVERWRITE \
--configuration-values '{"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists","effect":"NoSchedule"}],"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"role","operator":"In","values":["system"]}]}]}}}}'
To verify the add-on status after the updates complete, run the following commands:
for addon in coredns aws-ebs-csi-driver metrics-server snapshot-controller; do
aws eks describe-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name "$addon" \
--region "$REGION" \
--query 'addon.[addonName,status]' \
--output text
done
Expected: all four add-ons report ACTIVE. If an update is still in progress, wait for it to complete. Then run the verification again.
8. Updating terraform.tfvars
To update the terraform.tfvars file, perform the following steps:
- Navigate to the Helm releases module directory.
cd iac/aws/cluster/modules/05_helm_releases
- After completing Steps 7.1 through 7.3, set the following variables in
05_helm_releases/terraform.tfvars.
| Variable | Description | Configured in |
|---|---|---|
architecture | Worker node architecture: amd64 or arm64. | Values decided by user |
aws_region | AWS region where the EKS cluster is deployed. | Values decided by user |
backup_bucket | S3 bucket used for PPC backups. | Values captured from created resources |
backup_bucket_kms_arn | KMS key ARN used to encrypt the backup bucket. | Values captured from created resources |
eks_cluster_name | Name of the existing EKS cluster. | Values decided by user |
global_image_reg | Container image registry endpoint: <Container_Registry_Path>. | Values decided by user |
harbor_secret | Kubernetes secret used for an authenticated private registry. Set to harbor-secret, or leave empty for an unauthenticated registry. | Step 7.2 |
ingress_fqdn | Fully qualified domain name for the PPC ingress. | Values decided by user |
node_os | Worker node OS image string, such as BOTTLEROCKET_x86_64_FIPS. | Values decided by user |
owner_email | Email address of the cluster owner. | Values decided by user |
private_subnet_ids | IDs of the private subnets used by the cluster, one per Availability Zone. | Values decided by user |
storage_class_name | Existing storage class used for PPC workloads. | Step 7.1 |
vpc_cidr_block | CIDR block of the VPC containing the EKS cluster. | Values decided by user |
Note: Registry credentials are passed as environment variables (
TF_VAR_usernameandTF_VAR_password). They are configured in Step 7.2. They are not set directly interraform.tfvars. Leavebackup_storage_class_nameat its default value,pty-bkp, unless the deployment requires a different value.
- Add the following variables to
terraform.tfvars. Set each to the value shown before allowing Stage 05 to apply.
run_readiness_check = true
check_prev_stage = false
These variables ensure that PPC performs a readiness check on the existing EKS environment. They skip the previous automated stage validation. That validation is not required because those resources were created outside the installer.
- Save the file and exit the editor.
9. Running the readiness check
The readiness check verifies that the cluster is ready for the Stage 05 (Helm Releases) tofu apply. The same check runs automatically as a guard at the start of the Stage 05 apply. It runs because run_readiness_check is enabled in the terraform.tfvars file. If required prerequisites are missing, the apply stops before deploying any components.
Run the check independently now to identify and resolve any issues before starting the apply.
To run the readiness check, run the following command:
./bootstrap-scripts/readiness-helm-aws.sh
The script validates that all required EKS add-ons are ACTIVE. It also checks that the worker security group and subnet tags are present. It checks that Pod Identity associations exist, and that the backup bucket and KMS key are accessible.
Note: The readiness check is read-only and does not modify the cluster. Run it as often as needed, including after correcting reported errors. Repeat it until it completes successfully before proceeding to apply the OpenTofu configuration.
10. Applying the OpenTofu configuration
To deploy all PPC Helm charts onto the cluster, initialize and apply the OpenTofu configuration. Perform the following steps:
- Navigate to the Helm releases module directory.
cd iac/aws/cluster/modules/05_helm_releases
Important: Before running
tofu planortofu apply, review all values interraform.tfvars. Confirm that they match your target environment.
- To initialize, plan, and apply the OpenTofu configuration, run the following commands. They deploy all PPC Helm charts onto the cluster.
tofu init
tofu plan # Review the planned resources that will be created.
tofu apply # When prompted with "Enter a value:", type "yes".
- To verify the resources created in this stage, run the following commands:
# Confirm nodes are Ready
kubectl get nodes
# Confirm pods are Running
kubectl get pods -A
11. Common misconfigurations in In-Cluster Deployment for EKS
When Stages 00–04 are created manually using the console or CLI, this repo’s OpenTofu does not create them. Every IAM role, policy, tag, and rule must match the exact names and permissions Stage 05 expects. These are the issues that break the install:
| # | Issue | Correct configuration |
|---|---|---|
| 1 | KMS key policy lists another cluster’s roles. For example, eks-cluster2-test-* | List this cluster’s eks-<CLUSTER_NAME>-backup-recovery-utility-role and eks-<CLUSTER_NAME>-node-role. |
| 2 | Worker SG only opens tcp 1025-65535 from the cluster SG: port 53 excluded. | Add tcp/udp 53 ingress on the worker SG from the cluster SG. |
| 3 | EBS CSI policy attached to a differently named role. For example, AmazonEKSNodeRole-<CLUSTER_NAME>. | Attach AmazonEBSCSIDriverPolicy to eks-<CLUSTER_NAME>-node-role; Stage 05 hardcodes that name. |
| 4 | Node trust principal is http://ec2.amazonaws.com . Contains either prefix or trailing space. | Set the trust principal to exactly ec2.amazonaws.com with no prefix or trailing space. |
| 5 | Karpenter policy missing eks:DescribeCluster and SQS interruption actions. | Create eks-<CLUSTER_NAME>-karpenter-controller-policy. Include these actions, all with Resource: "*": ec2:Describe*, ec2:CreateLaunchTemplate, ec2:DeleteLaunchTemplate, ec2:RunInstances, ec2:TerminateInstances, ec2:CreateFleet, ec2:CreateTags, ssm:GetParameter, pricing:GetProducts, eks:DescribeCluster. Add the SQS actions sqs:DeleteMessage, sqs:GetQueueAttributes, sqs:GetQueueUrl, and sqs:ReceiveMessage, all with Resource: "*". Create eks-<CLUSTER_NAME>-karpenter-passrole-policy. Scope iam:PassRole to arn:aws:iam::<ACCOUNT_ID>:role/eks-<CLUSTER_NAME>-node-role. Attach both policies to the Karpenter role. |
| 6 | Subnets missing karpenter.sh/discovery/<CLUSTER_NAME>=true. | Run aws ec2 create-tags --region <REGION> --resources <SUBNET_ID_1> <SUBNET_ID_2> --tags "Key=karpenter.sh/discovery/<CLUSTER_NAME>,Value=true" on both subnets. Without this tag, the EC2NodeClass reports SubnetsNotFound (Ready=False), no nodes launch, and pods stay Pending. |
| 7 | Subnets missing kubernetes.io/cluster/<CLUSTER_NAME>=shared. | Run aws ec2 create-tags --region <REGION> --resources <SUBNET_ID_1> <SUBNET_ID_2> --tags "Key=kubernetes.io/cluster/<CLUSTER_NAME>,Value=shared" on both subnets. Required for EKS/ELB and Envoy Gateway LoadBalancer subnet discovery. |
| 8 | Named instance profile eks-<CLUSTER_NAME>-node-profile never created (NoSuchEntity). | Run aws iam create-instance-profile --instance-profile-name eks-<CLUSTER_NAME>-node-profile. Then run aws iam add-role-to-instance-profile --instance-profile-name eks-<CLUSTER_NAME>-node-profile --role-name eks-<CLUSTER_NAME>-node-role. Without this, the policy-workbench EC2NodeClass is stuck Ready: Unknown and all pods stay Pending. |
| 9 | iam:ListInstanceProfiles scoped to an instance-profile ARN. | Create eks-<CLUSTER_NAME>-karpenter-passrole-policy with three statement blocks. (1) iam:PassRole on arn:aws:iam::<ACCOUNT_ID>:role/eks-<CLUSTER_NAME>-node-role to allow passing the node role to instances.(2) iam:CreateInstanceProfile, iam:TagInstanceProfile, iam:AddRoleToInstanceProfile, iam:RemoveRoleFromInstanceProfile, iam:DeleteInstanceProfile, iam:GetInstanceProfile on arn:aws:iam::<ACCOUNT_ID>:instance-profile/*. This lets Karpenter create and manage instance profile wrappers.(3) iam:ListInstanceProfiles on Resource: "*" as Karpenter requires list access across all profiles. |
| 10 | Node role missing the OpenSearch S3 snapshot policy eks-<CLUSTER_NAME>-opensearch-s3-policy. | Create and attach the policy to the node role manually. Otherwise, OpenSearch Insight snapshots fail at runtime with S3 AccessDenied, while tofu apply stays green. |