Skip to content

Tamedia Kubernetes as a Service (KaaS) Terraform Module

Opinionated Terraform module to deploy Kubernetes in AWS. Includes:

Managed Addons:

  • EBS CSI
  • VPC CNI
  • CoreDNS
  • KubeProxy

Components (installed by default):

Requirements

The module needs some resources to be deployed in order to operate correctly:

IAM service-linked roles

Usage

module "k8s_platform" {
  source = "tx-pts-dai/kubernetes-platform/aws"
  # Pin this module to a specific version to avoid breaking changes
  # version = "0.0.0"

  name = "example-platform"

  vpc = {
    vpc_id          = "vpc-12345678"
    vpc_cidr        = "10.0.0.0/16"
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
    intra_subnets   = ["10.0.3.0/24"]
  }

  tags = {
    Environment = "sandbox"
    GithubRepo  = "terraform-aws-kubernetes-platform"
  }
}

See the Examples below for more use cases

Upgrading Kubernetes Version

The Kubernetes version is configured via the kubernetes_version variable. The default version is updated with each module release.

To upgrade your cluster to a new Kubernetes version:

module "k8s_platform" {
  source = "tx-pts-dai/kubernetes-platform/aws"

  kubernetes_version = "1.34"

  # ... other configuration
}

Important: Do not skip Kubernetes minor versions during upgrades. For example, upgrade from 1.32 → 1.33 → 1.34, not directly from 1.32 → 1.34.

Explanation and description of interesting use-cases

Why this module?

  • To provide an AWS account with a K8s cluster with batteries included so that you can start deploying your workloads on a well-built foundation
  • To encourage standardization and common practices
  • To ease maintenance

Examples

  • Complete - Includes creation of VPC, k8s cluster, addons and all the optional features.
  • Datadog - EKS deployment with Datadog Operator integration
  • Lacework - EKS deployment with Lacework integration
  • Network - VPC deployment with custom subnets for kubernetes

Cleanup example deployments

Destroy Workflow - This manual workflow destroys deployed example deployments by selection the branch and the example to destroy.

Contributing

Pre-Commit

Installation: install pre-commit and execute pre-commit install. This will generate pre-commit hooks according to the config in .pre-commit-config.yaml

Before submitting a PR be sure to have used the pre-commit hooks or run: pre-commit run -a

The pre-commit command will run:

  • Terraform fmt
  • Terraform validate
  • Terraform docs
  • Terraform validate with tflint
  • check for merge conflicts
  • fix end of files

as described in the .pre-commit-config.yaml file

Requirements

Name Version
terraform >= 1.10
aws >= 6.28
helm >= 3.0.2
kubectl >= 2.0.2
kubernetes >= 2.27
time >= 0.11

Providers

Name Version
aws >= 6.28
helm >= 3.0.2
kubernetes >= 2.27
time >= 0.11

Modules

Name Source Version
ack_capability terraform-aws-modules/eks/aws//modules/capability 21.15.1
acm terraform-aws-modules/acm/aws 6.3.0
argocd ./modules/argocd n/a
aws_ebs_csi_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
aws_gateway_controller_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
aws_lb_controller_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
aws_vpc_cni_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
ebs_csi_driver_irsa terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts 6.4.0
eks terraform-aws-modules/eks/aws 21.15.1
eks_addons ./modules/eks-addons n/a
external_dns_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
external_secrets_pod_identity terraform-aws-modules/eks-pod-identity/aws 2.7.0
karpenter terraform-aws-modules/eks/aws//modules/karpenter 21.15.1
karpenter_irsa terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts 6.4.0
karpenter_security_group ./modules/security-group n/a
ssm ./modules/ssm n/a
vpc_cni_irsa terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts 6.4.0

Resources

Name Type
aws_cloudwatch_log_group.fargate_fluentbit resource
aws_eks_access_entry.k8s_access resource
aws_eks_access_policy_association.k8s_access_custom resource
aws_eks_access_policy_association.k8s_access_predefined resource
aws_iam_policy.fargate_fluentbit resource
aws_iam_policy.karpenter_controller resource
aws_iam_role.k8s_access resource
aws_route_table_association.karpenter resource
aws_security_group_rule.eks_control_plane_ingress resource
aws_subnet.karpenter resource
helm_release.karpenter_crd resource
helm_release.karpenter_release resource
helm_release.karpenter_resources resource
kubernetes_config_map_v1.aws_logging resource
kubernetes_namespace_v1.aws_observability resource
time_sleep.wait_after_karpenter resource
time_sleep.wait_on_destroy resource
time_static.timestamp_id resource
aws_availability_zones.available data source
aws_caller_identity.current data source
aws_iam_policy_document.fargate_fluentbit data source
aws_iam_policy_document.k8s_access_assume data source
aws_iam_policy_document.karpenter_controller data source
aws_iam_roles.sso data source
aws_region.current data source
aws_route53_zone.base_domain_zone data source
aws_route_tables.private_route_tables data source

Inputs

Name Description Type Default Required
ack_iam_policy_arn IAM policy ARN to attach to the ACK capability role. Defaults to AdministratorAccess if not specified. string null no
acm_certificate ACM certificate configuration for the domain(s). Controls domain name, alternative domain names, wildcard configuration, and validation behavior.
Options include:
- domain_name: Primary domain name for the certificate. If not provided, uses base_domain from other configuration.
- subject_alternative_names: List of additional domain names to include in the certificate.
- wildcard_certificates: When true, adds a wildcard prefix (*.) to all domains in the certificate.
- prepend_stack_id: When true, prepends the stack identifier to each domain name. Only works after random_string is created.
- wait_for_validation: When true, Terraform will wait for certificate validation to complete before proceeding.
object({
domain_name = optional(string)
subject_alternative_names = optional(list(string), [])
wildcard_certificates = optional(bool, false)
prepend_stack_id = optional(bool, false)
wait_for_validation = optional(bool, false)
})
{} no
argocd Argo CD configurations
object({
# Hub specific
enable_hub = optional(bool, false)
namespace = optional(string, "argocd")
hub_iam_role_name = optional(string, "argocd-controller")

# Spoke specific
enable_spoke = optional(bool, false)

hub_iam_role_arn = optional(string, null)
hub_iam_role_arns = optional(list(string), null)

# Common
tags = optional(map(string), {})
})
{} no
base_domain Base domain for the platform, used for ingress and ACM certificates string null no
cluster_admins Map of IAM roles to add as cluster admins
role_arn: ARN of the IAM role to add as cluster admin
role_name: Name of the IAM role to add as cluster admin
kubernetes_groups: List of Kubernetes groups to add the role to (default: ["system:masters"])

role_arn and role_name are mutually exclusive, exactly one must be set.
map(object({
role_arn = optional(string)
role_name = optional(string)
kubernetes_groups = optional(list(string))
}))
{} no
create_addon_pod_identity_roles Create addon pod identities roles. If set to true, all roles will be created bool true no
eks Map of EKS configurations including cluster settings and core addon customization.

Cluster settings:
- cluster_endpoint_public_access: Enable public access to cluster endpoint (default: true)
- cluster_endpoint_private_access: Enable private access to cluster endpoint (default: true)
- enable_cluster_creator_admin_permissions: Grant admin permissions to cluster creator (default: false)

Core addon settings (vpc_cni, kube_proxy, eks_pod_identity_agent):
- configuration_values: JSON string of addon configuration (merged with defaults for vpc-cni)

Example:
eks = {
cluster_endpoint_public_access = false
vpc_cni = {
configuration_values = jsonencode({
env = {
ENABLE_PREFIX_DELEGATION = "true"
WARM_PREFIX_TARGET = "1"
}
})
}
}
any {} no
enable_ack Enable ACK (AWS Controllers for Kubernetes) EKS capability. Note: AdministratorAccess is attached by default. Use ack_iam_policy_arn to override with a least-privilege policy. bool true no
enable_acm_certificate Enable ACM certificate bool false no
enable_argocd Enable Argo CD bool false no
enable_fargate_fluentbit Enable Fargate Fluentbit bool true no
enable_sso_admin_auto_discovery Enable automatic discovery of SSO admin roles. When disabled, only explicitly defined cluster_admins are used. bool true no
enable_timestamp_id Disable the timestamp-based ID generation. When true, uses a static ID instead of timestamp. bool true no
extra_cluster_addons Map of cluster addon configurations to enable for the cluster. Addon name can be the map keys or set with name. Addons are created after karpenter resources any {} no
extra_cluster_addons_timeouts Create, update, and delete timeout configurations for the cluster addons map(string) {} no
karpenter Karpenter configurations
object({
subnet_cidrs = optional(list(string), [])
})
{} no
karpenter_helm_set List of Karpenter Helm set values
list(object({
name = string
value = string
type = optional(string)
}))
[] no
karpenter_helm_values List of Karpenter Helm values list(string) [] no
karpenter_resources_helm_set List of Karpenter Resources Helm set values
list(object({
name = string
value = string
type = optional(string)
}))
[] no
karpenter_resources_helm_values List of Karpenter Resources Helm values list(string) [] no
kubernetes_access_roles Map of reusable IAM roles that can be assumed by multiple principals.
Creates standard roles that grant different levels of Kubernetes access.

Supported predefined access_level values:
- "view" -> AmazonEKSViewPolicy (read-only)
- "edit" -> AmazonEKSEditPolicy (create/update resources)
- "admin" -> AmazonEKSClusterAdminPolicy (full admin)
- "custom" -> Use custom_policy_arns (list of policy ARNs)

Example:
{
"readonly" = {
controller_iam_role_arns = [
"arn:aws:iam::123456789012:role/backstage-prod",
"arn:aws:iam::123456789012:role/ai-agent"
]
access_level = "view" # Predefined: view, edit, admin, or custom
scope = "cluster" # "cluster" or "namespace"
namespaces = [] # required if scope = "namespace"
}
"developer" = {
controller_iam_role_arns = ["arn:aws:iam::123456789012:role/dev-team"]
access_level = "edit"
scope = "namespace"
namespaces = ["development", "staging"]
}
"ops-admin" = {
controller_iam_role_arns = ["arn:aws:iam::123456789012:role/ops-team"]
access_level = "admin"
scope = "cluster"
}
"custom-access" = {
controller_iam_role_arns = ["arn:aws:iam::123456789012:role/special-service"]
access_level = "custom"
custom_policy_arns = [
"arn:aws:eks::aws:cluster-access-policy/MyCustomPolicy"
]
scope = "cluster"
}
}

This creates:
- {cluster}-k8s-readonly (view access)
- {cluster}-k8s-developer (edit access on dev/staging namespaces)
- {cluster}-k8s-ops-admin (full admin access)
- {cluster}-k8s-custom-access (custom policies)
map(object({
controller_iam_role_arns = list(string)
access_level = string # "view", "edit", "admin", or "custom"
scope = string # "cluster" or "namespace"
namespaces = optional(list(string), [])
custom_policy_arns = optional(list(string), [])
external_id = optional(string)
}))
{} no
kubernetes_version Kubernetes version for the EKS cluster (e.g., "1.34") string "1.34" no
name The name of the platform, a timestamp will be appended to this name to make the stack_name. If not provided, the name of the directory will be used. string "" no
region AWS region to use string null no
tags Default tags to apply to all resources map(string) {} no
vpc VPC configurations
object({
vpc_id = string
vpc_cidr = string
private_subnets = list(string)
intra_subnets = list(string)
})
n/a yes

Outputs

Name Description
ack Map of attributes for the ACK EKS capability
argocd Map of attributes for the ArgoCD module
eks Map of attributes for the EKS cluster
karpenter Map of attributes for the Karpenter module
kubernetes_access_role_arns Map of reusable Kubernetes access role names to their IAM role ARNs
kubernetes_access_roles Detailed information about reusable Kubernetes access IAM roles

Authors

Module is maintained by Alfredo Gottardo, David Beauvererd, Davide Cammarata, Francisco Ferreira, Roland Bapst and Samuel Wibrow

License

Apache 2 Licensed. See LICENSE for full details.