Executive summary
To run LILT in your own AWS account, LILT’s deployment automation provisions a standard set of AWS resources — a managed Amazon EKS cluster with EKS-managed node groups, an S3 bucket, an RDS MySQL database, an optional SQS queue, the supporting network, and the encryption keys that protect them — and then runs the LILT platform on that cluster. AWS manages the Kubernetes control plane and the worker-node instance lifecycle; this is not a self-managed cluster running on hand-operated virtual machines. This document is the access request: it lists exactly what your security team needs to grant, why each item is needed, how it is scoped, and how long it is required. There are two grants:1 · Deployment role
2 · Runtime roles
What you are granting, at a glance
| Grant | Purpose | Scope | Lifetime |
|---|---|---|---|
| Deployment role | Create/update/delete the EKS cluster, S3, SQS, RDS, networking, IAM roles, and KMS keys for LILT | AWS account (services listed below); tightenable to a naming prefix | Only during install/upgrade — can be removed afterward |
| Runtime — EKS service roles | Let the control plane and worker nodes operate (standard AWS-managed policies) | The LILT cluster | Life of the cluster |
| Runtime — application & add-on roles | Let LILT pods use their own S3 bucket, KMS key, DNS zone, and (when configured) SQS queue | The specific bucket / queue / key / hosted zone LILT owns | Life of the cluster |
Security posture
What your team can rely on when granting this:- Least privilege. Every policy lists only the actions the component needs. Runtime roles are additionally scoped to the specific resource LILT owns (its bucket, queue, key, or DNS zone) — they cannot touch anything else in the account.
- No long-lived keys. Access is brokered by short-lived, federated credentials (EKS IRSA / Pod Identity for workloads; your choice of federation for the deployment role). LILT does not require static IAM access keys.
- Time-boxed deployment access. The broad create/delete permissions live on the deployment role, which is only needed during install or upgrade and can be detached the rest of the time.
- Encryption by default. S3 and RDS are encrypted with dedicated KMS keys; the RDS database is private (no public endpoint) and reachable only from within the VPC.
- Auditable. The runtime policies are fixed and enumerated in this document, so a granted deployment produces a known, reviewable set of standing roles.
<ACCOUNT_ID>, <REGION>,
<CLUSTER_NAME>, <PREFIX> (an environment name prefix, e.g. prod), and the
<*_ARN> / <HOSTED_ZONE_ID> / <OIDC_PROVIDER> values — substitute the ones
for your environment. This request assumes a single-region deployment;
multi-region follows the same model per region.Grant 1 · Deployment role
Create one IAM role for LILT’s deployment identity and attach the permissions below. This is the complete set ofcreate, describe, modify, tag, and
delete actions required to stand up and later tear down the resources LILT
manages. It is needed only while provisioning; you may detach it between changes.
Why each service is needed:
| Service | What it is used for |
|---|---|
| EKS | Create and manage the Kubernetes cluster, node groups, add-ons, and admin access entries |
| EC2 / VPC | Create the private subnets, NAT, route tables, security groups, and node launch templates the cluster runs in |
| S3 | Create the object-storage bucket (application assets and the container registry backend) |
| SQS | Create the queues used for S3 event notifications and node-lifecycle handling |
| RDS | Create and configure the MySQL database |
| KMS | Create the encryption keys that protect S3 and RDS |
| IAM | Create the runtime roles in Grant 2 and the cluster’s OIDC identity provider |
| Route 53 | Create the DNS zone and records for the application endpoints |
| Secrets Manager, CloudWatch Logs, EventBridge, SSM | Store the DB master secret, cluster log groups, and node-lifecycle event rules |
Policy 1 — STS, ECR, Secrets Manager, S3
Policy 1 — STS, ECR, Secrets Manager, S3
Policy 2 — SQS, RDS, EKS
Policy 2 — SQS, RDS, EKS
Policy 3 — EC2 / VPC, IAM, KMS
Policy 3 — EC2 / VPC, IAM, KMS
Policy 4 — Route 53, extended EC2, CloudWatch Logs, EKS Pod Identity, EventBridge, SSM
Policy 4 — Route 53, extended EC2, CloudWatch Logs, EKS Pod Identity, EventBridge, SSM
- The
eks:*PodIdentityAssociationactions (EKSPodIdentity) are required — LILT binds every workload to its IAM role via EKS Pod Identity, so the deployment creates these associations. Do not drop them. EventBridgeRulesand the EKS-servicessm:GetParameterread are only needed for node auto-provisioning (Karpenter); they can be dropped here.- The instance-lifecycle actions in
EC2Extended—ec2:RunInstances,ec2:TerminateInstances,ec2:StopInstances,ec2:StartInstances— are only needed for self-managed nodes or Karpenter. With EKS-managed node groups the EKS service manages instance lifecycle, so the deployment role does not use them; the remainingEC2Extendednetwork-interface / ACL / volume actions are still required.
Grant 2 · Runtime roles
These roles are created for you by the deployment (using Grant 1) and are assumed by the cluster and its workloads at runtime. You do not hand-craft them; they are enumerated here so your team can review the standing access that will exist in the account after install.EKS service roles (AWS-managed policies)
The cluster and its worker nodes use roles built entirely from AWS’s own managed policies — AWS’s least-privilege definitions for these service roles. No custom permissions are involved.| Role | Assumed by | AWS-managed policies attached |
|---|---|---|
| Cluster role | the EKS control plane | AmazonEKSClusterPolicy, AmazonEKSVPCResourceController |
| Node role | worker EC2 instances | AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryReadOnly, AmazonEKSVPCResourceController, CloudWatchAgentServerPolicy |
| Node role (auto-provisioning) | as above | additionally AmazonSSMManagedInstanceCore |
| EBS CSI driver | the storage driver (EKS Pod Identity) | service-role/AmazonEBSCSIDriverPolicy |
AmazonEKSServicePolicy to the
cluster role. On EKS 1.24+ its permissions are folded into
AmazonEKSClusterPolicy, so it is optional on new clusters.min/max/desired config). There are no
self-managed EC2 instances or Auto Scaling groups to operate. As a result the
Cluster Autoscaler and Karpenter roles below, and the “auto-provisioning”
node-role variant above (AmazonSSMManagedInstanceCore), are not used in
this model — they are documented only for deployments that opt into node
auto-provisioning.Application & add-on roles (custom, least-privilege)
Each of these is a role with a small inline policy, scoped to the specific resource LILT owns and assumed by one named Kubernetes workload via short-lived federated credentials (EKS IRSA or Pod Identity). None of them can access resources outside the ones LILT created.LILT application — its own S3 bucket, SQS queue, KMS key
LILT application — its own S3 bucket, SQS queue, KMS key
<CLUSTER_NAME>-bucket-argo),
encrypted with the same S3 KMS key — so Resource lists both
<S3_BUCKET_ARN> and <ARGO_S3_BUCKET_ARN> (and their /*). SQS is only
present when the deployment provisions an SQS queue; the reference module
does not, so the AllowSQSAccess statement is omitted there.Container registry (Harbor) — S3 under its own prefix
Container registry (Harbor) — S3 under its own prefix
harbor/ prefix of
the LILT bucket. Object access and bucket listing are both scoped to that
prefix — it cannot see the rest of the bucket.ExternalDNS — the LILT DNS zone only
ExternalDNS — the LILT DNS zone only
cert-manager — TLS certificate issuance (DNS-01)
cert-manager — TLS certificate issuance (DNS-01)
Cluster Autoscaler — scaling the LILT cluster's node groups
Cluster Autoscaler — scaling the LILT cluster's node groups
Node auto-provisioning (Karpenter) — cluster-tagged EC2 only
Node auto-provisioning (Karpenter) — cluster-tagged EC2 only
ec2:CreateFleet / RunInstances / CreateLaunchTemplate / CreateTags /
TerminateInstances and the iam:*InstanceProfile actions by the
kubernetes.io/cluster/<CLUSTER_NAME>: owned and karpenter.sh/nodepool
tags — use the current published
Karpenter controller policy
for your Karpenter version.AWS Load Balancer Controller — load balancers it creates
AWS Load Balancer Controller — load balancers it creates
External Secrets Operator (optional) — read the LILT-managed secrets only
External Secrets Operator (optional) — read the LILT-managed secrets only
external-secrets-sa service account
in the external-secrets namespace via EKS Pod Identity.Bastion host (optional) — describe the cluster + Session Manager
Bastion host (optional) — describe the cluster + Session Manager
enable_bastion). An EC2 instance
role that lets operators run aws eks describe-cluster /
update-kubeconfig against this one cluster and reach the private bastion
over AWS Systems Manager Session Manager (no public IP or open SSH port
required). It attaches the AWS-managed AmazonSSMManagedInstanceCore policy
plus the inline statement below.Cluster service account & Pod Identity wiring
The runtime roles above are not attached to pods directly. Each is bound to a named Kubernetes service account (SA), and an EKS Pod Identity association maps that SA to the IAM role. This section describes how LILT’s terraform sets that up so your team can see exactly which in-cluster identity receives which AWS permissions.The LILT cluster service account
LILT’s application does not spread its AWS access across many service accounts. A single service account — configured via thecluster_service_account
variable and created in the deployment namespace (namespace, default lilt) —
is the identity used for all of the application’s AWS access (S3, and any
other application-level AWS resources). It is a plain service account with no
IRSA eks.amazonaws.com/role-arn annotation: the role binding is done outside
the SA object, by the Pod Identity association.
How the pieces fit together
Three objects have to agree for a pod to receive AWS permissions:- The Kubernetes service account — the identity the pod runs as
(
namespace+name). - The IAM role — carries the least-privilege policy (e.g. the S3 + KMS
permissions) and has a trust policy that allows
pods.eks.amazonaws.comto assume it (sts:AssumeRole+sts:TagSession). This is what makes it a Pod Identity role rather than an IRSA/OIDC role. - The Pod Identity association — the AWS-side record that says “SA namespace/name on this cluster may assume this role.”
Service-account-to-role map
| Kubernetes service account | Namespace | Bound IAM role (Grant 2) | Grants |
|---|---|---|---|
cluster_service_account (e.g. lilt-sa) | namespace (default lilt) | LILT application role | S3 (LILT + Argo buckets) and its KMS key |
aws-load-balancer-controller-sa | kube-system | AWS Load Balancer Controller role | Manage the cluster’s ALBs/NLBs |
ebs-csi-controller-sa | kube-system | EBS CSI driver role | AmazonEBSCSIDriverPolicy |
external-secrets-sa (if used) | external-secrets | External Secrets role | Read the RDS / SSL / SMTP secrets |
Role/RoleBindings for the application and Argo Workflows components). That
RBAC governs access to the Kubernetes API inside the cluster and is entirely
separate from the AWS IAM permissions granted through the Pod Identity
association described here — the same SA simply serves both roles.How access is brokered
No component uses a long-lived IAM access key. Each principal obtains short-lived credentials via a federated trust:| Principal | Mechanism | How it is trusted |
|---|---|---|
| App, registry, ExternalDNS, cert-manager, autoscaler, Karpenter, LB controller | EKS IRSA (OIDC) or EKS Pod Identity | With IRSA, scoped to one Kubernetes service account (<OIDC_PROVIDER>:sub = system:serviceaccount:<namespace>:<sa-name>); with Pod Identity, the same SA is bound via an association. LILT’s reference terraform uses Pod Identity for the app and LB controller — see the note below. |
| External Secrets Operator (if used) | EKS Pod Identity | The external-secrets-sa service account in the external-secrets namespace |
| EBS CSI storage driver | EKS Pod Identity | The EKS Pod Identity service on your cluster |
| Worker nodes | EC2 instance profile | The node role, assumed by EC2 |
| Bastion host (if enabled) | EC2 instance profile | The bastion role, assumed by EC2 |
| Control plane | EKS service role | Assumed by the EKS service |
| Deployment role (Grant 1) | Your choice | You decide who may assume it — a federated CI identity or a named administrator, per your own access standards |
pods.eks.amazonaws.com instead of a web-identity subject.
