name: vpc-network
description: Complete VPC setup with public/private subnets, NAT Gateway, and security groups
version: 1.0.0
author: CFN-Forge
cfnForgeVersion: 1.0.0

variables:
  projectName:
    prompt: "Project name"
    default: "my-vpc-network"
  description:
    prompt: "Project description" 
    default: "VPC network infrastructure for AWS applications"
  vpcCidr:
    prompt: "VPC CIDR block"
    default: "10.0.0.0/16"
  enableNatGateway:
    prompt: "Enable NAT Gateway for private subnets?"
    default: "true"
    type: "boolean"
  multiAz:
    prompt: "Deploy across multiple Availability Zones?"
    default: "true"
    type: "boolean"

files:
  include:
    - "**/*"
  exclude:
    - "template.yaml"
    - ".git/**"

structure:
  cloudformation.yaml: |
    AWSTemplateFormatVersion: '2010-09-09'
    Description: {{description}}

    Parameters:
      Environment:
        Type: String
        Default: dev
        AllowedValues: [dev, staging, prod]
        Description: Environment name

    Conditions:
      EnableNatGateway: !Equals ["{{enableNatGateway}}", "true"]
      MultiAZ: !Equals ["{{multiAz}}", "true"]
      CreateSecondAZ: !And [!Condition MultiAZ, !Not [!Equals [!Select [1, !GetAZs ""], ""]]]

    Resources:
      # VPC
      VPC:
        Type: AWS::EC2::VPC
        Properties:
          CidrBlock: {{vpcCidr}}
          EnableDnsHostnames: true
          EnableDnsSupport: true
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-vpc"
            - Key: Environment
              Value: !Ref Environment

      # Internet Gateway
      InternetGateway:
        Type: AWS::EC2::InternetGateway
        Properties:
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-igw"

      InternetGatewayAttachment:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
          InternetGatewayId: !Ref InternetGateway
          VpcId: !Ref VPC

      # Public Subnets
      PublicSubnet1:
        Type: AWS::EC2::Subnet
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [0, !GetAZs ""]
          CidrBlock: !Select [0, !Cidr [{{vpcCidr}}, 6, 8]]
          MapPublicIpOnLaunch: true
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-public-subnet-1"
            - Key: Type
              Value: Public

      PublicSubnet2:
        Type: AWS::EC2::Subnet
        Condition: CreateSecondAZ
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [1, !GetAZs ""]
          CidrBlock: !Select [1, !Cidr [{{vpcCidr}}, 6, 8]]
          MapPublicIpOnLaunch: true
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-public-subnet-2"
            - Key: Type
              Value: Public

      # Private Subnets
      PrivateSubnet1:
        Type: AWS::EC2::Subnet
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [0, !GetAZs ""]
          CidrBlock: !Select [2, !Cidr [{{vpcCidr}}, 6, 8]]
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-private-subnet-1"
            - Key: Type
              Value: Private

      PrivateSubnet2:
        Type: AWS::EC2::Subnet
        Condition: CreateSecondAZ
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [1, !GetAZs ""]
          CidrBlock: !Select [3, !Cidr [{{vpcCidr}}, 6, 8]]
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-private-subnet-2"
            - Key: Type
              Value: Private

      # Database Subnets
      DatabaseSubnet1:
        Type: AWS::EC2::Subnet
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [0, !GetAZs ""]
          CidrBlock: !Select [4, !Cidr [{{vpcCidr}}, 6, 8]]
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-database-subnet-1"
            - Key: Type
              Value: Database

      DatabaseSubnet2:
        Type: AWS::EC2::Subnet
        Condition: CreateSecondAZ
        Properties:
          VpcId: !Ref VPC
          AvailabilityZone: !Select [1, !GetAZs ""]
          CidrBlock: !Select [5, !Cidr [{{vpcCidr}}, 6, 8]]
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-database-subnet-2"
            - Key: Type
              Value: Database

      # NAT Gateway
      NatGateway1EIP:
        Type: AWS::EC2::EIP
        Condition: EnableNatGateway
        DependsOn: InternetGatewayAttachment
        Properties:
          Domain: vpc
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-nat-eip-1"

      NatGateway2EIP:
        Type: AWS::EC2::EIP
        Condition: !And [EnableNatGateway, CreateSecondAZ]
        DependsOn: InternetGatewayAttachment
        Properties:
          Domain: vpc
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-nat-eip-2"

      NatGateway1:
        Type: AWS::EC2::NatGateway
        Condition: EnableNatGateway
        Properties:
          AllocationId: !GetAtt NatGateway1EIP.AllocationId
          SubnetId: !Ref PublicSubnet1
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-nat-1"

      NatGateway2:
        Type: AWS::EC2::NatGateway
        Condition: !And [EnableNatGateway, CreateSecondAZ]
        Properties:
          AllocationId: !GetAtt NatGateway2EIP.AllocationId
          SubnetId: !Ref PublicSubnet2
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-nat-2"

      # Route Tables
      PublicRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-public-routes"

      DefaultPublicRoute:
        Type: AWS::EC2::Route
        DependsOn: InternetGatewayAttachment
        Properties:
          RouteTableId: !Ref PublicRouteTable
          DestinationCidrBlock: 0.0.0.0/0
          GatewayId: !Ref InternetGateway

      PublicSubnet1RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref PublicRouteTable
          SubnetId: !Ref PublicSubnet1

      PublicSubnet2RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Condition: CreateSecondAZ
        Properties:
          RouteTableId: !Ref PublicRouteTable
          SubnetId: !Ref PublicSubnet2

      PrivateRouteTable1:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-private-routes-1"

      DefaultPrivateRoute1:
        Type: AWS::EC2::Route
        Condition: EnableNatGateway
        Properties:
          RouteTableId: !Ref PrivateRouteTable1
          DestinationCidrBlock: 0.0.0.0/0
          NatGatewayId: !Ref NatGateway1

      PrivateSubnet1RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref PrivateRouteTable1
          SubnetId: !Ref PrivateSubnet1

      PrivateRouteTable2:
        Type: AWS::EC2::RouteTable
        Condition: CreateSecondAZ
        Properties:
          VpcId: !Ref VPC
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-private-routes-2"

      DefaultPrivateRoute2:
        Type: AWS::EC2::Route
        Condition: !And [EnableNatGateway, CreateSecondAZ]
        Properties:
          RouteTableId: !Ref PrivateRouteTable2
          DestinationCidrBlock: 0.0.0.0/0
          NatGatewayId: !Ref NatGateway2

      PrivateSubnet2RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Condition: CreateSecondAZ
        Properties:
          RouteTableId: !Ref PrivateRouteTable2
          SubnetId: !Ref PrivateSubnet2

      # Database Subnet Group
      DatabaseSubnetGroup:
        Type: AWS::RDS::DBSubnetGroup
        Properties:
          DBSubnetGroupDescription: Subnet group for RDS database
          SubnetIds:
            - !Ref DatabaseSubnet1
            - !If [CreateSecondAZ, !Ref DatabaseSubnet2, !Ref DatabaseSubnet1]
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-db-subnet-group"

      # Security Groups
      WebSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupName: !Sub "${AWS::StackName}-web-sg"
          GroupDescription: Security group for web servers
          VpcId: !Ref VPC
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 80
              ToPort: 80
              CidrIp: 0.0.0.0/0
              Description: HTTP
            - IpProtocol: tcp
              FromPort: 443
              ToPort: 443
              CidrIp: 0.0.0.0/0
              Description: HTTPS
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-web-sg"

      ApplicationSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupName: !Sub "${AWS::StackName}-app-sg"
          GroupDescription: Security group for application servers
          VpcId: !Ref VPC
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 8080
              ToPort: 8080
              SourceSecurityGroupId: !Ref WebSecurityGroup
              Description: Application port from web tier
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-app-sg"

      DatabaseSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupName: !Sub "${AWS::StackName}-db-sg"
          GroupDescription: Security group for database servers
          VpcId: !Ref VPC
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 3306
              ToPort: 3306
              SourceSecurityGroupId: !Ref ApplicationSecurityGroup
              Description: MySQL/Aurora from application tier
            - IpProtocol: tcp
              FromPort: 5432
              ToPort: 5432
              SourceSecurityGroupId: !Ref ApplicationSecurityGroup
              Description: PostgreSQL from application tier
          Tags:
            - Key: Name
              Value: !Sub "${AWS::StackName}-db-sg"

    Outputs:
      VPC:
        Description: VPC ID
        Value: !Ref VPC
        Export:
          Name: !Sub "${AWS::StackName}-VPC"

      PublicSubnets:
        Description: Public subnet IDs
        Value: !If
          - CreateSecondAZ
          - !Sub "${PublicSubnet1},${PublicSubnet2}"
          - !Ref PublicSubnet1
        Export:
          Name: !Sub "${AWS::StackName}-PublicSubnets"

      PrivateSubnets:
        Description: Private subnet IDs
        Value: !If
          - CreateSecondAZ
          - !Sub "${PrivateSubnet1},${PrivateSubnet2}"
          - !Ref PrivateSubnet1
        Export:
          Name: !Sub "${AWS::StackName}-PrivateSubnets"

      DatabaseSubnets:
        Description: Database subnet IDs
        Value: !If
          - CreateSecondAZ
          - !Sub "${DatabaseSubnet1},${DatabaseSubnet2}"
          - !Ref DatabaseSubnet1
        Export:
          Name: !Sub "${AWS::StackName}-DatabaseSubnets"

      DatabaseSubnetGroup:
        Description: Database subnet group name
        Value: !Ref DatabaseSubnetGroup
        Export:
          Name: !Sub "${AWS::StackName}-DatabaseSubnetGroup"

      WebSecurityGroup:
        Description: Web security group ID
        Value: !Ref WebSecurityGroup
        Export:
          Name: !Sub "${AWS::StackName}-WebSecurityGroup"

      ApplicationSecurityGroup:
        Description: Application security group ID
        Value: !Ref ApplicationSecurityGroup
        Export:
          Name: !Sub "${AWS::StackName}-ApplicationSecurityGroup"

      DatabaseSecurityGroup:  
        Description: Database security group ID
        Value: !Ref DatabaseSecurityGroup
        Export:
          Name: !Sub "${AWS::StackName}-DatabaseSecurityGroup"

  .cfn-forge.yaml: |
    project:
      name: {{projectName}}
      description: {{description}}
      type: vpc-network

    # Global AWS settings (optional - can be overridden per environment)
    aws:
      profile: default  # Default AWS profile for all environments
      region: us-east-1 # Default region

    environments:
      dev:
        stackName: "{{projectName}}-dev"
        template: cloudformation.yaml
        region: us-east-1
        # aws:
        #   profile: dev-account    # Override profile for dev environment
        #   region: us-east-1       # Override region for dev environment
        parameters:
          Environment: dev
      
      staging:
        stackName: "{{projectName}}-staging"
        template: cloudformation.yaml
        region: us-east-1
        # aws:
        #   profile: staging-account # Override profile for staging
        #   region: us-west-2        # Override region for staging
        parameters:
          Environment: staging
      
      prod:
        stackName: "{{projectName}}-prod"
        template: cloudformation.yaml
        region: us-east-1
        # aws:
        #   profile: prod-account    # Override profile for production
        #   region: us-west-2        # Override region for production
        #   accountId: "123456789012" # Verify account ID for safety
        parameters:
          Environment: prod

    deployment:
      packagingBucket: "{{projectName}}-deployment-artifacts"
      createBucket: true
      git:
        watchBranches: ["main", "develop"]
        deployOnPush: true

  README.md: |
    # {{projectName}}

    {{description}}

    ## Architecture

    This template creates a complete VPC infrastructure with:

    - **VPC**: {{vpcCidr}} CIDR block
    - **Public Subnets**: For load balancers, NAT gateways
    - **Private Subnets**: For application servers, Lambda functions
    - **Database Subnets**: Isolated subnets for RDS databases
    - **Internet Gateway**: Internet access for public subnets
    - **NAT Gateway**: Outbound internet access for private subnets {{#if enableNatGateway}}✅{{else}}❌{{/if}}
    - **Multi-AZ**: High availability across multiple zones {{#if multiAz}}✅{{else}}❌{{/if}}

    ## Quick Start

    1. Deploy the VPC infrastructure:
       ```bash
       cfn-forge deploy
       ```

    2. Verify the deployment:
       ```bash
       cfn-forge validate
       ```

    ## Network Layout

    ```
    {{projectName}} VPC ({{vpcCidr}})
    ├── Public Subnets (Internet Gateway)
    │   ├── Public Subnet 1 (AZ-a)
    │   └── Public Subnet 2 (AZ-b) {{#if multiAz}}✅{{else}}❌{{/if}}
    ├── Private Subnets (NAT Gateway)
    │   ├── Private Subnet 1 (AZ-a)
    │   └── Private Subnet 2 (AZ-b) {{#if multiAz}}✅{{else}}❌{{/if}}
    └── Database Subnets (No Internet)
        ├── Database Subnet 1 (AZ-a)
        └── Database Subnet 2 (AZ-b) {{#if multiAz}}✅{{else}}❌{{/if}}
    ```

    ## Security Groups

    ### Web Security Group
    - **HTTP (80)**: Open to internet (0.0.0.0/0)
    - **HTTPS (443)**: Open to internet (0.0.0.0/0)

    ### Application Security Group  
    - **Port 8080**: Access from Web Security Group only

    ### Database Security Group
    - **MySQL (3306)**: Access from Application Security Group only
    - **PostgreSQL (5432)**: Access from Application Security Group only

    ## Deployment

    ### Environments

    - **dev**: Development environment
    - **staging**: Staging environment  
    - **prod**: Production environment

    ### Commands

    - `cfn-forge deploy` - Deploy VPC infrastructure
    - `cfn-forge deploy --env prod` - Deploy to production
    - `cfn-forge validate` - Validate CloudFormation template

    ## Usage Examples

    ### Launch EC2 Instances

    ```bash
    # Web servers in public subnets
    aws ec2 run-instances \
      --subnet-id $(cfn-forge output PublicSubnets | cut -d',' -f1) \
      --security-group-ids $(cfn-forge output WebSecurityGroup)

    # App servers in private subnets  
    aws ec2 run-instances \
      --subnet-id $(cfn-forge output PrivateSubnets | cut -d',' -f1) \
      --security-group-ids $(cfn-forge output ApplicationSecurityGroup)
    ```

    ### Create RDS Database

    ```bash
    aws rds create-db-instance \
      --db-subnet-group-name $(cfn-forge output DatabaseSubnetGroup) \
      --vpc-security-group-ids $(cfn-forge output DatabaseSecurityGroup) \
      --db-instance-identifier myapp-db \
      --engine mysql
    ```

    ### Deploy Lambda Functions

    ```yaml
    # In your Lambda CloudFormation template
    VpcConfig:
      SubnetIds: 
        - !ImportValue {{projectName}}-dev-PrivateSubnets
      SecurityGroupIds:
        - !ImportValue {{projectName}}-dev-ApplicationSecurityGroup
    ```

    ## Costs

    ### Fixed Costs (24/7)
    {{#if enableNatGateway}}
    - **NAT Gateway**: ~$32-45/month per gateway
    {{#if multiAz}}
    - **Total NAT Gateways**: 2 (~$64-90/month)
    {{else}}
    - **Total NAT Gateways**: 1 (~$32-45/month)
    {{/if}}
    {{else}}
    - **NAT Gateway**: Disabled (no fixed costs)
    {{/if}}

    ### Variable Costs
    - **Data Transfer**: $0.045/GB through NAT Gateway
    - **VPC, Subnets, Route Tables**: Free
    - **Security Groups, NACLs**: Free

    ## Best Practices

    - ✅ Separate tiers into different subnets
    - ✅ Use security groups for fine-grained access control
    - ✅ Deploy across multiple AZs for high availability
    - ✅ Use private subnets for application/database servers
    - ✅ Monitor NAT Gateway costs and data transfer

hooks:
  postInstall:
    - type: message
      content: "VPC network template created! This provides the foundation for your AWS infrastructure."