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
270 changes: 270 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion infrastructure/aws/acm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The module creates an aws_acm_certificate resource with DNS validation, which is

```hcl
module "acm" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/acm?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/acm?ref=v5.1.0"

domain_name = "your-domain-name"
zone_id = "your-zone-id"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/aws_load_balancer_controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This module creates a helm_release resource to deploy the AWS Load Balancer Cont

```hcl
module "aws_load_balancer_controller" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/aws_load_balancer_controller?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/aws_load_balancer_controller?ref=v5.1.0"

cluster_name = "your-cluster-name"
vpc_id = "your-vpc-id"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This module creates an S3 bucket with versioning and server-side encryption enab

```hcl
module "backend" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/backend?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/backend?ref=v5.1.0"
}
```

Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/dns/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The module conditionally creates an aws_route53_zone resource for a public hoste

```hcl
module "dns" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/dns?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/dns?ref=v5.1.0"

domain_name = "your-domain-name"
vpc_id = "your-vpc-id"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The module wraps terraform-aws-modules/eks to create the EKS cluster (aws_eks_cl

```hcl
module "eks" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/eks?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/eks?ref=v5.1.0"

aws_subnets_private_ids = "your-aws-subnets-private-ids"
aws_vpc_vpc_id = "your-aws-vpc-vpc-id"
Expand Down
94 changes: 28 additions & 66 deletions infrastructure/aws/iam/agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,33 @@

## Description

Creates an IRSA-enabled IAM agent role for the nullplatform Kubernetes service account on EKS, using privilege separation: the agent role only carries an sts:AssumeRole policy and assumes a separate permissions role (provisioned outside this module) that holds the scoped workload policies
Creates an IRSA (IAM Roles for Service Accounts) role for a nullplatform agent on EKS, with an assume-role policy allowing the agent to assume a conventional permissions role and any additional roles

## Architecture

The module uses the terraform-aws-modules/iam//modules/iam-role-for-service-accounts submodule to create an aws_iam_role (the agent role) with an OIDC trust policy bound to a specific Kubernetes namespace and service account. The agent role only carries an sts:AssumeRole policy that allows it to assume a permissions role (and any additional assume_role_arns).

The default permissions role and its workload policies (Route53, ELB, EKS, AVP) are **no longer created by this module**: they are provisioned per-cluster by the k8s scope's OpenTofu module (`k8s/scope/tofu/iam/modules` in the scopes repo). This module still authorizes assuming that role by its conventional ARN (`nullplatform-{cluster_name}-agent-permissions-role`), derived from the role name and the caller account id, and exposes that ARN as an output. The scope module must create the permissions role with that same conventional name so the wiring matches.
The module uses the terraform-aws-modules/iam//modules/iam-role-for-service-accounts module to create an aws_iam_role with an OIDC trust policy scoped to a specific Kubernetes namespace and service account. An aws_iam_policy (nullplatform_assume_role_policy) is created and attached to the agent role, granting sts:AssumeRole on a conventionally named permissions role ARN, any extra permissions roles, and any caller-supplied assume_role_arns. Optionally, one or more aws_iam_role resources (extra_permissions) are created via for_each from var.permissions_roles, each trusting only the agent role ARN, with aws_iam_role_policy_attachment resources wiring the provided policy ARNs to each extra role.

## Features

- Creates an IRSA IAM agent role scoped to a specific Kubernetes namespace and service account via OIDC provider trust
- Keeps the agent role minimal: it only carries an sts:AssumeRole policy targeting the (externally-created) permissions role and any additional assume_role_arns
- Authorizes assuming the conventional permissions role ARN even though the role itself is created elsewhere (k8s scope tofu module)
- Supports attaching additional custom IAM policies to the agent role via the additional_policies map
- Supports creating additional permissions roles via the permissions_roles map, each trusting the agent role and assumable by it
- Creates IRSA-enabled aws_iam_role scoped to a specific Kubernetes namespace and service account via OIDC provider trust
- Creates aws_iam_policy granting sts:AssumeRole on a conventional permissions role ARN and any additional supplied role ARNs
- Creates optional extra aws_iam_role resources (permissions_roles) trusted exclusively by the agent role with configurable policy attachments
- Attaches additional caller-supplied policy ARNs directly to the agent role via var.additional_policies
- Outputs the agent role ARN, the conventional permissions role ARN, and a map of extra permissions role ARNs for downstream consumption
- Derives deterministic role ARNs from account ID and name locals to avoid circular dependencies between role trust and assume policies

## Basic Usage

```hcl
module "agent" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/agent?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/agent?ref=v5.1.0"

agent_namespace = "your-agent-namespace"
aws_iam_openid_connect_provider_arn = "your-aws-iam-openid-connect-provider-arn"
cluster_name = "your-cluster-name"
}
```

## Multiple permissions roles

The agent is always allowed to assume the default permissions role by its
conventional ARN (`nullplatform-{cluster_name}-agent-permissions-role`), which is
created externally by the k8s scope tofu module. To have the agent assume
additional, module-created roles with their own policies, use the
`permissions_roles` map. Each entry creates a role that trusts the agent role and
gets the given policy ARNs attached; the agent's assume policy is extended with
all of them.

```hcl
module "agent" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/agent?ref=v4.5.0"

agent_namespace = "your-agent-namespace"
aws_iam_openid_connect_provider_arn = "your-aws-iam-openid-connect-provider-arn"
cluster_name = "your-cluster-name"

permissions_roles = {
data = {
policy_arns = ["arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"]
}
ops = {
name = "custom-ops-role"
policy_arns = ["arn:aws:iam::123456789012:policy/ops-policy"]
}
}
}
```

For roles that already exist elsewhere (not created by this module), use
`assume_role_arns` instead — the agent will be allowed to assume them directly.

## Using Outputs

```hcl
Expand Down Expand Up @@ -94,7 +60,6 @@ resource "example_resource" "this" {
| [aws_iam_policy.nullplatform_assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role.extra_permissions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.extra_permissions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |

## Inputs

Expand All @@ -106,7 +71,7 @@ resource "example_resource" "this" {
| <a name="input_aws_iam_openid_connect_provider_arn"></a> [aws\_iam\_openid\_connect\_provider\_arn](#input\_aws\_iam\_openid\_connect\_provider\_arn) | ARN of the AWS IAM OIDC provider for EKS service account authentication | `string` | n/a | yes |
| <a name="input_cluster_name"></a> [cluster\_name](#input\_cluster\_name) | Name of the cluster where the policy runs | `string` | n/a | yes |
| <a name="input_permissions_role_name"></a> [permissions\_role\_name](#input\_permissions\_role\_name) | Override for the permissions IAM role name. Defaults to nullplatform-{cluster\_name}-agent-permissions-role | `string` | `""` | no |
| <a name="input_permissions_roles"></a> [permissions\_roles](#input\_permissions\_roles) | Additional permissions roles created by this module and assumable by the agent role. Map key is a logical name; name overrides the role name (defaults to nullplatform-{cluster\_name}-{key}); policy\_arns are the policy ARNs attached to the role. | <pre>map(object({<br> name = optional(string)<br> policy_arns = optional(list(string), [])<br> }))</pre> | `{}` | no |
| <a name="input_permissions_roles"></a> [permissions\_roles](#input\_permissions\_roles) | Additional permissions roles created by this module and assumable by the agent role. Map key is a logical name; name overrides the role name (defaults to nullplatform-{cluster\_name}-{key}); policy\_arns are the policy ARNs attached to the role. | <pre>map(object({<br/> name = optional(string)<br/> policy_arns = optional(list(string), [])<br/> }))</pre> | `{}` | no |
| <a name="input_policies_name_prefix"></a> [policies\_name\_prefix](#input\_policies\_name\_prefix) | Override for IAM policy name prefix. Defaults to nullplatform\_{cluster\_name} | `string` | `""` | no |
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | Override for the IAM role name. Defaults to nullplatform-{cluster\_name}-agent-role | `string` | `""` | no |
| <a name="input_service_account_name"></a> [service\_account\_name](#input\_service\_account\_name) | Kubernetes service account name trusted by the IRSA role | `string` | `"nullplatform-agent"` | no |
Expand All @@ -123,18 +88,15 @@ resource "example_resource" "this" {
<!-- BEGIN_AI_METADATA
{
"name": "agent",
"description": "Creates an IRSA-enabled IAM agent role for the nullplatform Kubernetes service account on EKS, using privilege separation: the agent role only carries an sts:AssumeRole policy and assumes a separate permissions role that holds the scoped workload policies",
"architecture": "The module uses the terraform-aws-modules/iam//modules/iam-role-for-service-accounts submodule to create an aws_iam_role (the agent role) with an OIDC trust policy bound to a specific Kubernetes namespace and service account. The agent role only carries an sts:AssumeRole policy that allows it to assume a separate permissions role (and any additional assume_role_arns). The permissions role is a standalone aws_iam_role whose trust policy allows only the agent role to assume it, and the four aws_iam_policy resources (Route53, ELB, EKS, and Amazon Verified Permissions) are attached to it. ARNs are derived from role names and the caller account id to avoid a circular dependency between the two roles. Both role ARNs are exposed as outputs.",
"description": "Creates an IRSA (IAM Roles for Service Accounts) role for a nullplatform agent on EKS, with an assume-role policy allowing the agent to assume a conventional permissions role and any additional roles",
"architecture": "The module uses the terraform-aws-modules/iam//modules/iam-role-for-service-accounts module to create an aws_iam_role with an OIDC trust policy scoped to a specific Kubernetes namespace and service account. An aws_iam_policy (nullplatform_assume_role_policy) is created and attached to the agent role, granting sts:AssumeRole on a conventionally named permissions role ARN, any extra permissions roles, and any caller-supplied assume_role_arns. Optionally, one or more aws_iam_role resources (extra_permissions) are created via for_each from var.permissions_roles, each trusting only the agent role ARN, with aws_iam_role_policy_attachment resources wiring the provided policy ARNs to each extra role.",
"features": [
"Creates an IRSA IAM agent role scoped to a specific Kubernetes namespace and service account via OIDC provider trust",
"Keeps the agent role minimal: it only carries an sts:AssumeRole policy targeting the permissions role and any additional assume_role_arns",
"Creates a separate permissions role that trusts only the agent role and holds the workload policies",
"Attaches a Route53 policy granting DNS record management permissions for hosted zones to the permissions role",
"Attaches an ELB policy granting describe permissions for load balancers and target groups to the permissions role",
"Attaches an EKS policy granting read access to clusters, node groups, and addons to the permissions role",
"Attaches an Amazon Verified Permissions (AVP) policy granting full verifiedpermissions access to the permissions role",
"Supports attaching additional custom IAM policies to the agent role via the additional_policies map",
"Supports creating additional permissions roles via the permissions_roles map, each trusting the agent role and assumable by it"
"Creates IRSA-enabled aws_iam_role scoped to a specific Kubernetes namespace and service account via OIDC provider trust",
"Creates aws_iam_policy granting sts:AssumeRole on a conventional permissions role ARN and any additional supplied role ARNs",
"Creates optional extra aws_iam_role resources (permissions_roles) trusted exclusively by the agent role with configurable policy attachments",
"Attaches additional caller-supplied policy ARNs directly to the agent role via var.additional_policies",
"Outputs the agent role ARN, the conventional permissions role ARN, and a map of extra permissions role ARNs for downstream consumption",
"Derives deterministic role ARNs from account ID and name locals to avoid circular dependencies between role trust and assume policies"
],
"inputs": [
{
Expand All @@ -158,18 +120,13 @@ resource "example_resource" "this" {
"required": false
},
{
"name": "additional_policies",
"description": "Additional policy ARNs to attach to the agent role",
"required": false
},
{
"name": "permissions_role_name",
"description": "Override for the permissions IAM role name. Defaults to nullplatform-{cluster_name}-agent-permissions-role",
"name": "permissions_roles",
"description": "Additional permissions roles created by this module and assumable by the agent role. Map key is a logical name; name overrides the role name (defaults to nullplatform-{cluster_name}-{key}); policy_arns are the policy ARNs attached to the role.",
"required": false
},
{
"name": "permissions_roles",
"description": "Additional permissions roles created by this module and assumable by the agent role. Map key is a logical name; name overrides the role name (defaults to nullplatform-{cluster_name}-{key}); policy_arns are the policy ARNs attached to the role.",
"name": "additional_policies",
"description": "Additional policy ARNs to attach to the agent role",
"required": false
},
{
Expand All @@ -182,6 +139,11 @@ resource "example_resource" "this" {
"description": "Override for the IAM role name. Defaults to nullplatform-{cluster_name}-agent-role",
"required": false
},
{
"name": "permissions_role_name",
"description": "Override for the permissions IAM role name. Defaults to nullplatform-{cluster_name}-agent-permissions-role",
"required": false
},
{
"name": "policies_name_prefix",
"description": "Override for IAM policy name prefix. Defaults to nullplatform_{cluster_name}",
Expand All @@ -193,6 +155,6 @@ resource "example_resource" "this" {
"nullplatform_agent_permissions_role_arn",
"nullplatform_agent_extra_permissions_role_arns"
],
"hash": "5142461751e55436dbc95fa82a376955"
"hash": "080cc2f1402698f5884c98e39f0ef01a"
}
END_AI_METADATA -->
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This module creates an IAM role for the AWS Load Balancer Controller using the t

```hcl
module "aws_load_balancer_controller_iam" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/aws_load_balancer_controller_iam?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/aws_load_balancer_controller_iam?ref=v5.1.0"

aws_iam_openid_connect_provider_arn = "your-aws-iam-openid-connect-provider-arn"
cluster_name = "your-cluster-name"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/cert_manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ An aws_iam_policy is created granting Route53 permissions (GetChange, ChangeReso

```hcl
module "cert_manager" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/cert_manager?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/cert_manager?ref=v5.1.0"

aws_iam_openid_connect_provider_arn = "your-aws-iam-openid-connect-provider-arn"
cluster_name = "your-cluster-name"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/ci-build-workflow-user/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The module creates an aws_iam_user named with the cluster_name prefix and genera

```hcl
module "ci-build-workflow-user" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/ci-build-workflow-user?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/ci-build-workflow-user?ref=v5.1.0"

cluster_name = "your-cluster-name"
}
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/ecr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The module creates an aws_iam_role named nullplatform-{cluster_name}-application

```hcl
module "ecr" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/ecr?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/ecr?ref=v5.1.0"

build_workflow_group_name = "your-build-workflow-group-name"
cluster_name = "your-cluster-name"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/external_dns/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The module creates an aws_iam_policy granting Route53 permissions scoped to the

```hcl
module "external_dns" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/external_dns?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/external_dns?ref=v5.1.0"

aws_iam_openid_connect_provider_arn = "your-aws-iam-openid-connect-provider-arn"
cluster_name = "your-cluster-name"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/s3-assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This module creates an aws_iam_policy resource named with the cluster_name prefi

```hcl
module "s3-assets" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/s3-assets?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/s3-assets?ref=v5.1.0"

assets_bucket = "your-assets-bucket"
build_workflow_group_name = "your-build-workflow-group-name"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/iam/s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The module creates an aws_s3_bucket_policy resource attached to an existing S3 b

```hcl
module "s3" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/s3?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/iam/s3?ref=v5.1.0"

bucket_arn = "your-bucket-arn"
bucket_id = "your-bucket-id"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/aws/ingress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The module creates up to two kubernetes_ingress_v1 resources — one for an inte

```hcl
module "ingress" {
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/ingress?ref=v5.0.0"
source = "git::https://github.com/nullplatform/tofu-modules.git//infrastructure/aws/ingress?ref=v5.1.0"

certificate_arn = "your-certificate-arn"
}
Expand Down
Loading