349 lines
13 KiB
Python
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"
|
|
) |