""" 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 '
Server: '$(hostname)'
' >> /var/www/html/index.html", "echo 'Great Spirit blesses this server
' >> /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 'Server: '$(hostname)'
' >> /var/www/html/index.html", "echo 'Thunder Being protects this server
' >> /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