AWS Services Setup for Tabsdata on EKS
Tabsdata on EKS runs as long-running deployment pods in a single namespace, and dispatches every publisher, subscriber and transformer execution as its own Kubernetes job. It keeps no state in the cluster: table data lives in AWS S3 and all metadata lives in AWS RDS for PostgreSQL. This document covers the AWS-side setup those three services need before Tabsdata can be installed, and how to expose the instance once it is running.
The values produced here are the ones the Tabsdata admin needs at hand for Install Tabsdata on AWS EKS.
Before you begin
These instructions assume you have knowledge of, and full access to, the AWS IAM, EKS, RDS and S3 services, or that your AWS admins do. Each section indicates the type of admin access it requires.
It is recommended you read through the whole setup before you begin, so you can gather all the necessary information and have it ready.
Prepare the EKS cluster
(EKS admin)
Tabsdata must be installed into an existing cluster <TABSDATA_CLUSTER>, in an
empty namespace.
Create an EKS namespace <TABSDATA_NAMESPACE>.
Node scheduling
(EKS admin)
Karpenter must be installed in the cluster and given the AWS resources it needs:
an IAM role for the controller (IRSA or EKS Pod Identity) allowing it to run
instances, create launch templates and pass the node role; a node IAM role
admitted to the cluster via an EKS access entry or aws-auth; the SQS
interruption queue with its EventBridge rules; and karpenter.sh/discovery tags
on the subnets and security groups the EC2NodeClass selects. Because Karpenter
cannot run on a node it manages, a small fixed managed node group must exist
beforehand, outside the pools, to hold it and the cluster addons.
Two EC2NodeClass/NodePool pairs are then created, distinguished mainly by
local disk. The services pool is untainted, sized for the long-running instance
pods, with the instance store exposed to the kubelet, expiry disabled and
consolidation enabled so the fleet shrinks. The functions pool is sized for the
substantially larger disk a run stages, with an explicit memory floor since that
does not follow from vCPU or disk, and is tainted so a function pod that lost
its toleration fails visibly rather than running slowly on a small machine. All
sizes in the reference pools are initial suggested values. Set them from the
instance's own requests and expected concurrency and volumetry. Pool and node
class names are free; placement follows the pods' resource requests, so function
pods land on the functions pool because only it provisions machines that large.
Three strings are binding and must match exactly. Two PriorityClass objects
named tabsdata-service and tabsdata-function must exist, with the service
class ranked higher, because the API server rejects a pod naming a class that is
absent. The functions pool's taint key, value and effect must be identical to
pods.function.placement.tolerations in the instance's configs/tabsdata.yaml,
edited via tdkserver get-cfg / tdkserver put-cfg. Resource requests and the
aut-services disruption budget arrive with the instance and need no
administrator action.
Map your AWS user to a Kubernetes group
(EKS admin)
Map the AWS username <AWS_USERNAME> that will install and manage Tabsdata to the
Kubernetes group <TABSDATA_GROUP> in the cluster <TABSDATA_CLUSTER>, region
<TABSDATA_CLUSTER_REGION>.
Create the namespace role and binding
(EKS admin)
This role grants Tabsdata the permissions it needs inside its own namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: <TABSDATA_ROLE>
namespace: <TABSDATA_NAMESPACE>
rules:
- apiGroups: [ "" ]
resources: [ "pods" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete", "deletecollection" ]
- apiGroups: [ "" ]
resources: [ "services", "configmaps", "secrets", "serviceaccounts" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete" ]
- apiGroups: [ "" ]
resources: [ "pods/log" ]
verbs: [ "get", "list" ]
- apiGroups: [ "" ]
resources: [ "pods/portforward" ]
verbs: [ "create" ]
- apiGroups: [ "apps" ]
resources: [ "deployments" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete", "deletecollection" ]
- apiGroups: [ "policy" ]
resources: [ "poddisruptionbudgets" ]
verbs: [ "get", "list", "create", "update", "delete" ]
- apiGroups: [ "networking.k8s.io" ]
resources: [ "ingresses" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete" ]
- apiGroups: [ "batch" ]
resources: [ "jobs", "cronjobs" ]
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete", "deletecollection" ]
- apiGroups: [ "rbac.authorization.k8s.io" ]
resources: [ "roles", "rolebindings" ]
verbs: [ "get", "list", "create", "update", "delete" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: <TABSDATA_ROLE>
namespace: <TABSDATA_NAMESPACE>
subjects:
- kind: Group
name: <TABSDATA_GROUP>
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: <TABSDATA_ROLE>
apiGroup: rbac.authorization.k8s.io
Create the cluster role and binding
(EKS admin)
A few of the checks Tabsdata runs cannot be expressed in a namespaced role, so they need a cluster role. All of them are read-only, and none grants any access beyond reading.
Create the cluster role <TABSDATA_CLUSTER_ROLE> and bind it to the group
<TABSDATA_GROUP>.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: <TABSDATA_CLUSTER_ROLE>
rules:
- apiGroups: [ "" ]
resources: [ "namespaces", "services", "nodes" ]
verbs: [ "get", "list" ]
- apiGroups: [ "karpenter.sh" ]
resources: [ "nodepools" ]
verbs: [ "get", "list" ]
Finally, provide a <KUBECONFIG> file to the Tabsdata operator so the installation
steps below can reach the cluster.
Verify your permissions
(Tabsdata admin)
Run these checks with the <KUBECONFIG> you were given, before going any further.
kubectl auth can-i create deployments.apps
kubectl auth can-i create cronjobs.batch
kubectl auth can-i create secrets
kubectl auth can-i create services
kubectl auth can-i create roles.rbac.authorization.k8s.io
kubectl auth can-i create serviceaccounts
kubectl auth can-i get pods/log
kubectl auth can-i deletecollection pods
kubectl auth can-i deletecollection deployments.apps
kubectl auth can-i deletecollection jobs.batch
kubectl auth can-i deletecollection cronjobs.batch
kubectl auth can-i create pods/portforward
kubectl auth can-i create ingresses.networking.k8s.io
kubectl auth can-i create poddisruptionbudgets.policy
kubectl auth can-i list namespaces
kubectl auth can-i list services --all-namespaces
kubectl auth can-i list nodes
kubectl auth can-i list nodepools.karpenter.sh
Every command must answer yes. If any command fails or answers no, check
with your AWS EKS administrator before proceeding.
Tabsdata database
(RDS admin)
Tabsdata stores its own state and the metadata for user data in PostgreSQL.
Create an AWS RDS for PostgreSQL 18.4 instance with a database
<TABSDATA_DATABASE>, using password authentication with <RDS_USERNAME>
and <RDS_PASSWORD>.
<RDS_USERNAME> must have the following permissions:
| Requirement | Kind | Statement |
|---|---|---|
CONNECT on <TABSDATA_DATABASE> | privilege | GRANT CONNECT ON DATABASE <TABSDATA_DATABASE> TO <RDS_USERNAME>; |
CREATEROLE | role attribute | ALTER ROLE <RDS_USERNAME> CREATEROLE; |
CREATE on <TABSDATA_DATABASE> | privilege | GRANT CREATE ON DATABASE <TABSDATA_DATABASE> TO <RDS_USERNAME>; |
The RDS master username already satisfies all three, and owns any database it creates.
The Tabsdata installation will create the necessary database schemas, roles and grants.
What the installation creates
(RDS admin)
One schema per Tabsdata component, inside <TABSDATA_DATABASE>:
| Schema | Component |
|---|---|
<TABSDATA_DATABASE>_apiserver | API server |
<TABSDATA_DATABASE>_aiagent | AI agent |
Each schema holds that component's tables, indexes, views, triggers, row-level-security policies and baseline data.
Three PostgreSQL roles. Roles are cluster-global, so their names must be unique
across the whole RDS instance, which is why they derive from <TABSDATA_DATABASE>:
| Role | Login | Password | Owns |
|---|---|---|---|
<TABSDATA_DATABASE>_apiserver | LOGIN | must be provided | the API server schema |
<TABSDATA_DATABASE>_aiagent | LOGIN | must be provided | the AI agent schema |
<TABSDATA_DATABASE>_app | NOLOGIN | none | nothing |
The two login roles are the identities Tabsdata authenticates as, one per component. Their passwords are supplied during installation.
<TABSDATA_DATABASE>_app is the role every Tabsdata connection then switches to,
and the one row-level security is enforced against. It is shared by both
components, owns nothing, and cannot be reached directly: it has no login and no
password, and is used only internally by Tabsdata.
Tabsdata cloud storage
(S3 admin)
Tabsdata uses AWS S3 bucket(s) for data storage.
You need an S3 bucket <S3_BUCKET> in region <S3_REGION>, and full-access
credentials for it: <S3_ACCESS_KEY> and <S3_SECRET_KEY>.
Configure access from outside the cluster (over HTTPS)
(EKS admin)
None of this applies to local access via kubectl port-forward, as described in
Install Tabsdata on AWS EKS.
Once installed, Tabsdata is running inside the cluster, but is not reachable from outside it.
Public access is delivered by two AWS components layered on the cluster. In EKS,
the apiserver Service is fronted by an alb-class Ingress, which the AWS Load
Balancer Controller turns into an internet-facing Application Load Balancer
targeting pod IPs, so the controller must already be installed with an IAM role
permitting ELBv2 management, and the VPC's public subnets must carry the
kubernetes.io/role/elb tag in every availability zone in use. That ALB listens
on HTTP only, and its security group is locked to the AWS-managed CloudFront
origin-facing prefix list (read from EC2), so it is not reachable directly.
In front of it, a CloudFront distribution uses the ALB as a custom origin and
serves viewers over HTTPS on its own *.cloudfront.net hostname, which is why
no Route 53 record or ACM certificate is needed. Deployment of the distribution
takes five to ten minutes; after that the instance answers only through
CloudFront.
Use the distribution's *.cloudfront.net URL as <TABSDATA_PUBLIC_URL>, and
point your browser at it.