Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .codex/config.toml
100644 → 100755
Empty file.
Empty file modified .github/workflows/terraform-pr.yml
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .terraform-docs.yml
100644 → 100755
Empty file.
Empty file modified AGENTS.md
100644 → 100755
Empty file.
Empty file modified Makefile
100644 → 100755
Empty file.
62 changes: 62 additions & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Simple Terraform module for creating an Amazon EKS cluster with:
- Managed node group IAM role
- One or more EKS managed node groups
- Core EKS add-ons: `coredns`, `kube-proxy`, and `vpc-cni`
- Optional Amazon EKS managed capabilities: Argo CD, ACK, and KRO
- Optional EKS-side Karpenter readiness without installing Karpenter itself
- Useful connection and composition outputs

Expand Down Expand Up @@ -47,8 +48,57 @@ aws eks update-kubeconfig --name dev-eks
- `examples/minimal` - smallest practical module call using defaults for node groups, add-ons, API access, and logging.
- `examples/basic` - simple explicit managed node group configuration.
- `examples/advanced` - restricted API access, full control-plane logging, multiple node groups, expanded add-on configuration, optional IAM-backed add-ons, and optional node subnet overrides.
- `examples/capabilities` - Amazon EKS managed capabilities for Argo CD, ACK, and KRO, including IAM Identity Center authentication for Argo CD and optional capability role policies.
- `examples/karpenter-ready` - EKS-side Karpenter readiness with discovery tags, a Karpenter node role, and node access entry while leaving the Karpenter controller, Helm release, interruption queue, NodePool, and EC2NodeClass to a separate module.

## EKS Capabilities

Enable the `capabilities` map when this module should create Amazon EKS managed capabilities. Supported types are `ARGOCD`, `ACK`, and `KRO`.

```hcl
module "eks" {
source = "./eks"

name = "dev"
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]

capabilities = {
argocd = {
type = "ARGOCD"
argocd = {
idc_instance_arn = "arn:aws:sso:::instance/ssoins-7223a1b234567890"
namespace = "argocd"
rbac_role_mappings = [
{
role = "ADMIN"
identities = [
{
id = "12345678-1234-1234-1234-123456789012"
type = "SSO_GROUP"
}
]
}
]
}
}

ack = {
type = "ACK"
}

kro = {
type = "KRO"
create_iam_role = false
iam_role_arn = "arn:aws:iam::123456789012:role/platform/KROCapabilityRole"
}
}
}
```

When enabled, the module can create a capability IAM role trusted by `capabilities.eks.amazonaws.com` and creates all configured entries through one `aws_eks_capability.this` resource block. Attach managed policies or an inline policy to the capability role only when a capability needs access to supporting AWS services.

For `ARGOCD`, configure the nested `argocd` object with IAM Identity Center settings, optional RBAC role mappings, and optional VPC endpoint IDs. If `argocd.network_access_vpce_ids` is empty, AWS exposes the default public managed Argo CD endpoint. Supplying VPC endpoint IDs makes the Argo CD server private-only through those endpoints.

## Karpenter Readiness

Enable the `karpenter` object when this module should prepare the cluster for Karpenter-managed capacity:
Expand Down Expand Up @@ -97,12 +147,16 @@ This module deliberately does not install the Karpenter controller, create its c
| [aws_ec2_tag.karpenter_subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag) | resource |
| [aws_eks_access_entry.karpenter_node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_access_entry) | resource |
| [aws_eks_addon.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_addon) | resource |
| [aws_eks_capability.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_capability) | resource |
| [aws_eks_cluster.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster) | resource |
| [aws_eks_node_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group) | resource |
| [aws_iam_role.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.eks_capability](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.karpenter_node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.eks_capability](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy_attachment.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.eks_capability](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.karpenter_node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |

Expand All @@ -112,6 +166,7 @@ This module deliberately does not install the Karpenter controller, create its c
| ---- | ----------- | ---- | ------- | :------: |
| <a name="input_access_config"></a> [access\_config](#input\_access\_config) | Optional EKS access configuration for cluster authentication mode and creator admin permissions. | <pre>object({<br/> authentication_mode = optional(string)<br/> bootstrap_cluster_creator_admin_permissions = optional(bool)<br/> })</pre> | `null` | no |
| <a name="input_addons"></a> [addons](#input\_addons) | EKS add-ons to install after the managed node groups are created. | <pre>map(object({<br/> configuration_values = optional(string)<br/> pod_identity_associations = optional(list(object({<br/> role_arn = string<br/> service_account = string<br/> })), [])<br/> resolve_conflicts_on_create = optional(string, "OVERWRITE")<br/> resolve_conflicts_on_update = optional(string, "OVERWRITE")<br/> service_account_role_arn = optional(string)<br/> version = optional(string)<br/> }))</pre> | <pre>{<br/> "coredns": {},<br/> "kube-proxy": {},<br/> "vpc-cni": {}<br/>}</pre> | no |
| <a name="input_capabilities"></a> [capabilities](#input\_capabilities) | Amazon EKS managed capabilities to create, keyed by a stable local name. Supported types are ARGOCD, ACK, and KRO. The module can create a capability IAM role per entry, or use an externally managed role ARN. | <pre>map(object({<br/> capability_name = optional(string)<br/> create_iam_role = optional(bool, true)<br/> delete_propagation_policy = optional(string, "RETAIN")<br/> iam_policy_arns = optional(set(string), [])<br/> iam_role_arn = optional(string)<br/> iam_role_name = optional(string)<br/> inline_policy_json = optional(string)<br/> type = string<br/> argocd = optional(object({<br/> idc_instance_arn = optional(string)<br/> idc_region = optional(string)<br/> namespace = optional(string)<br/> network_access_vpce_ids = optional(set(string), [])<br/> rbac_role_mappings = optional(list(object({<br/> role = string<br/> identities = list(object({<br/> id = string<br/> type = string<br/> }))<br/> })), [])<br/> }))<br/> }))</pre> | `{}` | no |
| <a name="input_cloudwatch_log_group_kms_key_id"></a> [cloudwatch\_log\_group\_kms\_key\_id](#input\_cloudwatch\_log\_group\_kms\_key\_id) | Optional KMS key ID or ARN for encrypting the EKS control plane CloudWatch log group. | `string` | `null` | no |
| <a name="input_cloudwatch_log_retention_days"></a> [cloudwatch\_log\_retention\_days](#input\_cloudwatch\_log\_retention\_days) | Retention in days for the EKS control plane CloudWatch log group. | `number` | `30` | no |
| <a name="input_cluster_encryption_config"></a> [cluster\_encryption\_config](#input\_cluster\_encryption\_config) | Optional EKS encryption configuration for Kubernetes secrets using an existing KMS key. | <pre>object({<br/> provider_key_arn = string<br/> resources = optional(list(string), ["secrets"])<br/> })</pre> | `null` | no |
Expand All @@ -135,6 +190,13 @@ This module deliberately does not install the Karpenter controller, create its c
| Name | Description |
| ---- | ----------- |
| <a name="output_addon_arns"></a> [addon\_arns](#output\_addon\_arns) | EKS add-on ARNs by add-on name. |
| <a name="output_argocd_idc_managed_application_arns"></a> [argocd\_idc\_managed\_application\_arns](#output\_argocd\_idc\_managed\_application\_arns) | IAM Identity Center managed application ARNs by ARGOCD capability key. |
| <a name="output_argocd_server_urls"></a> [argocd\_server\_urls](#output\_argocd\_server\_urls) | Managed Argo CD server URLs by ARGOCD capability key. |
| <a name="output_capability_arns"></a> [capability\_arns](#output\_capability\_arns) | Amazon EKS capability ARNs by capability key. |
| <a name="output_capability_iam_role_arns"></a> [capability\_iam\_role\_arns](#output\_capability\_iam\_role\_arns) | IAM role ARNs used by Amazon EKS capabilities by capability key. |
| <a name="output_capability_iam_role_names"></a> [capability\_iam\_role\_names](#output\_capability\_iam\_role\_names) | IAM role names used by Amazon EKS capabilities by capability key. |
| <a name="output_capability_names"></a> [capability\_names](#output\_capability\_names) | Amazon EKS capability names by capability key. |
| <a name="output_capability_versions"></a> [capability\_versions](#output\_capability\_versions) | Amazon EKS capability software versions by capability key. |
| <a name="output_cluster_arn"></a> [cluster\_arn](#output\_cluster\_arn) | EKS cluster ARN. |
| <a name="output_cluster_certificate_authority_data"></a> [cluster\_certificate\_authority\_data](#output\_cluster\_certificate\_authority\_data) | Base64-encoded cluster certificate authority data. |
| <a name="output_cluster_endpoint"></a> [cluster\_endpoint](#output\_cluster\_endpoint) | Kubernetes API server endpoint. |
Expand Down
16 changes: 16 additions & 0 deletions data.tf
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,19 @@ data "aws_iam_policy_document" "node_assume_role" {
actions = ["sts:AssumeRole"]
}
}

data "aws_iam_policy_document" "capability_assume_role" {
statement {
effect = "Allow"

principals {
type = "Service"
identifiers = ["capabilities.eks.amazonaws.com"]
}

actions = [
"sts:AssumeRole",
"sts:TagSession"
]
}
}
Empty file modified examples/advanced/README.md
100644 → 100755
Empty file.
Empty file modified examples/advanced/main.tf
100644 → 100755
Empty file.
Empty file modified examples/advanced/outputs.tf
100644 → 100755
Empty file.
Empty file modified examples/advanced/variables.tf
100644 → 100755
Empty file.
Empty file modified examples/basic/main.tf
100644 → 100755
Empty file.
Empty file modified examples/basic/outputs.tf
100644 → 100755
Empty file.
Empty file modified examples/basic/variables.tf
100644 → 100755
Empty file.
55 changes: 55 additions & 0 deletions examples/capabilities/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# EKS Capabilities Example

This example creates an EKS cluster and enables all Amazon EKS managed capability types currently supported by the module:

- `ARGOCD` for managed Argo CD.
- `ACK` for AWS Controllers for Kubernetes.
- `KRO` for Kube Resource Orchestrator.

It requires:

- Existing subnet IDs for the cluster and managed node group.
- An IAM Identity Center instance ARN for Argo CD authentication.
- Optionally, an IAM Identity Center group ID to map to the Argo CD `ADMIN` role.
- Optionally, VPC endpoint IDs to make the managed Argo CD server private-only.
- Optional managed or inline IAM policies per capability role. The exact policies depend on what Argo CD, ACK, or KRO should access or manage.

```hcl
module "eks" {
source = "../.."

name = "example-capabilities"
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]

capabilities = {
argocd = {
type = "ARGOCD"
argocd = {
idc_instance_arn = "arn:aws:sso:::instance/ssoins-7223a1b234567890"
namespace = "argocd"
rbac_role_mappings = [
{
role = "ADMIN"
identities = [
{
id = "12345678-1234-1234-1234-123456789012"
type = "SSO_GROUP"
}
]
}
]
}
}

ack = {
type = "ACK"
}

kro = {
type = "KRO"
}
}
}
```

After apply, use `capability_arns` to inspect the created capabilities and `argocd_server_url` to open the managed Argo CD UI.
109 changes: 109 additions & 0 deletions examples/capabilities/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
terraform {
required_version = ">= 1.5.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.0"
}
}
}

provider "aws" {
region = var.region
}

module "eks" {
source = "../.."

name = var.name
cluster_name = var.cluster_name
kubernetes_version = var.kubernetes_version
subnet_ids = var.subnet_ids

endpoint_private_access = true
endpoint_public_access = true
public_access_cidrs = var.public_access_cidrs

access_config = {
authentication_mode = "API"
bootstrap_cluster_creator_admin_permissions = true
}

node_groups = {
system = {
capacity_type = "ON_DEMAND"
desired_size = 2
disk_size = 50
instance_types = var.node_instance_types
labels = { workload = "system" }
max_size = 3
min_size = 1
update_max_unavailable = 1
}
}

addons = {
coredns = {}
kube-proxy = {}
vpc-cni = {}
}

capabilities = {
argocd = {
type = "ARGOCD"
capability_name = "argocd"

create_iam_role = true
iam_policy_arns = var.argocd_capability_iam_policy_arns
inline_policy_json = var.argocd_capability_inline_policy_json

argocd = {
namespace = "argocd"
idc_instance_arn = var.identity_center_instance_arn
idc_region = var.identity_center_region
network_access_vpce_ids = var.argocd_private_vpce_ids
rbac_role_mappings = local.argocd_rbac_role_mappings
}
}

ack = {
type = "ACK"
capability_name = "ack"

create_iam_role = true
iam_policy_arns = var.ack_capability_iam_policy_arns
inline_policy_json = var.ack_capability_inline_policy_json
}

kro = {
type = "KRO"
capability_name = "kro"

create_iam_role = true
iam_policy_arns = var.kro_capability_iam_policy_arns
inline_policy_json = var.kro_capability_inline_policy_json
}
}

tags = merge(
var.tags,
{
Example = "capabilities"
}
)
}

locals {
argocd_rbac_role_mappings = var.argocd_admin_group_id == null ? [] : [
{
role = "ADMIN"
identities = [
{
id = var.argocd_admin_group_id
type = "SSO_GROUP"
}
]
}
]
}
34 changes: 34 additions & 0 deletions examples/capabilities/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
output "cluster_name" {
description = "EKS cluster name."
value = module.eks.cluster_name
}

output "capability_arns" {
description = "Amazon EKS capability ARNs by capability key."
value = module.eks.capability_arns
}

output "capability_versions" {
description = "Amazon EKS capability software versions by capability key."
value = module.eks.capability_versions
}

output "capability_iam_role_arns" {
description = "IAM role ARNs used by Amazon EKS capabilities by capability key."
value = module.eks.capability_iam_role_arns
}

output "argocd_server_url" {
description = "Managed Argo CD server URL."
value = try(module.eks.argocd_server_urls["argocd"], null)
}

output "argocd_idc_managed_application_arn" {
description = "IAM Identity Center managed application ARN created for the Argo CD capability."
value = try(module.eks.argocd_idc_managed_application_arns["argocd"], null)
}

output "update_kubeconfig_command" {
description = "AWS CLI command to configure kubectl for this cluster."
value = module.eks.update_kubeconfig_command
}
Loading