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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,6 @@ terraform.tfstate.backup
.claude/

# Local examples (for testing only, not part of the module distribution)
nullplatform/scope_definition/examples/
nullplatform/scope_definition/examples/
# Local API skill token (credential — never commit)
np-api-skill.token
25 changes: 25 additions & 0 deletions nullplatform/identity-access-control/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 104 additions & 0 deletions nullplatform/identity-access-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Module: identity-access-control

## Description

Configures an identity & access control provider in nullplatform via a `nullplatform_provider_config` resource. The provider type defaults to the AWS IAM provider (`aws-iam-configuration`) but is exposed as a variable, so new clouds can be supported by passing their own `type` and `attributes`.

## Architecture

The module creates a single `nullplatform_provider_config` resource. The `type` input selects which provider specification to configure (default `aws-iam-configuration`), and the `attributes` input carries the provider-specific configuration, JSON-encoded to match that specification's schema. `dimensions` metadata is supported for environment- or region-specific configuration. The module is intentionally generic: it does not validate cloud-specific attribute shapes, leaving that to the caller, so adding a new cloud requires no changes here. Unlike provider configs that hold externally-rotated secrets, this module does not set `ignore_changes` on `attributes`, so Terraform remains the source of truth and changes are propagated on apply.

For AWS, this module is the platform-side counterpart to `infrastructure/aws/iam/agent`: that module grants the agent `sts:AssumeRole` permission over the role ARNs, while this module publishes those ARNs to nullplatform under friendly selectors.

## Features

- Creates a nullplatform identity & access control provider configuration
- Cloud-agnostic: `type` and `attributes` are inputs, defaulting to AWS IAM
- For AWS IAM, maps friendly selectors to assumable IAM role ARNs for use in scope/service code
- Supports dimensions for environment- or region-specific configuration
- Keeps Terraform as the source of truth for the configuration (no attribute drift suppression)

## Basic Usage (AWS IAM — default)

```hcl
module "identity_access_control" {
source = "git::https://github.com/nullplatform/tofu-modules.git//nullplatform/identity-access-control?ref=v4.0.1"

nrn = "your-nrn"

attributes = {
iam_role_arns = {
arns = [
{
selector = "billing"
arn = "arn:aws:iam::123456789012:role/billing-reader"
},
{
selector = "analytics"
arn = "arn:aws:iam::123456789012:role/analytics-reader"
},
]
}
}
}
```

## Usage for a new cloud

```hcl
module "identity_access_control" {
source = "git::https://github.com/nullplatform/tofu-modules.git//nullplatform/identity-access-control?ref=v4.0.1"

nrn = "your-nrn"
type = "azure-iam-configuration" # slug of the provider specification

attributes = {
# ... shape matching the azure-iam-configuration schema
}
}
```

## Using Outputs

```hcl
# Reference outputs in other resources
resource "example_resource" "this" {
example_attribute = module.identity_access_control.id
}
```

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_nullplatform"></a> [nullplatform](#requirement\_nullplatform) | >= 0.0.86 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_nullplatform"></a> [nullplatform](#provider\_nullplatform) | >= 0.0.86 |

## Resources

| Name | Type |
|------|------|
| [nullplatform_provider_config.identity_access_control](https://registry.terraform.io/providers/nullplatform/nullplatform/latest/docs/resources/provider_config) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_nrn"></a> [nrn](#input\_nrn) | nullplatform Resource Name where the provider configuration applies | `string` | n/a | yes |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | Provider-specific configuration, matching the schema of the selected provider type | `any` | n/a | yes |
| <a name="input_type"></a> [type](#input\_type) | Slug of the nullplatform provider specification to configure | `string` | `"aws-iam-configuration"` | no |
| <a name="input_dimensions"></a> [dimensions](#input\_dimensions) | Dimensions used to scope this provider configuration | `map(string)` | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | ID of the provider configuration |
| <a name="output_nrn"></a> [nrn](#output\_nrn) | NRN the provider configuration is attached to |
<!-- END_TF_DOCS -->
6 changes: 6 additions & 0 deletions nullplatform/identity-access-control/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "nullplatform_provider_config" "identity_access_control" {
nrn = var.nrn
type = var.type
dimensions = var.dimensions
attributes = jsonencode(var.attributes)
}
9 changes: 9 additions & 0 deletions nullplatform/identity-access-control/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "id" {
description = "ID of the provider configuration"
value = nullplatform_provider_config.identity_access_control.id
}

output "nrn" {
description = "NRN the provider configuration is attached to"
value = nullplatform_provider_config.identity_access_control.nrn
}
8 changes: 8 additions & 0 deletions nullplatform/identity-access-control/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
nullplatform = {
source = "nullplatform/nullplatform"
version = ">= 0.0.86"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
mock_provider "nullplatform" {}

variables {
nrn = "organization=myorg:account=myaccount"
attributes = {
iam_role_arns = {
arns = [
{ selector = "billing", arn = "arn:aws:iam::123456789012:role/billing-reader" },
{ selector = "analytics", arn = "arn:aws:iam::123456789012:role/analytics-reader" }
]
}
}
}

run "default_type_is_aws_iam_configuration" {
command = plan

assert {
condition = nullplatform_provider_config.identity_access_control.type == "aws-iam-configuration"
error_message = "Provider config type should default to 'aws-iam-configuration'"
}

assert {
condition = nullplatform_provider_config.identity_access_control.nrn == "organization=myorg:account=myaccount"
error_message = "NRN should match input"
}
}

run "custom_type_for_new_cloud" {
command = plan

variables {
type = "azure-iam-configuration"
}

assert {
condition = nullplatform_provider_config.identity_access_control.type == "azure-iam-configuration"
error_message = "Provider config type should honor the type variable"
}
}

run "attributes_are_json_encoded" {
command = plan

assert {
condition = can(jsondecode(nullplatform_provider_config.identity_access_control.attributes))
error_message = "attributes should be valid JSON"
}

assert {
condition = length(jsondecode(nullplatform_provider_config.identity_access_control.attributes).iam_role_arns.arns) == 2
error_message = "attributes should encode the provided structure verbatim"
}

assert {
condition = strcontains(nullplatform_provider_config.identity_access_control.attributes, "arn:aws:iam::123456789012:role/billing-reader")
error_message = "attributes should contain the configured role ARN"
}
}
21 changes: 21 additions & 0 deletions nullplatform/identity-access-control/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
variable "nrn" {
description = "nullplatform Resource Name where the identity & access control provider configuration applies"
type = string
}

variable "type" {
description = "Slug of the nullplatform provider specification to configure (e.g. aws-iam-configuration). Set this when adding support for a new cloud."
type = string
default = "aws-iam-configuration"
}

variable "attributes" {
description = "Provider-specific configuration, matching the schema of the selected provider type. Encoded to JSON for the provider config. For aws-iam-configuration: { iam_role_arns = { arns = [{ selector, arn }] } }."
type = any
}

variable "dimensions" {
description = "Dimensions used to scope this provider configuration (e.g., environment, region)"
type = map(string)
default = {}
}