Skip to content

AWS: EKS, RDS and platform services

The AWS deployment is split into four roots. Networking and the database live outside Kubernetes; the web and rest services run on EKS. The load balancer controller translates the application's Ingress into an ALB. That ALB is created indirectly by the controller, rather than declared as an aws_lb resource in the Terraform roots.

Networking and traffic

aws/network consumes terraform-aws-modules/vpc/aws with the ~> 5.0 constraint. It selects as many availability zones as there are private subnet entries, taking the first available zones returned by AWS.

Setting Versioned default Consequence
Region eu-west-1 All AWS roots must agree
Base name gitlab-terraform-eks Does not automatically include ENVIRONMENT
VPC 10.0.0.0/16 Private network for the AWS implementation
Private subnets 10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24 EKS nodes and the RDS subnet group
Public subnets 10.0.4.0/24, 10.0.5.0/24, 10.0.6.0/24 Public module resources and ALB subnet discovery
NAT Enabled; one NAT Gateway Shared egress for private subnets
DNS Hostnames and DNS support enabled Internal resolution and managed endpoints

Public subnets have kubernetes.io/role/elb=1; private ones have kubernetes.io/role/internal-elb=1. These tags let the controller discover load balancer subnets. They do not themselves expose an application: the Ingress requests the external load balancer.

A single NAT reduces the number of gateways but concentrates egress and can create cross-zone traffic. It should not be described as a highly available egress strategy. The thesis explains the choice of small compute sizes for the demonstration (§7.2.7, printed page 44 / PDF 50); it does not explicitly attribute every availability tradeoff to the author.

EKS and its identities

aws/kubernetes consumes terraform-aws-modules/eks/aws (~> 20.0) and network outputs. It configures:

  • Cluster name gitlab-terraform-eks and Kubernetes version 1.31.
  • Nodes in private subnets.
  • Public API access enabled, with allowed CIDRs 0.0.0.0/0.
  • Administrative permissions for the cluster creator identity.
  • One default managed node group: t3.small, desired 1, minimum 1, maximum 3.
  • A 33% unavailability limit during node group updates.
  • IRSA and the aws-ebs-csi-driver add-on.

Version 1.31 is the value in the source, not a version recommendation for a new deployment. Before rebuilding the lab, check that version's availability and support in the target region, and update the configuration through a reviewed change where necessary.

The node group's 1–3 limits do not establish automatic scaling based on load or pending pods. No Cluster Autoscaler or Karpenter is declared. AWS distinguishes capacity settings from mechanisms that adjust capacity in response to workloads; see EKS autoscaling.

EBS CSI through IRSA

The AmazonEKSTFEBSCSIRole-<cluster> role is created with IAM module 5.39.0, trusts the cluster's OIDC identity and restricts the subject to system:serviceaccount:kube-system:ebs-csi-controller-sa. It receives the managed AmazonEBSCSIDriverPolicy; the add-on receives that role's ARN.

The association is with the controller service account, not a blanket grant of that policy to every node role. The driver enables storage capability: the reviewed demonstration manifests declare no PVC for web or rest, since data lives in RDS.

RDS MySQL

The database layer consumes the VPC and subnets from network, and the node security group from kubernetes through the eks state alias.

Setting Source value
Engine MySQL 8.0
Instance class db.t4g.micro
Storage gp3, initially 20 GiB, maximum 100 GiB
Database and port restdb, TCP 3306
Initial user restuser; required sensitive password
Exposure publicly_accessible=false
Availability multi_az=false
Backups 1-day automated backup retention
Deletion protection Disabled
Final snapshot Skipped by default
Change application apply_immediately=true

The RDS security group accepts MySQL from the EKS node security group and permits general outbound traffic. This provides a network boundary between the database and clients, but does not replace SQL user authorization or pod-level network policy.

Outputs expose host, port, database, sensitive username, security IDs and JDBC URL. The password is supplied as an input and participates in state; sensitive does not remove it from IaC persistence. See protecting state and plans.

Platform preparation

aws/platform requires the EKS API to be reachable from the runner. The Kubernetes and Helm providers execute aws eks get-token using the job's AWS identity, cluster name and region. This bootstrap path differs from subsequent application-pipeline access through the Agent.

Resource Purpose
app namespace Hosts the demonstration workloads
rest Secret REST_DB_HOST, REST_DB_PORT, REST_DB_DATABASE, REST_DB_USER, REST_DB_PASSWORD
gitlab-agent namespace Hosts the agent
gitlab-agent Helm release Uses the supplied KAS address and agent token
ALB controller service account aws-load-balancer-controller in kube-system, annotated with its IRSA role
ALB controller IRSA role IAM-module policy plus additional listener-attribute permissions
ALB controller Helm release Uses cluster, region, VPC and the pre-created service account

The additional policy allows elasticloadbalancing:DescribeListenerAttributes and elasticloadbalancing:ModifyListenerAttributes on *. Its existence is verified in source; the particular incident or reason for adding it cannot be established from the file and is not invented here.

Neither Helm release pins a chart version. The VPC/EKS modules use major-version constraints; IAM is pinned to 5.39.0. No provider lockfiles are versioned in the snapshot. These differences matter when reproducing the installation months later.

HTTP and TLS ingress

The Ingress belongs to web-application/deployments/frontend. It requests an internet-facing ALB, IP targets, 80/443 listeners and HTTPS redirection. It routes /api/v1 to rest:8080 and / to web:8080.

The manifest contains a domain and a concrete ACM ARN from the original deployment. A replica requires a valid certificate in the target region and DNS pointing to the generated load balancer. Neither certificate nor DNS is provisioned by the inspected roots. Replacing these values is an adaptation prerequisite, not an operation performed by the documentation pipeline.

Acceptance checks

After creation, check each layer: coherent networking outputs; Ready nodes; available RDS reachable by the application; connected agent; available ALB controller; and a rest secret with expected keys, without printing its values. After application deployment, check the HTTPS endpoint, API routing and database connection. A successful apply_platform alone does not establish these functional outcomes.

For variables and credentials, see the reference. To retire the environment while preserving necessary data, see teardown.

Sources