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
2 changes: 2 additions & 0 deletions k8s/specs/tofu/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
21 changes: 21 additions & 0 deletions k8s/specs/tofu/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
locals {
# Module identifier
iam_module_name = "iam"

# Whether resources are created
iam_create = var.iam_create_role
Comment thread
fedemaleh marked this conversation as resolved.

# Derived names (overridable via variables)
permissions_role_name = var.permissions_role_name != "" ? var.permissions_role_name : "nullplatform-${var.cluster_name}-agent-permissions-role"
policies_name_prefix = var.policies_name_prefix != "" ? var.policies_name_prefix : "nullplatform_${var.cluster_name}"

# Primary agent role trusted by the permissions role. Defaults to the
# conventional agent role name for the cluster when not provided explicitly.
agent_role_arn = var.agent_role_arn != "" ? var.agent_role_arn : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/nullplatform-${var.cluster_name}-agent-role"

# Default tags applied to every IAM resource
iam_default_tags = merge(var.iam_resource_tags_json, {
ManagedBy = "nullplatform-custom-scope-role"
Module = local.iam_module_name
})
}
166 changes: 166 additions & 0 deletions k8s/specs/tofu/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
################################################################################
# IAM permissions role assumed by the nullplatform agent role
#
# Holds the actual workload policies (Route53, EKS, ELB). Its trust policy
# trusts only the agent IRSA role (plus any additional roles), so an agent's IRSA
# token cannot exercise these permissions without first assuming it (sts:AssumeRole).
#
# This is the "permissions role" half of the reference module
# tofu-modules/infrastructure/aws/iam/agent. The IRSA agent role itself is
# created once at cluster setup and is out of scope for this module.
################################################################################

resource "aws_iam_role" "nullplatform_agent_permissions" {
count = local.iam_create ? 1 : 0

name = local.permissions_role_name
description = "Permissions role assumed by the nullplatform agent role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { AWS = concat([local.agent_role_arn], var.additional_agent_role_arns) }
Action = "sts:AssumeRole"
}]
Comment thread
fedemaleh marked this conversation as resolved.
})

tags = local.iam_default_tags
}

################################################################################
# Policy attachments
################################################################################

resource "aws_iam_role_policy_attachment" "permissions_route53" {
count = local.iam_create ? 1 : 0

role = aws_iam_role.nullplatform_agent_permissions[0].name
policy_arn = aws_iam_policy.nullplatform_route53_policy[0].arn
}

resource "aws_iam_role_policy_attachment" "permissions_eks" {
count = local.iam_create ? 1 : 0

role = aws_iam_role.nullplatform_agent_permissions[0].name
policy_arn = aws_iam_policy.nullplatform_eks_policy[0].arn
}

resource "aws_iam_role_policy_attachment" "permissions_elb" {
count = local.iam_create ? 1 : 0

role = aws_iam_role.nullplatform_agent_permissions[0].name
policy_arn = aws_iam_policy.nullplatform_elb_policy[0].arn
}
Comment thread
fedemaleh marked this conversation as resolved.

################################################################################
# Route 53 IAM policy
# Manage Route 53 DNS records for service discovery.
################################################################################

resource "aws_iam_policy" "nullplatform_route53_policy" {
count = local.iam_create ? 1 : 0

name = "${local.policies_name_prefix}_route53_policy"
description = "Policy for managing Route 53 DNS records"
tags = local.iam_default_tags
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets",
"route53:GetHostedZone",
"route53:ListHostedZones",
"route53:ListHostedZonesByName"
],
"Resource" : [
"arn:aws:route53:::hostedzone/*"
],
}
]
})
}

################################################################################
# Elastic Load Balancing (ELB) IAM policy
# Describe and monitor load balancers and target groups.
################################################################################

resource "aws_iam_policy" "nullplatform_elb_policy" {
count = local.iam_create ? 1 : 0

name = "${local.policies_name_prefix}_elb_policy"
description = "Policy for managing Elastic Load Balancing resources"
tags = local.iam_default_tags
policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeTargetGroups"
],
"Resource" : "*",
"Condition" : {
"StringEquals" : {
"aws:RequestedRegion" : [
data.aws_region.current.region
]
}
}
},
{
"Effect" : "Allow",
"Action" : [
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeRules"
],
"Resource" : [
"arn:aws:elasticloadbalancing:*:*:loadbalancer/app/k8s-nullplatform-*",
"arn:aws:elasticloadbalancing:*:*:targetgroup/k8s-nullplatform-*"
],
}
]
}
)
}

################################################################################
# EKS IAM policy
# Describe and list EKS cluster resources.
################################################################################

resource "aws_iam_policy" "nullplatform_eks_policy" {
count = local.iam_create ? 1 : 0

name = "${local.policies_name_prefix}_eks_policy"
description = "Policy for managing EKS cluster resources"
tags = local.iam_default_tags
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"eks:DescribeCluster",
"eks:ListClusters",
"eks:DescribeNodegroup",
"eks:ListNodegroups",
"eks:DescribeAddon",
"eks:ListAddons"
],
"Resource" : [
"arn:aws:eks:*:*:cluster/*",
"arn:aws:eks:*:*:nodegroup/*",
"arn:aws:eks:*:*:addon/*"
],
}
]
})
}
14 changes: 14 additions & 0 deletions k8s/specs/tofu/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "permissions_role_arn" {
description = "ARN of the permissions role assumed by the nullplatform agent role"
value = local.iam_create ? aws_iam_role.nullplatform_agent_permissions[0].arn : ""
}

output "permissions_role_name" {
description = "Name of the permissions role"
value = local.iam_create ? aws_iam_role.nullplatform_agent_permissions[0].name : ""
}

output "permissions_role_id" {
description = "ID of the permissions role"
value = local.iam_create ? aws_iam_role.nullplatform_agent_permissions[0].id : ""
}
50 changes: 50 additions & 0 deletions k8s/specs/tofu/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
variable "agent_role_arn" {
description = "ARN of the primary nullplatform agent IRSA role allowed to assume this permissions role via sts:AssumeRole, and always a trusted principal of the role's trust policy. Defaults (when empty) to the conventional agent role for the cluster: arn:aws:iam::<account>:role/nullplatform-<cluster_name>-agent-role."
type = string
default = ""

validation {
condition = var.agent_role_arn == "" || can(regex("^arn:aws:iam::[0-9]{12}:role/.+", var.agent_role_arn))
error_message = "agent_role_arn must be empty (to use the derived default) or match arn:aws:iam::<account-id>:role/<role-name>"
}
}

variable "additional_agent_role_arns" {
description = "Extra IAM role ARNs allowed to assume this permissions role, appended to agent_role_arn in the trust policy. Defaults to none."
type = list(string)
default = []

validation {
condition = alltrue([for arn in var.additional_agent_role_arns : can(regex("^arn:aws:iam::[0-9]{12}:role/.+", arn))])
error_message = "each additional_agent_role_arns entry must match arn:aws:iam::<account-id>:role/<role-name>"
}
}

variable "cluster_name" {
description = "Name of the cluster where the agent runs. Used to derive default resource names."
type = string
}

variable "permissions_role_name" {
description = "Override for the permissions IAM role name. Defaults to nullplatform-{cluster_name}-agent-permissions-role."
type = string
default = ""
}

variable "policies_name_prefix" {
description = "Override for the IAM policy name prefix. Defaults to nullplatform_{cluster_name}."
type = string
default = ""
}

variable "iam_create_role" {
description = "Whether to create the permissions role and its policies. When false, the module produces no resources."
type = bool
default = true
}

variable "iam_resource_tags_json" {
description = "Tags to apply to IAM resources created by this module."
type = map(string)
default = {}
}
10 changes: 10 additions & 0 deletions k8s/specs/tofu/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
# v6+ required: the ELB policy reads data.aws_region.current.region,
# which replaced the v5 `.name` attribute.
version = ">= 6.0"
}
}
}
Loading