Skip to main content

Overview

The global AWS resources module provisions foundational infrastructure components that are shared across all environments (if multiple enviornments in one account) (development, staging, production). These resources are created once per account and referenced by environment-specific modules, ensuring consistency, security, and centralized management.

Why Global Resources?

Global resources provide:
  • Centralized Security: Single KMS key and IAM roles for encryption and access control
  • Audit Compliance: Unified CloudTrail logging for all API activity
  • Resource Reusability: IAM roles and policies shared across multiple modules
  • Consistency: Standardized configuration across all environments
  • Simplified Management: Update policies and permissions in one place

Core Components

1. KMS Encryption Key

A customer-managed KMS key that encrypts data at rest for all Artos resources, including EKS secrets, RDS databases, S3 buckets, CloudTrail logs, and Secrets Manager entries.

Key Features

FeatureConfigurationPurpose
Automatic Key RotationEnabled (annual)Rotates encryption keys automatically for enhanced security
Deletion Protection7-day windowPrevents accidental deletion with a recovery period
Multi-Service AccessEKS, RDS, S3, CloudTrail, Secrets ManagerSingle key for all encryption needs
Key Aliasalias/{project}-{environment}-kms-keyHuman-readable identifier for the key

Service Permissions

The KMS key policy grants encryption/decryption permissions to multiple AWS services:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT_ID:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "Allow EKS Service",
      "Effect": "Allow",
      "Principal": {
        "Service": "eks.amazonaws.com"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow RDS Service",
      "Effect": "Allow",
      "Principal": {
        "Service": "rds.amazonaws.com"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    }
    // Additional statements for S3, CloudTrail, Secrets Manager
  ]
}
What This Means: The KMS key can be used by AWS services on your behalf to encrypt/decrypt data without requiring manual intervention. The root account retains full administrative access to manage the key.

2. IAM Roles for EKS

The module creates three primary IAM roles for different EKS compute types, each with specific permissions for their function.

EKS Cluster Service Role

Purpose: Allows the EKS control plane to manage AWS resources on your behalf.
PropertyValue
Role Name{project}-{environment}-eks-service-role
Trust Policyeks.amazonaws.com
Managed PolicyAmazonEKSClusterPolicy
What It Does:
  • Creates and manages Elastic Network Interfaces (ENIs) in your VPC
  • Manages security groups for cluster-VPC communication
  • Creates CloudWatch log streams for cluster logging
  • Describes EC2 resources to validate cluster configuration

EKS Node Group Role

Purpose: Grants EC2 worker nodes permissions to join the cluster, pull container images, and access AWS services.
PropertyValue
Role Name{project}-{environment}-eks-node-group-role
Trust Policyec2.amazonaws.com
Managed PoliciesAmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryReadOnly, AmazonSSMManagedInstanceCore
Additional Permissions:
  1. Cross-Account ECR Access: Pull container images from the Artos-managed ECR registry
  2. SSM Session Manager: Secure shell access to nodes without SSH keys
Cross-Account ECR Policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:DescribeRepositories",
        "ecr:DescribeImages"
      ],
      "Resource": [
        "arn:aws:ecr:*:<artos_ecr_aws_account>:repository/development/*",
        "arn:aws:ecr:*:<artos_ecr_aws_account>:repository/thirdparty/*"
      ]
    }
  ]
}
Why This Matters: Nodes can pull pre-built Artos container images from the centralized ECR registry without requiring image copies or manual transfers.

EKS Fargate Role

Purpose: Allows Fargate profiles to execute pods and pull container images.
PropertyValue
Role Name{project}-{environment}-eks-fargate-role
Trust Policyeks-fargate-pods.amazonaws.com
Managed PolicyAmazonEKSFargatePodExecutionRolePolicy
Additional Permissions:
  • Cross-Account ECR Access: Same as node group role for image pulling
Fargate vs. Node Groups: Fargate pods run on AWS-managed infrastructure (serverless), while node groups run on customer-managed EC2 instances. The Fargate role is only used when Fargate profiles are configured.

RDS Enhanced Monitoring Role

Purpose: Allows RDS to publish detailed monitoring metrics to CloudWatch.
PropertyValue
Role Name{project}-{environment}-rds-enhanced-monitoring-role
Trust Policymonitoring.rds.amazonaws.com
Managed PolicyAmazonRDSEnhancedMonitoringRole
What It Does: Enables RDS instances to send OS-level metrics (CPU, memory, disk I/O, network) to CloudWatch at 1-60 second intervals for detailed performance analysis.

3. CloudTrail Audit Logging

AWS CloudTrail records all API calls made in your AWS account, providing a complete audit trail for security analysis, compliance, and troubleshooting.

CloudTrail Configuration

SettingValuePurpose
Multi-Region TrailEnabledCaptures API calls from all AWS regions
Global Service EventsEnabledLogs IAM, STS, CloudFront events
Event SelectorAll management events + S3 data eventsRecords resource creation/modification
EncryptionKMS (using global KMS key)Encrypts log files at rest
Log StorageS3 bucket with versioningImmutable audit log

What CloudTrail Captures

Management Events (who did what):
  • EKS cluster creation/modification
  • RDS database parameter changes
  • IAM role assumption
  • Security group rule changes
  • S3 bucket policy updates
Data Events (data access):
  • S3 object uploads/downloads to CloudTrail bucket
  • API calls to Artos services

CloudTrail S3 Bucket

The module creates a dedicated S3 bucket for storing CloudTrail logs:
FeatureConfiguration
Bucket Name{project}-{environment}-cloudtrail-logs-{random}
VersioningEnabled
EncryptionKMS (using global KMS key)
Force DestroyDisabled (logs are retained even if Terraform is destroyed)
Bucket PolicyAllows CloudTrail service to write logs
Bucket Policy Example:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::bucket-name"
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::bucket-name/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}
Why This Policy: The AWSCloudTrailAclCheck statement allows CloudTrail to verify bucket permissions, while AWSCloudTrailWrite permits log file uploads with the bucket-owner-full-control ACL to ensure you maintain ownership of log files.

Module Configuration

Basic Configuration

# terraform.tfvars
project_name            = "genai-artos"
environment             = "production"
aws_region              = "us-east-1"
terraform_state_bucket  = "artos-terraform-state"

tags = {
  system_owner = "[email protected]"
  system_admin = "[email protected]"
  created_by   = "Terraform"
  cost_center  = "engineering"
  application  = "artos-backend"
}

Backend Configuration

The module uses S3 backend for Terraform state storage. Create a backend configuration file for each environment: File: backend-global-production-us-east-1.hcl
# Backend configuration for production environment in us-east-1
# Usage: terraform init -backend-config=backend-global-production-us-east-1.hcl

bucket = "artos-terraform-state"
key    = "global/production/us-east-1/terraform.tfstate"
region = "us-east-1"

Initialization and Deployment

# Initialize Terraform with backend configuration
terraform init -backend-config=backend-global-production-us-east-1.hcl

# Review planned changes
terraform plan

# Apply global resources
terraform apply

# View outputs (KMS key ARN, IAM role ARNs, CloudTrail ARN)
terraform output

Using Global Resources in Environment Modules

Global resources are referenced by environment-specific modules (networking, EKS, RDS, S3) using Terraform data sources or outputs from remote state.

Example: Referencing KMS Key in RDS Module

# Environment module references global KMS key
data "terraform_remote_state" "global" {
  backend = "s3"
  config = {
    bucket = "artos-terraform-state"
    key    = "global/production/us-east-1/terraform.tfstate"
    region = "us-east-1"
  }
}

# Use KMS key in RDS cluster
resource "aws_rds_cluster" "main" {
  cluster_identifier      = "artos-production"
  engine                  = "aurora-postgresql"
  storage_encrypted       = true
  kms_key_id             = data.terraform_remote_state.global.outputs.kms_key_arn
  # ... other configuration
}

Example: Referencing IAM Roles in EKS Module

# Reference global IAM roles
resource "aws_eks_cluster" "main" {
  name     = "artos-production"
  role_arn = data.terraform_remote_state.global.outputs.eks_service_role_arn
  # ... other configuration
}

resource "aws_eks_node_group" "main" {
  cluster_name    = aws_eks_cluster.main.name
  node_role_arn   = data.terraform_remote_state.global.outputs.eks_node_group_role_arn
  # ... other configuration
}

resource "aws_eks_fargate_profile" "main" {
  cluster_name           = aws_eks_cluster.main.name
  fargate_profile_name   = "artos-fargate"
  pod_execution_role_arn = data.terraform_remote_state.global.outputs.eks_fargate_role_arn
  # ... other configuration
}

Module Outputs

The global resources module exports the following outputs for use by other modules:
Output NameDescriptionExample Value
kms_key_idKMS key ID12345678-1234-1234-1234-123456789012
kms_key_arnKMS key ARNarn:aws:kms:us-east-1:123456789012:key/12345678-...
eks_service_role_arnEKS cluster service role ARNarn:aws:iam::123456789012:role/artos-prod-eks-service-role
eks_node_group_role_arnEKS node group role ARNarn:aws:iam::123456789012:role/artos-prod-eks-node-group-role
eks_fargate_role_arnEKS Fargate role ARNarn:aws:iam::123456789012:role/artos-prod-eks-fargate-role
rds_enhanced_monitoring_role_arnRDS monitoring role ARNarn:aws:iam::123456789012:role/artos-prod-rds-enhanced-monitoring-role
cloudtrail_arnCloudTrail ARNarn:aws:cloudtrail:us-east-1:123456789012:trail/artos-prod-cloudtrail

Security Best Practices

1. KMS Key Management

Key Rotation:
  • Automatic key rotation is enabled by default (annual rotation)
  • Rotation is transparent to applications (AWS handles re-encryption)
  • Historical key material is retained for decrypting old data
Access Control:
  • Only the root account has full administrative access
  • Service principals have minimal required permissions (encrypt/decrypt only)
  • Consider creating separate KMS keys for highly sensitive data

2. IAM Role Security

Principle of Least Privilege:
  • Each role has only the permissions required for its specific function
  • Cross-account ECR access is limited to specific repositories
  • SSM Session Manager replaces SSH for secure node access
Trust Policies:
  • Trust policies restrict role assumption to specific AWS services
  • No direct user access to service roles (principle of least privilege)
Monitoring:
  • All role assumptions are logged in CloudTrail
  • Set up CloudWatch alarms for unexpected role usage

3. CloudTrail Audit Logging

Log Integrity:
  • Versioning enabled on log bucket prevents accidental deletion
  • KMS encryption protects log confidentiality
  • S3 Object Lock (optional) provides immutable audit logs
Access Control:
  • CloudTrail bucket policy restricts write access to CloudTrail service only
  • Separate IAM policy required to read logs (not granted by default)
  • Consider enabling S3 Access Logging for the CloudTrail bucket
Alerting:
# Example: CloudWatch alarm for CloudTrail logging disabled
resource "aws_cloudwatch_metric_alarm" "cloudtrail_disabled" {
  alarm_name          = "cloudtrail-logging-disabled"
  comparison_operator = "LessThanThreshold"
  evaluation_periods  = "1"
  metric_name         = "IsLogging"
  namespace           = "CloudTrailMetrics"
  period              = "300"
  statistic           = "Average"
  threshold           = "1"
  alarm_description   = "CloudTrail logging has been disabled"
  alarm_actions       = [aws_sns_topic.alerts.arn]
}

Operational Considerations

Cross-Account ECR Access

The global IAM roles include policies for pulling images from the Artos-managed ECR registry. This enables: Centralized Image Management:
  • Artos team maintains pre-built, tested container images
  • Automatic security patching and updates
  • Version-controlled image releases
Required Configuration:
  1. On Artos Side: ECR repository policies must allow your AWS account to pull images
  2. On Customer Side: IAM roles (created by this module) grant nodes permission to pull images. These updates can also be added to each ECR repository.

Terraform State Management

Backend Configuration:
  • Global resources use S3 backend for state storage
  • State file contains sensitive data (ARNs, resource IDs)
  • Enable S3 versioning and encryption on state bucket
  • The environment specific state files will be different for than the global tfstate files for each environment.
State Locking:
# Add DynamoDB table for state locking
terraform {
  backend "s3" {
    bucket         = "artos-terraform-state"
    key            = "global/production/us-east-1/global.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

Resource Dependencies

Deployment Order:
  1. First: Deploy global resources module
  2. Second: Deploy networking module (VPC, subnets, security groups)
  3. Third: Deploy environment-specific modules (EKS, RDS, S3, etc.)
Why This Order: Environment modules reference global resource outputs (KMS key ARN, IAM role ARNs) via remote state, so global resources must exist first.

Troubleshooting

Issue: KMS Key Access Denied

Symptom: Services (EKS, RDS) cannot encrypt/decrypt data using KMS key. Solution:
# Verify KMS key policy includes service principal
aws kms get-key-policy --key-id <KEY_ID> --policy-name default

# Check CloudTrail for denied KMS API calls
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=Decrypt \
  --max-results 10

Issue: Cross-Account ECR Pull Failures

Symptom: EKS pods cannot pull images from Artos ECR registry. Solution:
# Verify IAM role policy is attached to node group role
aws iam list-attached-role-policies --role-name <NODE_GROUP_ROLE_NAME>
aws iam get-role-policy --role-name <NODE_GROUP_ROLE_NAME> --policy-name cross-account-ecr

# Test ECR authentication from node
kubectl run test-pod --image=<artos_ecr_aws_account>.dkr.ecr.us-east-1.amazonaws.com/development/test:latest
kubectl describe pod test-pod  # Check for ImagePullBackOff errors
Common Causes:
  1. ECR repository policy does not allow your AWS account
  2. IAM role policy has incorrect repository ARNs
  3. Node instance profile not associated with IAM role
The global resources module is referenced by:
  • Networking Module: Uses KMS key for VPC Flow Logs encryption
  • EKS Module: Uses IAM roles for cluster, nodes, and Fargate
  • RDS Module: Uses KMS key for database encryption and enhanced monitoring role
  • S3 Module: Uses KMS key for bucket encryption
  • IAM Module: References service roles for IRSA configuration