Skip to main content

Cross-Account Parameters

NTC Parameters is a purpose-built solution for sharing configuration data across AWS multi-account environments. It addresses the unique challenges of parameter management in complex organizational structures where multiple accounts need access to shared configuration data with different read and write permissions.

The Multi-Account Parameter Challenge

In a well-architected AWS multi-account environment, resources are distributed across specialized accounts based on their function. However, these resources often need to reference each other's configuration details:

Common Scenarios

CloudTrail Configuration

  • Organizational CloudTrail hosted in management account or delegated security account
  • S3 bucket for log storage hosted in dedicated log archive account
  • Trail configuration needs the exact S3 bucket ARN from the log archive account

Security Configuration

  • S3 bucket as destination for security findings
  • Organizational Unit Ids as targets for security policies
  • Notify account owner or security contact about security findings

Network Resource Sharing

  • VPC Transit Gateway hosted in connectivity account
  • Application accounts need to attach to the Transit Gateway
  • Requires sharing Transit Gateway ID, route table IDs, and network CIDRs

Without a centralized parameter sharing solution, these scenarios typically result in:

  • Hardcoded values that become maintenance nightmares
  • Manual coordination between account teams
  • Configuration drift when values change
  • Deployment dependencies that complicate automation

Why Not AWS SSM Parameter Store?

While AWS SSM Parameter Store is excellent for single-account parameter management, it has significant limitations in multi-account scenarios:

Access Management Complexity

SSM Parameter Store Limitations:

# SSM requires cross-account IAM roles for write access
resource "aws_iam_role" "parameter_writer" {
name = "ssm-parameter-writer"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::ACCOUNT_ID:root" // we allow another account to assume this role
}
Action = "sts:AssumeRole"
}
]
})
}

# Additional policies needed for parameter access
resource "aws_iam_role_policy" "parameter_writer_policy" {
name = "ssm-parameter-access"
role = aws_iam_role.parameter_writer.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ssm:PutParameter",
"ssm:GetParameter",
"ssm:DeleteParameter"
]
Resource = "arn:aws:ssm:*:*:parameter/myorg/*" // define for which parameters to grant write access
}
]
})
}

# RAM sharing organization configuration to grant read access to parameters
resource "aws_ram_resource_share" "ssm_share" {
name = "ssm-parameter-reader"
allow_external_principals = false
}

resource "aws_ram_resource_association" "ssm_association" {
resource_arn = aws_ssm_parameter.example.arn
resource_share_arn = aws_ram_resource_share.ssm_share.arn
}

resource "aws_ram_principal_association" "dev_shared_params" {
principal = "o-example123456" # grant read access to accounts in organization
resource_share_arn = aws_ram_resource_share.ssm_share.arn
}

NTC Parameters Simplicity:

# Simple S3 bucket policy manages all access
module "ntc_parameters" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters?ref=X.X.X"

bucket_name = "myorg-parameters"
org_id = "o-example123456" # grant read access to accounts in organization

parameter_nodes = [
{
node_name = "connectivity"
node_owner_account_id = "123456789012" # grant write access to Connectivity account
},
{
node_name = "security"
node_owner_account_id = "123456789013" # grant write access to Security account
}
]
}

Data Structure Limitations

SSM Parameter Store:

  • Only supports string values
  • JSON objects must be encoded as strings
  • No native support for complex nested structures
  • Requires manual JSON parsing in consuming code
  • Up to 8 KB per parameter
# SSM Parameter Store - complex objects as JSON strings
resource "aws_ssm_parameter" "network_config" {
name = "/myorg/network/config"
type = "String"
value = jsonencode({
transit_gateway_id = "tgw-1234567890abcdef0"
route_tables = {
shared = "tgw-rtb-shared123"
isolated = "tgw-rtb-isolated456"
}
cidrs = {
connectivity = "10.0.0.0/16"
workloads = "10.1.0.0/16"
}
})
}

# Consumer must decode JSON manually
data "aws_ssm_parameter" "network_config" {
name = "/myorg/network/config"
}

locals {
network_config = jsondecode(data.aws_ssm_parameter.network_config.value)
tgw_id = local.network_config.transit_gateway_id
}

NTC Parameters:

  • Native support for complex JSON structures
  • Direct access to nested values
  • Type preservation for numbers, booleans, arrays
  • No size limits
# NTC Parameters - native JSON support
module "ntc_parameters_writer" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters//modules/writer?ref=X.X.X"

bucket_name = "myorg-parameters"
parameter_node = "connectivity"
node_parameters = {
transit_gateway_id = aws_ec2_transit_gateway.main.id
route_tables = {
shared = aws_ec2_transit_gateway_route_table.shared.id
isolated = aws_ec2_transit_gateway_route_table.isolated.id
}
cidrs = {
connectivity = "10.0.0.0/16"
workloads = "10.1.0.0/16"
}
}
}

# Consumer gets direct access to nested values
module "ntc_parameters_reader" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters//modules/reader?ref=X.X.X"

bucket_name = "myorg-parameters"
}

locals {
tgw_id = module.ntc_parameters_reader.all_parameters.connectivity.transit_gateway_id
shared_rt = module.ntc_parameters_reader.all_parameters.connectivity.route_tables.shared
}

Understanding Parameter Nodes and Node Owners

Before diving into the technical architecture, it's essential to understand the core concepts of Parameter Nodes and Node Owners that make NTC Parameters so effective for multi-account environments.

What are Parameter Nodes?

A Parameter Node is a logical grouping of related parameters that belong to a specific functional area within your AWS organization. Think of it as a namespace or container that organizes parameters by their purpose and ownership.

Each parameter node contains a subset of the total parameters in your organization, focusing on a specific domain such as:

  • Network resources (Transit Gateways, VPCs, route tables)
  • Security configurations (KMS keys, Security Hub settings, GuardDuty configurations)
  • Logging infrastructure (S3 buckets, CloudTrail settings)
  • Organization metadata (Account IDs, OU structures, policies)

What are Node Owners?

A Node Owner is the AWS account that has write access to a specific parameter node. This account is responsible for:

  • Creating and updating parameters within their node
  • Maintaining the accuracy of the parameter data
  • Managing the lifecycle of resources that generate these parameters

The node owner concept implements a clear separation of responsibilities - each account manages only the parameters for resources they own, while all accounts can read parameters from all nodes.

Real-World Example: Log Archive Node

Let's look at a real example from a log archive account that owns the log-archive parameter node:

{
"log_bucket_arns": {
"aws_config": "arn:aws:s3:::myorg-config-archive",
"dns_query_logs": "arn:aws:s3:::myorg-dns-query-logs-archive",
"guardduty": "arn:aws:s3:::myorg-guardduty-archive",
"org_cloudtrail": "arn:aws:s3:::myorg-cloudtrail-archive",
"transit_gateway_flow_logs": "arn:aws:s3:::myorg-transit-gateway-logs-archive",
"vpc_flow_logs": "arn:aws:s3:::myorg-vpc-flow-logs-archive"
},
"log_bucket_ids": {
"aws_config": "myorg-config-archive",
"dns_query_logs": "myorg-dns-query-logs-archive",
"guardduty": "myorg-guardduty-archive",
"org_cloudtrail": "myorg-cloudtrail-archive",
"transit_gateway_flow_logs": "myorg-transit-gateway-logs-archive",
"vpc_flow_logs": "myorg-vpc-flow-logs-archive"
},
"log_bucket_kms_key_arns": {
"aws_config": "arn:aws:kms:us-east-1:444444444444:key/11111111-2222-3333-4444-555555555555",
"dns_query_logs": "arn:aws:kms:us-east-1:444444444444:key/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"guardduty": "arn:aws:kms:us-east-1:444444444444:key/12345678-1234-1234-1234-123456789abc",
"org_cloudtrail": "arn:aws:kms:us-east-1:444444444444:key/87654321-4321-4321-4321-210987654321",
"transit_gateway_flow_logs": "arn:aws:kms:us-east-1:444444444444:key/abcdef12-3456-7890-abcd-ef1234567890",
"vpc_flow_logs": "arn:aws:kms:us-east-1:444444444444:key/fedcba98-7654-3210-fedc-ba9876543210"
}
}

In this example:

  • Parameter Node: log-archive (owned by the log archive account)
  • Node Owner: Log archive account (e.g., 444444444444)
  • Parameter Categories: The node contains three main parameter groups:
    • log_bucket_arns: Full ARNs for S3 buckets used by different AWS services
    • log_bucket_ids: Bucket names/IDs for reference
    • log_bucket_kms_key_arns: KMS keys used to encrypt each type of log data

Other accounts can now reference these parameters without hardcoding values:

# Security account configuring organizational CloudTrail
resource "aws_cloudtrail" "organization_trail" {
name = "organization-trail"
s3_bucket_name = module.ntc_parameters_reader.all_parameters["log-archive"].log_bucket_ids.org_cloudtrail
kms_key_id = module.ntc_parameters_reader.all_parameters["log-archive"].log_bucket_kms_key_arns.org_cloudtrail

# ... other configuration
}

NTC Parameters Architecture

NTC Parameters leverages S3's robust access control mechanisms to provide a simple yet powerful parameter sharing solution:

Core Components

# S3-based parameter storage with organization-wide access
module "ntc_parameters_bucket" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters?ref=X.X.X"

bucket_name = "myorg-ntc-parameters"

# Automatic read access for all organization members
org_id = "o-example123456"

# Granular write access per parameter node
parameter_nodes = [
{
node_name = "mgmt-organizations"
node_owner_account_id = "111111111111" # Management account
},
{
node_name = "connectivity"
node_owner_account_id = "222222222222" # Connectivity account
},
{
node_name = "security-tooling"
node_owner_account_id = "333333333333" # Security account
},
{
node_name = "log-archive"
node_owner_account_id = "444444444444" # Log archive account
}
]
}

Parameter Node Structure

Parameter nodes are organized in S3 using a specific folder structure that separates ownership information, optional account mapping, and individual node parameters:

s3://myorg-ntc-parameters/
├── nodeowners.json # Node ownership mapping and access control
├── account_map.json # Optional: Complete account inventory from NTC Account Factory
├── mgmt-organizations/
│ └── parameters.json # Organization metadata (org_id, ou_ids, etc.)
├── connectivity/
│ └── parameters.json # Network resources (TGW, VPC CIDRs, etc.)
├── security-tooling/
│ └── parameters.json # Security configurations (Security Hub, GuardDuty)
└── log-archive/
└── parameters.json # Logging infrastructure (S3 buckets, KMS keys)

Key Components:

  • nodeowners.json: Contains the mapping of which AWS account owns each parameter node and controls write access
  • account_map.json: Optional file automatically created by NTC Account Factory containing complete account inventory with metadata
  • Node Folders: Each parameter node has its own folder named after the node (e.g., log-archive/, connectivity/)
  • parameters.json: Contains the actual parameter data as nested JSON objects within each node folder

This structure provides clear separation between:

  1. Ownership metadata (who can write to which node)
  2. Global account inventory (shared account information)
  3. Domain-specific parameters (organized by functional area)

Integration with NTC Account Factory

NTC Parameters seamlessly integrates with the NTC Account Factory to provide automatic account inventory sharing:

Account Map Generation

The Account Factory automatically publishes account information and baseline configuration data, but NOT the individual account details shown in the previous example. The actual Account Factory implementation focuses on account groupings and baseline roles:

# In the management account with Account Factory
locals {
ntc_parameters_writer_node = "mgmt-account-factory"

# Parameters to store in the ntc-parameters bucket
ntc_parameters_to_write = {
"core_accounts" = local.account_factory_core_account_ids
"workload_accounts" = local.account_factory_workloads_account_ids
"baseline_role_arns" = module.ntc_account_factory.account_factory_baseline_iam_role_arns
}

# Store and share account map from account factory
ntc_account_map = {
for account in local.account_factory_list_enriched : account.account_id => account
}
}

module "ntc_parameters_writer" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters?ref=X.X.X"

bucket_name = local.ntc_parameters_bucket_name
parameter_node = local.ntc_parameters_writer_node
node_parameters = local.ntc_parameters_to_write
replace_parameters = true
store_account_map = true
account_map = local.ntc_account_map
}

This creates:

  1. Node parameters (s3://bucket/mgmt-account-factory/parameters.json) containing:

    • core_accounts: Account IDs for core infrastructure accounts
    • workload_accounts: Account IDs for workload accounts
    • baseline_role_arns: IAM role ARNs created by the Account Factory for baseline access
  2. Account map (s3://bucket/account_map.json) containing the complete account inventory generated by Account Factory

Consumer Usage

Any account in the organization can access parameters and account map:

# In any consumer account
module "ntc_parameters_reader" {
source = "github.com/nuvibit-terraform-collection/terraform-aws-ntc-parameters//modules/reader?ref=X.X.X"

bucket_name = "myorg-ntc-parameters"
}

locals {
# Access Account Factory parameters
core_accounts = module.ntc_parameters_reader.all_parameters["mgmt-account-factory"].core_accounts
workload_accounts = module.ntc_parameters_reader.all_parameters["mgmt-account-factory"].workload_accounts
baseline_role_arns = module.ntc_parameters_reader.all_parameters["mgmt-account-factory"].baseline_role_arns

# Access the complete account map (if available)
all_accounts_map = module.ntc_parameters_reader.account_map
}

Conclusion

NTC Parameters provides a robust, scalable solution for cross-account parameter sharing in AWS multi-account environments. By leveraging S3's proven access control mechanisms and native JSON support, it eliminates the complexity of traditional parameter sharing approaches while providing enhanced functionality for complex organizational deployments.

Key advantages include:

  • Simplified access management through S3 bucket policies
  • Native JSON support for complex data structures
  • Seamless Account Factory integration for automatic account inventory sharing
  • Organization-wide read access with granular write permissions
  • No additional IAM role assumptions required

Whether you're implementing a new multi-account architecture or migrating from existing parameter management solutions, NTC Parameters provides the foundation for reliable, secure, and maintainable configuration sharing across your AWS organization.