mirror of
https://github.com/ysoftdevs/terraform-aws-eks.git
synced 2026-03-18 15:33:46 +01:00
feat!: Replace the use of aws-auth configmap with EKS cluster access entry (#2858)
* feat: Replace `resolve_conflicts` with `resolve_conflicts_on_create`/`delete`; raise MSV of AWS provider to `v5.0` to support * fix: Replace dynamic DNS suffix for `sts:AssumeRole` API calls for static suffix * feat: Add module tag * feat: Align Karpenter permissions with Karpenter v1beta1/v0.32 permissions from upstream * refactor: Move `aws-auth` ConfigMap functionality to its own sub-module * chore: Update examples * feat: Add state `moved` block for Karpenter Pod Identity role re-name * fix: Correct variable `create` description * feat: Add support for cluster access entries * chore: Bump MSV of Terraform to `1.3` * fix: Replace defunct kubectl provider with an updated forked equivalent * chore: Update and validate examples for access entry; clean up provider usage * docs: Correct double redundant variable descriptions * feat: Add support for Cloudwatch log group class argument * fix: Update usage tag placement, fix Karpenter event spelling, add upcoming changes section to upgrade guide * feat: Update Karpenter module to generalize naming used and align policy with the upstream Karpenter policy * feat: Add native support for Windows based managed nodegroups similar to AL2 and Bottlerocket * feat: Update self-managed nodegroup module to use latest features of ASG * docs: Update and simplify docs * fix: Correct variable description for AMI types * fix: Update upgrade guide with changes; rename Karpenter controller resource names to support migrating for users * docs: Complete upgrade guide docs for migration and changes applied * Update examples/karpenter/README.md Co-authored-by: Anton Babenko <anton@antonbabenko.com> * Update examples/outposts/README.md Co-authored-by: Anton Babenko <anton@antonbabenko.com> * Update modules/karpenter/README.md Co-authored-by: Anton Babenko <anton@antonbabenko.com> --------- Co-authored-by: Anton Babenko <anton@antonbabenko.com>
This commit is contained in:
254
main.tf
254
main.tf
@@ -12,6 +12,8 @@ data "aws_iam_session_context" "current" {
|
||||
locals {
|
||||
create = var.create && var.putin_khuylo
|
||||
|
||||
partition = data.aws_partition.current.partition
|
||||
|
||||
cluster_role = try(aws_iam_role.this[0].arn, var.iam_role_arn)
|
||||
|
||||
create_outposts_local_cluster = length(var.outpost_config) > 0
|
||||
@@ -30,6 +32,17 @@ resource "aws_eks_cluster" "this" {
|
||||
version = var.cluster_version
|
||||
enabled_cluster_log_types = var.cluster_enabled_log_types
|
||||
|
||||
access_config {
|
||||
authentication_mode = var.authentication_mode
|
||||
|
||||
# See access entries below - this is a one time operation from the EKS API.
|
||||
# Instead, we are hardcoding this to false and if users wish to achieve this
|
||||
# same functionality, we will do that through an access entry which can be
|
||||
# enabled or disabled at any time of their choosing using the variable
|
||||
# var.enable_cluster_creator_admin_permissions
|
||||
bootstrap_cluster_creator_admin_permissions = false
|
||||
}
|
||||
|
||||
vpc_config {
|
||||
security_group_ids = compact(distinct(concat(var.cluster_additional_security_group_ids, [local.cluster_security_group_id])))
|
||||
subnet_ids = coalescelist(var.control_plane_subnet_ids, var.subnet_ids)
|
||||
@@ -71,14 +84,15 @@ resource "aws_eks_cluster" "this" {
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
{ terraform-aws-modules = "eks" },
|
||||
var.tags,
|
||||
var.cluster_tags,
|
||||
)
|
||||
|
||||
timeouts {
|
||||
create = lookup(var.cluster_timeouts, "create", null)
|
||||
update = lookup(var.cluster_timeouts, "update", null)
|
||||
delete = lookup(var.cluster_timeouts, "delete", null)
|
||||
create = try(var.cluster_timeouts.create, null)
|
||||
update = try(var.cluster_timeouts.update, null)
|
||||
delete = try(var.cluster_timeouts.delete, null)
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
@@ -109,6 +123,7 @@ resource "aws_cloudwatch_log_group" "this" {
|
||||
name = "/aws/eks/${var.cluster_name}/cluster"
|
||||
retention_in_days = var.cloudwatch_log_group_retention_in_days
|
||||
kms_key_id = var.cloudwatch_log_group_kms_key_id
|
||||
log_group_class = var.cloudwatch_log_group_class
|
||||
|
||||
tags = merge(
|
||||
var.tags,
|
||||
@@ -117,6 +132,92 @@ resource "aws_cloudwatch_log_group" "this" {
|
||||
)
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Access Entry
|
||||
################################################################################
|
||||
|
||||
locals {
|
||||
# This replaces the one time logic from the EKS API with something that can be
|
||||
# better controlled by users through Terraform
|
||||
bootstrap_cluster_creator_admin_permissions = {
|
||||
cluster_creator = {
|
||||
principal_arn = data.aws_iam_session_context.current.issuer_arn
|
||||
type = "STANDARD"
|
||||
|
||||
policy_associations = {
|
||||
admin = {
|
||||
policy_arn = "arn:${local.partition}:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
|
||||
access_scope = {
|
||||
type = "cluster"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Merge the bootstrap behavior with the entries that users provide
|
||||
merged_access_entries = merge(
|
||||
{ for k, v in local.bootstrap_cluster_creator_admin_permissions : k => v if var.enable_cluster_creator_admin_permissions },
|
||||
var.access_entries,
|
||||
)
|
||||
|
||||
# Flatten out entries and policy associations so users can specify the policy
|
||||
# associations within a single entry
|
||||
flattened_access_entries = flatten([
|
||||
for entry_key, entry_val in local.merged_access_entries : [
|
||||
for pol_key, pol_val in lookup(entry_val, "policy_associations", {}) :
|
||||
merge(
|
||||
{
|
||||
principal_arn = entry_val.principal_arn
|
||||
kubernetes_groups = lookup(entry_val, "kubernetes_groups", [])
|
||||
tags = lookup(entry_val, "tags", {})
|
||||
type = lookup(entry_val, "type", "STANDARD")
|
||||
user_name = lookup(entry_val, "user_name", null)
|
||||
},
|
||||
{ for k, v in {
|
||||
association_policy_arn = pol_val.policy_arn
|
||||
association_access_scope_type = pol_val.access_scope.type
|
||||
association_access_scope_namespaces = lookup(pol_val.access_scope, "namespaces", [])
|
||||
} : k => v if !contains(["EC2_LINUX", "EC2_WINDOWS", "FARGATE_LINUX"], lookup(entry_val, "type", "STANDARD")) },
|
||||
{
|
||||
entry_key = entry_key
|
||||
pol_key = pol_key
|
||||
}
|
||||
)
|
||||
]
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_eks_access_entry" "this" {
|
||||
for_each = { for k, v in local.flattened_access_entries : "${v.entry_key}_${v.pol_key}" => v if local.create }
|
||||
|
||||
cluster_name = aws_eks_cluster.this[0].name
|
||||
kubernetes_groups = try(each.value.kubernetes_groups, [])
|
||||
principal_arn = each.value.principal_arn
|
||||
type = try(each.value.type, "STANDARD")
|
||||
user_name = try(each.value.user_name, null)
|
||||
|
||||
tags = merge(var.tags, try(each.value.tags, {}))
|
||||
}
|
||||
|
||||
resource "aws_eks_access_policy_association" "this" {
|
||||
for_each = { for k, v in local.flattened_access_entries : "${v.entry_key}_${v.pol_key}" => v if local.create }
|
||||
|
||||
access_scope {
|
||||
namespaces = try(each.value.association_access_scope_namespaces, [])
|
||||
type = each.value.association_access_scope_type
|
||||
}
|
||||
|
||||
cluster_name = aws_eks_cluster.this[0].name
|
||||
|
||||
policy_arn = each.value.association_policy_arn
|
||||
principal_arn = each.value.principal_arn
|
||||
|
||||
depends_on = [
|
||||
aws_eks_access_entry.this,
|
||||
]
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# KMS Key
|
||||
################################################################################
|
||||
@@ -148,7 +249,10 @@ module "kms" {
|
||||
cluster = { name = "eks/${var.cluster_name}" }
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
tags = merge(
|
||||
{ terraform-aws-modules = "eks" },
|
||||
var.tags,
|
||||
)
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -239,7 +343,7 @@ resource "aws_iam_openid_connect_provider" "oidc_provider" {
|
||||
# Not available on outposts
|
||||
count = local.create_oidc_provider ? 1 : 0
|
||||
|
||||
client_id_list = distinct(compact(concat(["sts.${local.dns_suffix}"], var.openid_connect_audiences)))
|
||||
client_id_list = distinct(compact(concat(["sts.amazonaws.com"], var.openid_connect_audiences)))
|
||||
thumbprint_list = concat(local.oidc_root_ca_thumbprint, var.custom_oidc_thumbprints)
|
||||
url = aws_eks_cluster.this[0].identity[0].oidc[0].issuer
|
||||
|
||||
@@ -256,13 +360,9 @@ resource "aws_iam_openid_connect_provider" "oidc_provider" {
|
||||
locals {
|
||||
create_iam_role = local.create && var.create_iam_role
|
||||
iam_role_name = coalesce(var.iam_role_name, "${var.cluster_name}-cluster")
|
||||
iam_role_policy_prefix = "arn:${data.aws_partition.current.partition}:iam::aws:policy"
|
||||
iam_role_policy_prefix = "arn:${local.partition}:iam::aws:policy"
|
||||
|
||||
cluster_encryption_policy_name = coalesce(var.cluster_encryption_policy_name, "${local.iam_role_name}-ClusterEncryption")
|
||||
|
||||
# TODO - hopefully this can be removed once the AWS endpoint is named properly in China
|
||||
# https://github.com/terraform-aws-modules/terraform-aws-eks/issues/1904
|
||||
dns_suffix = coalesce(var.cluster_iam_role_dns_suffix, data.aws_partition.current.dns_suffix)
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "assume_role_policy" {
|
||||
@@ -274,7 +374,7 @@ data "aws_iam_policy_document" "assume_role_policy" {
|
||||
|
||||
principals {
|
||||
type = "Service"
|
||||
identifiers = ["eks.${local.dns_suffix}"]
|
||||
identifiers = ["eks.amazonaws.com"]
|
||||
}
|
||||
|
||||
dynamic "principals" {
|
||||
@@ -283,7 +383,7 @@ data "aws_iam_policy_document" "assume_role_policy" {
|
||||
content {
|
||||
type = "Service"
|
||||
identifiers = [
|
||||
"ec2.${local.dns_suffix}",
|
||||
"ec2.amazonaws.com",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -394,11 +494,12 @@ resource "aws_eks_addon" "this" {
|
||||
cluster_name = aws_eks_cluster.this[0].name
|
||||
addon_name = try(each.value.name, each.key)
|
||||
|
||||
addon_version = coalesce(try(each.value.addon_version, null), data.aws_eks_addon_version.this[each.key].version)
|
||||
configuration_values = try(each.value.configuration_values, null)
|
||||
preserve = try(each.value.preserve, null)
|
||||
resolve_conflicts = try(each.value.resolve_conflicts, "OVERWRITE")
|
||||
service_account_role_arn = try(each.value.service_account_role_arn, null)
|
||||
addon_version = coalesce(try(each.value.addon_version, null), data.aws_eks_addon_version.this[each.key].version)
|
||||
configuration_values = try(each.value.configuration_values, null)
|
||||
preserve = try(each.value.preserve, true)
|
||||
resolve_conflicts_on_create = try(each.value.resolve_conflicts_on_create, "OVERWRITE")
|
||||
resolve_conflicts_on_update = try(each.value.resolve_conflicts_on_update, "OVERWRITE")
|
||||
service_account_role_arn = try(each.value.service_account_role_arn, null)
|
||||
|
||||
timeouts {
|
||||
create = try(each.value.timeouts.create, var.cluster_addons_timeouts.create, null)
|
||||
@@ -422,11 +523,12 @@ resource "aws_eks_addon" "before_compute" {
|
||||
cluster_name = aws_eks_cluster.this[0].name
|
||||
addon_name = try(each.value.name, each.key)
|
||||
|
||||
addon_version = coalesce(try(each.value.addon_version, null), data.aws_eks_addon_version.this[each.key].version)
|
||||
configuration_values = try(each.value.configuration_values, null)
|
||||
preserve = try(each.value.preserve, null)
|
||||
resolve_conflicts = try(each.value.resolve_conflicts, "OVERWRITE")
|
||||
service_account_role_arn = try(each.value.service_account_role_arn, null)
|
||||
addon_version = coalesce(try(each.value.addon_version, null), data.aws_eks_addon_version.this[each.key].version)
|
||||
configuration_values = try(each.value.configuration_values, null)
|
||||
preserve = try(each.value.preserve, true)
|
||||
resolve_conflicts_on_create = try(each.value.resolve_conflicts_on_create, "OVERWRITE")
|
||||
resolve_conflicts_on_update = try(each.value.resolve_conflicts_on_update, "OVERWRITE")
|
||||
service_account_role_arn = try(each.value.service_account_role_arn, null)
|
||||
|
||||
timeouts {
|
||||
create = try(each.value.timeouts.create, var.cluster_addons_timeouts.create, null)
|
||||
@@ -468,111 +570,3 @@ resource "aws_eks_identity_provider_config" "this" {
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# aws-auth configmap
|
||||
################################################################################
|
||||
|
||||
locals {
|
||||
node_iam_role_arns_non_windows = distinct(
|
||||
compact(
|
||||
concat(
|
||||
[for group in module.eks_managed_node_group : group.iam_role_arn if group.platform != "windows"],
|
||||
[for group in module.self_managed_node_group : group.iam_role_arn if group.platform != "windows"],
|
||||
var.aws_auth_node_iam_role_arns_non_windows,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
node_iam_role_arns_windows = distinct(
|
||||
compact(
|
||||
concat(
|
||||
[for group in module.eks_managed_node_group : group.iam_role_arn if group.platform == "windows"],
|
||||
[for group in module.self_managed_node_group : group.iam_role_arn if group.platform == "windows"],
|
||||
var.aws_auth_node_iam_role_arns_windows,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fargate_profile_pod_execution_role_arns = distinct(
|
||||
compact(
|
||||
concat(
|
||||
[for group in module.fargate_profile : group.fargate_profile_pod_execution_role_arn],
|
||||
var.aws_auth_fargate_profile_pod_execution_role_arns,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
aws_auth_configmap_data = {
|
||||
mapRoles = yamlencode(concat(
|
||||
[for role_arn in local.node_iam_role_arns_non_windows : {
|
||||
rolearn = role_arn
|
||||
username = "system:node:{{EC2PrivateDNSName}}"
|
||||
groups = [
|
||||
"system:bootstrappers",
|
||||
"system:nodes",
|
||||
]
|
||||
}
|
||||
],
|
||||
[for role_arn in local.node_iam_role_arns_windows : {
|
||||
rolearn = role_arn
|
||||
username = "system:node:{{EC2PrivateDNSName}}"
|
||||
groups = [
|
||||
"eks:kube-proxy-windows",
|
||||
"system:bootstrappers",
|
||||
"system:nodes",
|
||||
]
|
||||
}
|
||||
],
|
||||
# Fargate profile
|
||||
[for role_arn in local.fargate_profile_pod_execution_role_arns : {
|
||||
rolearn = role_arn
|
||||
username = "system:node:{{SessionName}}"
|
||||
groups = [
|
||||
"system:bootstrappers",
|
||||
"system:nodes",
|
||||
"system:node-proxier",
|
||||
]
|
||||
}
|
||||
],
|
||||
var.aws_auth_roles
|
||||
))
|
||||
mapUsers = yamlencode(var.aws_auth_users)
|
||||
mapAccounts = yamlencode(var.aws_auth_accounts)
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "aws_auth" {
|
||||
count = var.create && var.create_aws_auth_configmap ? 1 : 0
|
||||
|
||||
metadata {
|
||||
name = "aws-auth"
|
||||
namespace = "kube-system"
|
||||
}
|
||||
|
||||
data = local.aws_auth_configmap_data
|
||||
|
||||
lifecycle {
|
||||
# We are ignoring the data here since we will manage it with the resource below
|
||||
# This is only intended to be used in scenarios where the configmap does not exist
|
||||
ignore_changes = [data, metadata[0].labels, metadata[0].annotations]
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map_v1_data" "aws_auth" {
|
||||
count = var.create && var.manage_aws_auth_configmap ? 1 : 0
|
||||
|
||||
force = true
|
||||
|
||||
metadata {
|
||||
name = "aws-auth"
|
||||
namespace = "kube-system"
|
||||
}
|
||||
|
||||
data = local.aws_auth_configmap_data
|
||||
|
||||
depends_on = [
|
||||
# Required for instances where the configmap does not exist yet to avoid race condition
|
||||
kubernetes_config_map.aws_auth,
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user