Files
aws-production/production_stack.py
2025-06-27 16:06:02 +00:00

349 lines
13 KiB
Python

"""
Production Stack with Native American tribes and deities naming convention
"""
import aws_cdk as cdk
from aws_cdk import (
Stack,
aws_ec2 as ec2,
aws_s3 as s3,
aws_iam as iam,
aws_secretsmanager as secretsmanager,
CfnOutput,
RemovalPolicy,
Tags,
Fn
)
from constructs import Construct
class ProductionStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Common tags for all resources
production_tags = {
"Environment": "Production",
"Project": "CDK-Demo",
"Owner": "DevOps-Team",
"CostCenter": "Engineering"
}
# Apply tags to the entire stack
for key, value in production_tags.items():
Tags.of(self).add(key, value)
# Create networking resources
self.create_networking()
# Create security groups
self.create_security_groups()
# Create compute resources
self.create_compute_resources()
# Create storage resources
self.create_storage_resources()
# Create IAM resources
self.create_iam_resources()
# Create outputs
self.create_outputs()
def create_networking(self):
"""Create VPC and networking components - Cherokee Nation theme"""
# VPC - Cherokee (one of the largest tribes)
self.vpc = ec2.Vpc(
self, "CherokeeVPC",
vpc_name="Cherokee-Production-VPC",
ip_protocol=ec2.IpProtocol.IPV4_ONLY,
max_azs=2,
ip_addresses=ec2.IpAddresses.cidr("10.0.0.0/16"),
subnet_configuration=[
ec2.SubnetConfiguration(
name="Sequoyah-Public-Subnet", # Sequoyah - Cherokee scholar who created Cherokee syllabary
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24
)
],
enable_dns_hostnames=True,
enable_dns_support=True
)
# Internet Gateway is automatically created by CDK with VPC
def create_security_groups(self):
"""Create security groups - Apache Nation theme"""
# Security Group - Apache (known for their warrior culture)
self.web_security_group = ec2.SecurityGroup(
self, "ApacheSecurityGroup",
vpc=self.vpc,
security_group_name="Apache-Web-SecurityGroup",
description="Apache Security Group for web servers - allows SSH and HTTP",
allow_all_outbound=True
)
# Allow SSH from anywhere (port 22)
self.web_security_group.add_ingress_rule(
peer=ec2.Peer.any_ipv4(),
connection=ec2.Port.tcp(22),
description="SSH access from anywhere"
)
# Allow HTTP from anywhere (port 80)
self.web_security_group.add_ingress_rule(
peer=ec2.Peer.any_ipv4(),
connection=ec2.Port.tcp(80),
description="HTTP access from anywhere"
)
def create_compute_resources(self):
"""Create EC2 instances - Sioux Nation theme"""
# User data script to install and start NGINX
nginx_user_data = ec2.UserData.for_linux()
nginx_user_data.add_commands(
"#!/bin/bash",
"yum update -y",
"amazon-linux-extras install nginx1 -y",
"systemctl start nginx",
"systemctl enable nginx",
# Create custom index page with server info
"echo '<h1>Wakan Tanka Server</h1>' > /var/www/html/index.html",
"echo '<p>Server: '$(hostname)'</p>' >> /var/www/html/index.html",
"echo '<p>Great Spirit blesses this server</p>' >> /var/www/html/index.html",
"systemctl restart nginx"
)
# Get the latest Amazon Linux 2 AMI
amzn_linux = ec2.MachineImage.latest_amazon_linux2(
edition=ec2.AmazonLinuxEdition.STANDARD,
virtualization=ec2.AmazonLinuxVirt.HVM,
storage=ec2.AmazonLinuxStorage.GENERAL_PURPOSE
)
# EC2 Instance 1 - Sitting Bull (famous Lakota leader)
self.instance_sitting_bull = ec2.Instance(
self, "SittingBullInstance",
instance_name="SittingBull-WebServer",
instance_type=ec2.InstanceType.of(
ec2.InstanceClass.T2,
ec2.InstanceSize.MICRO
),
machine_image=amzn_linux,
vpc=self.vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC
),
security_group=self.web_security_group,
key_pair=ec2.KeyPair.from_key_pair_name(self, "SittingBullKeyPair", "my-cdk-keypair"),
user_data=nginx_user_data,
associate_public_ip_address=True
)
# EC2 Instance 2 - Crazy Horse (famous Oglala Lakota war leader)
nginx_user_data_2 = ec2.UserData.for_linux()
nginx_user_data_2.add_commands(
"#!/bin/bash",
"yum update -y",
"amazon-linux-extras install nginx1 -y",
"systemctl start nginx",
"systemctl enable nginx",
# Create custom index page with server info
"echo '<h1>Crazy Horse Server</h1>' > /var/www/html/index.html",
"echo '<p>Server: '$(hostname)'</p>' >> /var/www/html/index.html",
"echo '<p>Thunder Being protects this server</p>' >> /var/www/html/index.html",
"systemctl restart nginx"
)
self.instance_crazy_horse = ec2.Instance(
self, "CrazyHorseInstance",
instance_name="CrazyHorse-WebServer",
instance_type=ec2.InstanceType.of(
ec2.InstanceClass.T2,
ec2.InstanceSize.MICRO
),
machine_image=amzn_linux,
vpc=self.vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC
),
security_group=self.web_security_group,
key_pair=ec2.KeyPair.from_key_pair_name(self, "CrazyHorseKeyPair", "my-cdk-keypair"),
user_data=nginx_user_data_2,
associate_public_ip_address=True
)
def create_storage_resources(self):
"""Create S3 bucket - Cherokee storage theme"""
# S3 Bucket - Cherokee naming as requested
self.s3_bucket = s3.Bucket(
self, "CherokeeStorageBucket",
bucket_name="cherokee-storage-bucket-aws-20250627",
versioned=True,
removal_policy=RemovalPolicy.DESTROY, # For demo purposes
auto_delete_objects=True, # For demo cleanup
public_read_access=False,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED
)
def create_iam_resources(self):
"""Create IAM users and groups with Secrets Manager integration - Native American deities theme"""
# IAM Group with ReadOnly access - Kokopelli (Hopi fertility deity)
self.readonly_group = iam.Group(
self, "KokopelliReadOnlyGroup",
group_name="Kokopelli-ReadOnlyAccess-Group"
)
# Attach AWS managed ReadOnlyAccess policy
self.readonly_group.add_managed_policy(
iam.ManagedPolicy.from_aws_managed_policy_name("ReadOnlyAccess")
)
# Create 5 IAM users with Native American deity names
self.iam_users = []
self.user_secrets = []
user_names = [
"Quetzalcoatl", # Aztec feathered serpent deity
"Wendigo", # Algonquian cannibalistic spirit
"Thunderbird", # Powerful supernatural bird in many tribes
"Coyote", # Trickster deity in many Western tribes
"Raven" # Creator deity in Pacific Northwest tribes
]
for user_name in user_names:
# Create a secret in Secrets Manager for each user's password
user_secret = secretsmanager.Secret(
self, f"{user_name}Secret",
secret_name=f"iam-user-password/{user_name.lower()}-production-user",
description=f"Password for IAM user {user_name}-Production-User",
generate_secret_string=secretsmanager.SecretStringGenerator(
secret_string_template='{"username":"' + f"{user_name}-Production-User" + '"}',
generate_string_key="password",
exclude_characters=' "\\\'@/\\',
include_space=False,
password_length=16,
require_each_included_type=True
),
removal_policy=RemovalPolicy.DESTROY # For demo cleanup
)
# Create user with password from Secrets Manager
user = iam.User(
self, f"{user_name}User",
user_name=f"{user_name}-Production-User",
password=user_secret.secret_value_from_json("password")
)
# Add user to ReadOnly group
user.add_to_group(self.readonly_group)
# Enable console access and password management
user.add_managed_policy(
iam.ManagedPolicy.from_aws_managed_policy_name("IAMUserChangePassword")
)
# Grant the user permission to read their own secret (for password retrieval if needed)
user_secret.grant_read(user)
self.iam_users.append(user)
self.user_secrets.append(user_secret)
def create_outputs(self):
"""Create CloudFormation outputs"""
# EC2 Instance Public IPs
CfnOutput(
self, "SittingBullPublicIP",
value=self.instance_sitting_bull.instance_public_ip,
description="Public IP address of Sitting Bull web server"
)
CfnOutput(
self, "CrazyHorsePublicIP",
value=self.instance_crazy_horse.instance_public_ip,
description="Public IP address of Crazy Horse web server"
)
# S3 Bucket Name
CfnOutput(
self, "CherokeeS3BucketName",
value=self.s3_bucket.bucket_name,
description="Name of the Cherokee storage S3 bucket"
)
# IAM User Information with Secrets Manager integration
user_names = [
"Quetzalcoatl", # Aztec feathered serpent deity
"Wendigo", # Algonquian cannibalistic spirit
"Thunderbird", # Powerful supernatural bird in many tribes
"Coyote", # Trickster deity in many Western tribes
"Raven" # Creator deity in Pacific Northwest tribes
]
for i, user in enumerate(self.iam_users):
CfnOutput(
self, f"IAMUser{i+1}Name",
value=user.user_name,
description=f"IAM username for {user_names[i]} production user"
)
# Secrets Manager Information
for i, secret in enumerate(self.user_secrets):
CfnOutput(
self, f"User{i+1}SecretArn",
value=secret.secret_arn,
description=f"Secrets Manager ARN for {user_names[i]} user password"
)
# Instructions for retrieving passwords
CfnOutput(
self, "PasswordRetrievalInstructions",
value="Use AWS CLI: aws secretsmanager get-secret-value --secret-id <secret-arn> --query SecretString --output text",
description="Command template for retrieving IAM user passwords from Secrets Manager"
)
CfnOutput(
self, "SecretsManagerConsoleURL",
value="https://console.aws.amazon.com/secretsmanager/",
description="AWS Secrets Manager Console URL to view and manage user passwords"
)
# Web URLs for easy access - Fixed using Fn.sub for proper token handling
CfnOutput(
self, "SittingBullWebURL",
value=Fn.sub("http://${PublicIP}", {
"PublicIP": self.instance_sitting_bull.instance_public_ip
}),
description="Web URL for Sitting Bull server"
)
CfnOutput(
self, "CrazyHorseWebURL",
value=Fn.sub("http://${PublicIP}", {
"PublicIP": self.instance_crazy_horse.instance_public_ip
}),
description="Web URL for Crazy Horse server"
)
# VPC Information
CfnOutput(
self, "CherokeeVPCId",
value=self.vpc.vpc_id,
description="Cherokee VPC ID"
)
# Security Group Information
CfnOutput(
self, "ApacheSecurityGroupId",
value=self.web_security_group.security_group_id,
description="Apache Security Group ID"
)