Zilla Gateway Deployment on EKS
Zilla Gateway Deployment on EKS
This guide describes how to deploy a Zilla Platform Gateway on Amazon EKS.
This page assumes that the Zilla Platform Control & Management plane has already been deployed and initialized.
Prerequisites
- Zilla Platform deployed and initialized (admin account created)
- Amazon EKS cluster
- AWS CLI configured with sufficient IAM permissions
kubectlandhelminstalledkeytool(part of the JDK) for TLS keystore generation
Install Required Tools (macOS)
brew install openjdkRequired Environment Variables
The following variables must be set before running any commands in this guide. AWS_REGION, CLUSTER_NAME, DOMAIN, and ZILLA_PLATFORM_LICENSE_KEY should already be exported from the platform deployment. The bootstrap token is obtained from the Zilla Platform console or API after creating an environment.
export AWS_REGION="<AWS_REGION>"
export CLUSTER_NAME="<CLUSTER_NAME>"
export DOMAIN="<CUSTOM_DOMAIN>"
export GATEWAY_DOMAIN="<GATEWAY_DOMAIN>"
export ZILLA_PLATFORM_LICENSE_KEY="<LICENSE_KEY>"
export BOOTSTRAP_TOKEN="<BOOTSTRAP_TOKEN>"Info
GATEWAY_DOMAIN is the DNS domain that Kafka clients use to connect to the gateway (e.g., kafka.example.com). It is independent of the platform domain and should reflect the external-facing hostname(s) your clients will resolve.
Info
BOOTSTRAP_TOKEN is generated when you create an Environment in the Zilla Platform console (Environments → Create → Generate Bootstrap Token). Copy the token value and export it here before deploying the gateway.
Create the Environment Namespace
Create a dedicated Kubernetes namespace for the environment:
kubectl create namespace <ENVIRONMENT_NAME>Configure Access to AWS Secrets Manager (IRSA)
Zilla environment gateways can retrieve TLS certificates and other sensitive material from AWS Secrets Manager. This is achieved using IAM Roles for Service Accounts (IRSA).
Create IAM Policy for Secrets Access
The gateway's aws-secrets vault uses the AWS Resource Groups Tagging API (tag:GetResources) to discover Secrets Manager entries by their certificate-authority-arn tag, then fetches the certificate chain from ACM PCA. All four action groups below must be granted — without tag:GetResources the vault discovers nothing and presents an empty cert to clients, which silently fails the TLS handshake.
cat <<EOF > zilla-secrets-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SecretsManagerRead",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:${AWS_REGION}:$(aws sts get-caller-identity --query Account --output text):secret:zilla-platform/certs/*"
},
{
"Sid": "ResourceGroupsTaggingRead",
"Effect": "Allow",
"Action": "tag:GetResources",
"Resource": "*"
},
{
"Sid": "AcmCertChain",
"Effect": "Allow",
"Action": "acm:GetCertificate",
"Resource": "*"
},
{
"Sid": "AcmPcaCertChain",
"Effect": "Allow",
"Action": [
"acm-pca:GetCertificate",
"acm-pca:GetCertificateAuthorityCertificate"
],
"Resource": "arn:aws:acm-pca:${AWS_REGION}:$(aws sts get-caller-identity --query Account --output text):certificate-authority/*"
}
]
}
EOF
aws iam create-policy \
--policy-name ZillaGatewaySecretsPolicy \
--policy-document file://zilla-secrets-policy.jsonCreate IAM Role for IRSA
Create an IAM role that can be assumed by the environment gateway service account.
# Get OIDC provider URL
OIDC_PROVIDER=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region ${AWS_REGION} \
--query 'cluster.identity.oidc.issuer' --output text | sed 's|https://||')
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
# Create trust policy for the service account
cat <<EOF > trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:<ENVIRONMENT_NAME>:<ENVIRONMENT_NAME>-zilla-platform-environment",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
# Create the IAM role
aws iam create-role \
--role-name ZillaGatewayRole \
--assume-role-policy-document file://trust-policy.json
# Attach the secrets policy
aws iam attach-role-policy \
--role-name ZillaGatewayRole \
--policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/ZillaGatewaySecretsPolicy
# Get the role ARN for use in values.yaml
export ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/ZillaGatewayRole"
echo "Role ARN: $ROLE_ARN"Note
The trust policy uses <ENVIRONMENT_NAME>-zilla-platform-environment as the service account name — this is the name the chart generates by default. If you override serviceAccount.name in environment-values.yaml, update the sub condition in the trust policy to match.
Generate Gateway TLS Keystore
The gateway's tls_server binding presents a server certificate to inbound clients using a filesystem vault backed by a PKCS12 keystore. The certificate must cover the DNS domain that Kafka clients use to connect to the gateway (GATEWAY_DOMAIN), which is independent of the platform's internal domain.
mkdir -p ~/zilla-tls
keytool -genkeypair \
-alias "gateway" \
-keyalg RSA -keysize 2048 \
-dname "CN=*.${GATEWAY_DOMAIN}, O=Aklivity, L=Palo Alto, ST=California, C=US" \
-ext "SAN=dns:*.${GATEWAY_DOMAIN},dns:${GATEWAY_DOMAIN}" \
-validity 365 \
-storetype PKCS12 \
-keystore ~/zilla-tls/keys \
-storepass generated
kubectl -n <ENVIRONMENT_NAME> create secret generic gateway-tls \
--from-file=keys=$HOME/zilla-tls/keysConfigure Environment Values
The gateway chart does not expose any ports by default. You must explicitly configure only the ports required for your deployment under product.tcp.ports in environment-values.yaml. Opening only the ports your clients actually need reduces the attack surface.
For example, to expose HTTPS (port 443) and Kafka over TLS (port 9094):
product:
tcp:
ports:
- name: https
port: 443
- name: kafka-tls
port: 9094To expose plain Kafka only (port 9092):
product:
tcp:
ports:
- name: kafka
port: 9092Update environment-values.yaml with IRSA, filesystem vault, port configuration, and NLB cross-zone settings:
# environment-values.yaml
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::<ACCOUNT_ID>:role/ZillaGatewayRole"
tls:
secretName: gateway-tls
product:
tcp:
annotations:
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
configs:
zilla.yaml:
content: |
name: "gateway"
vaults:
server:
type: "filesystem"
options:
keys:
store: "tls/server/keys"
password: "generated"
trust:
store: "${{platform.config.url}}/server/trust"Note
Update the role ARN with your actual account ID. The product.tcp cross-zone annotation ensures the NLB routes traffic across all availability zones — without it, only the ENI in the same AZ as the gateway pod is reachable and other IPs will time out.
Warning
The trust store is fetched from the control plane at gateway startup only. Restart the gateway pod after registering or updating Certificate Authorities in the console to pick up trust changes. Automatic trust store refresh is a known platform limitation and will be addressed in a future release.
Deploy the Gateway
Deploy the gateway using the environment Helm chart:
helm install <ENVIRONMENT_NAME> oci://ghcr.io/aklivity/charts/zilla-platform-environment \
-n <ENVIRONMENT_NAME> \
-f environment-values.yaml \
--set bootstrapToken="${BOOTSTRAP_TOKEN}" \
--set platformURI="https://platform.${DOMAIN}" \
--set licenseKey="${ZILLA_PLATFORM_LICENSE_KEY}" \
--set kubernetes.distribution="eks"Info
The gateway pod will automatically receive AWS credentials via IRSA to access secrets from AWS Secrets Manager (if configured).
Verify Deployment
kubectl get pods -n <ENVIRONMENT_NAME>