AWSTemplateFormatVersion: "2010-09-09"
Description: DEEPDIVE Scenario 9 - a deliberately broken network. Find and fix every fault.

Parameters:
  AmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
  InstanceType:
    Type: String
    Default: t3.micro
  InstanceProfileName:
    Type: String
    Default: deepdive-ec2-role

Resources:
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.50.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: broken-vpc

  Igw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: broken-igw

  IgwAttach:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref Igw

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Vpc
      CidrBlock: 10.50.1.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: broken-public

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Vpc
      CidrBlock: 10.50.2.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: broken-private

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: broken-public-rt

  PublicRouteTableAssoc:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  PublicNacl:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: broken-public-nacl

  NaclInHttp:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNacl
      RuleNumber: 100
      Protocol: 6
      RuleAction: allow
      Egress: false
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 80
        To: 80

  NaclInEphemeral:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNacl
      RuleNumber: 110
      Protocol: 6
      RuleAction: allow
      Egress: false
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 1024
        To: 65535

  NaclOutToApp:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNacl
      RuleNumber: 100
      Protocol: 6
      RuleAction: allow
      Egress: true
      CidrBlock: 10.50.0.0/16
      PortRange:
        From: 8080
        To: 8080

  PublicNaclAssoc:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      NetworkAclId: !Ref PublicNacl

  WebSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: web tier
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: broken-web-sg

  AppSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: app tier
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 10.99.0.0/16
      Tags:
        - Key: Name
          Value: broken-app-sg

  AppInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref AmiId
      InstanceType: !Ref InstanceType
      SubnetId: !Ref PrivateSubnet
      SecurityGroupIds: [!Ref AppSg]
      IamInstanceProfile: !Ref InstanceProfileName
      Tags:
        - Key: Name
          Value: broken-app
      UserData:
        Fn::Base64: |
          #!/bin/bash
          cat > /opt/app.py <<'PY'
          import json
          from http.server import BaseHTTPRequestHandler, HTTPServer

          class H(BaseHTTPRequestHandler):
              def do_GET(self):
                  body = json.dumps({"service": "app", "status": "ok"}).encode()
                  self.send_response(200)
                  self.send_header("Content-Type", "application/json")
                  self.send_header("Content-Length", str(len(body)))
                  self.end_headers()
                  self.wfile.write(body)

          HTTPServer(("0.0.0.0", 8080), H).serve_forever()
          PY
          cat > /etc/systemd/system/app.service <<'UNIT'
          [Unit]
          Description=app
          [Service]
          ExecStart=/usr/bin/python3 /opt/app.py
          Restart=always
          [Install]
          WantedBy=multi-user.target
          UNIT
          systemctl daemon-reload && systemctl enable --now app

  WebInstance:
    Type: AWS::EC2::Instance
    DependsOn: IgwAttach
    Properties:
      ImageId: !Ref AmiId
      InstanceType: !Ref InstanceType
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds: [!Ref WebSg]
      IamInstanceProfile: !Ref InstanceProfileName
      Tags:
        - Key: Name
          Value: broken-web
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          cat > /opt/web.py <<'PY'
          import urllib.request
          from http.server import BaseHTTPRequestHandler, HTTPServer

          APP = "http://${AppInstance.PrivateIp}:8080/"

          class H(BaseHTTPRequestHandler):
              def do_GET(self):
                  try:
                      reply = urllib.request.urlopen(APP, timeout=2).read().decode()
                      status = "App reachable: OK " + reply
                  except Exception as exc:
                      status = "App unreachable: FAIL " + str(exc)
                  body = ("<h1>Web tier OK</h1><p>" + status + "</p>").encode()
                  self.send_response(200)
                  self.send_header("Content-Type", "text/html")
                  self.send_header("Content-Length", str(len(body)))
                  self.end_headers()
                  self.wfile.write(body)

          HTTPServer(("0.0.0.0", 80), H).serve_forever()
          PY
          cat > /etc/systemd/system/web.service <<'UNIT'
          [Unit]
          Description=web
          [Service]
          ExecStart=/usr/bin/python3 /opt/web.py
          Restart=always
          [Install]
          WantedBy=multi-user.target
          UNIT
          systemctl daemon-reload && systemctl enable --now web

Outputs:
  VpcId:
    Value: !Ref Vpc
  IgwId:
    Value: !Ref Igw
  WebInstanceId:
    Value: !Ref WebInstance
  AppInstanceId:
    Value: !Ref AppInstance
  AppPrivateIp:
    Value: !GetAtt AppInstance.PrivateIp
  PublicRouteTableId:
    Value: !Ref PublicRouteTable
  PublicNaclId:
    Value: !Ref PublicNacl
  WebSgId:
    Value: !Ref WebSg
  AppSgId:
    Value: !Ref AppSg
