Skip to content

Commit 785d07f

Browse files
authored
Add account verification for Atmos auth in Terraform (#14)
This file implements account verification for Atmos auth identity selection in Terraform, ensuring the selected identity operates in the correct AWS account. It includes logic to compare the current AWS account ID with the expected account ID based on tenant-stage context.
1 parent 5e62647 commit 785d07f

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

src/mixins/provider-atmos-auth.tf

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Account Verification for Atmos Auth Identity Selection
2+
#
3+
# Purpose:
4+
# We use Atmos auth to select an identity (AWS IAM role/user) to run Terraform. This file ensures
5+
# that the selected identity is operating in the correct AWS account that we intend to target.
6+
#
7+
# How it works:
8+
# 1. Gets the current AWS account ID from the identity selected via Atmos auth
9+
# 2. Compares it against the expected account ID derived from the context (tenant-stage)
10+
# 3. Uses the account_map variable to look up the expected account ID based on the tenant-stage
11+
# naming convention (format: "tenant-stage")
12+
# 4. If verification is enabled and the accounts don't match, Terraform will fail with a clear error
13+
#
14+
# This verification process ensures that when using Atmos auth to select an identity, we're
15+
# targeting the correct account as determined by the component's context variables.
16+
17+
# Get current AWS account ID for verification
18+
data "aws_caller_identity" "account_verification" {}
19+
20+
# Optional account map for account verification
21+
# If provided, will verify that the current AWS account matches the expected account
22+
# based on tenant-stage naming convention (format: "tenant-stage")
23+
# Note: If this variable is already defined in variables.tf, Terraform will use that definition
24+
variable "account_map" {
25+
type = object({
26+
full_account_map = map(string)
27+
audit_account_account_name = optional(string, "")
28+
root_account_account_name = optional(string, "")
29+
})
30+
description = "Map of account names (tenant-stage format) to account IDs. Used to verify we're targeting the correct AWS account. Optional attributes support component-specific functionality (e.g., audit_account_account_name for cloudtrail, root_account_account_name for aws-sso)."
31+
default = {
32+
full_account_map = {}
33+
audit_account_account_name = ""
34+
root_account_account_name = ""
35+
}
36+
}
37+
38+
# Compute expected account name from tenant and stage
39+
locals {
40+
# Construct expected account name in format "tenant-stage"
41+
# Only construct if both tenant and stage are non-null and non-empty
42+
expected_account_name = (
43+
try(var.tenant, null) != null &&
44+
try(var.stage, null) != null &&
45+
try(var.tenant, "") != "" &&
46+
try(var.stage, "") != ""
47+
) ? "${var.tenant}-${var.stage}" : null
48+
49+
# Get expected account ID from account_map if account_map is provided and account name can be constructed
50+
expected_account_id = try(
51+
local.expected_account_name != null ? var.account_map.full_account_map[local.expected_account_name] : null,
52+
null
53+
)
54+
55+
# Current account ID
56+
current_account_id = data.aws_caller_identity.account_verification.account_id
57+
58+
# Only validate if:
59+
# 1. account_map is provided (not empty)
60+
# 2. Expected account name can be constructed from tenant-stage
61+
# 3. Expected account ID exists in the account_map
62+
should_validate = (
63+
length(var.account_map.full_account_map) > 0 &&
64+
local.expected_account_name != null &&
65+
local.expected_account_id != null
66+
)
67+
68+
# Validation error message
69+
# Must always be a string (never null) for use in precondition error_message
70+
validation_error = local.should_validate && local.current_account_id != local.expected_account_id ? (
71+
"Account verification failed: Expected account ID ${local.expected_account_id} for account '${local.expected_account_name}' (tenant: ${var.tenant}, stage: ${var.stage}), but current account ID is ${local.current_account_id}"
72+
) : "Account verification check passed"
73+
}
74+
75+
# Validate account matches expected account when account_map is provided
76+
# Using terraform_data (available in Terraform 1.4+) for validation
77+
# For Terraform < 1.4, this will still work but validation happens at plan time
78+
resource "terraform_data" "account_verification" {
79+
count = local.should_validate ? 1 : 0
80+
81+
lifecycle {
82+
precondition {
83+
condition = local.current_account_id == local.expected_account_id
84+
error_message = local.validation_error
85+
}
86+
}
87+
}
88+
89+
provider "aws" {
90+
region = var.region
91+
}

0 commit comments

Comments
 (0)