Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. Linked to AWS Parameter
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  InstanceType:
    Description: Enter t3.small, t3.medium. Default is t3.medium.
    Type: String
    Default: t3.medium
    AllowedValues: 
      - t3.small
      - t3.medium
  LatestAmiId:
    Description: (DO NOT CHANGE)
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
    AllowedValues:
      - /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
# IAM Role Instance Profile
  WPHa2LabInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: WPHa2LabInstanceRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/ReadOnlyAccess

  WPHa2LabInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: WPHa2LabInstanceProfile
      Path: /
      Roles:
        - !Ref WPHa2LabInstanceRole

# VPC1 Resource
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
     CidrBlock: 10.1.0.0/16
     EnableDnsSupport: true
     EnableDnsHostnames: true
     Tags:
      - Key: Name
        Value: WP-VPC1
  VPC1InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: WP-VPC1-IGW
  VPC1InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref VPC1InternetGateway
      VpcId: !Ref VPC1

  VPC1RouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: WP-VPC1-PublicRT
  VPC1RouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: WP-VPC1-PrivateRT

  VPC1Route1:
    Type: AWS::EC2::Route
    DependsOn: VPC1InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref VPC1RouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref VPC1InternetGateway

  VPC1Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      MapPublicIpOnLaunch: true
      CidrBlock: 10.1.1.0/24
      Tags:
        - Key: Name
          Value: WP-VPC1-Subnet1
  VPC1Subnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VPC1RouteTable1
      SubnetId: !Ref VPC1Subnet1
  VPC1Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 2, !GetAZs '' ]
      MapPublicIpOnLaunch: true
      CidrBlock: 10.1.2.0/24
      Tags:
        - Key: Name
          Value: WP-VPC1-Subnet2
  VPC1Subnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VPC1RouteTable1
      SubnetId: !Ref VPC1Subnet2

  VPC1Subnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 0, !GetAZs '' ]
      MapPublicIpOnLaunch: true
      CidrBlock: 10.1.3.0/24
      Tags:
        - Key: Name
          Value: WP-VPC1-Subnet3
  VPC1Subnet3RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VPC1RouteTable2
      SubnetId: !Ref VPC1Subnet3
  VPC1Subnet4:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC1
      AvailabilityZone: !Select [ 2, !GetAZs '' ]
      MapPublicIpOnLaunch: true
      CidrBlock: 10.1.4.0/24
      Tags:
        - Key: Name
          Value: WP-VPC1-Subnet4
  VPC1Subnet4RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VPC1RouteTable2
      SubnetId: !Ref VPC1Subnet4

# Security Group
  VPC1SG1:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: SGWebSrv
      Tags:
      - Key : Name
        Value : SGWebSrv
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '22'
        ToPort: '22'
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: '80'
        ToPort: '80'
        CidrIp: 0.0.0.0/0
      - IpProtocol: icmp
        FromPort: -1
        ToPort: -1
        CidrIp: 0.0.0.0/0

  VPC1SG2:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: SGALB
      Tags:
      - Key : Name
        Value : SGALB
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '80'
        ToPort: '80'
        CidrIp: 0.0.0.0/0

  VPC1SG3:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: SGRDS
      Tags:
      - Key : Name
        Value : SGRDS
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '3306'
        ToPort: '3306'
        SourceSecurityGroupId: !Ref VPC1SG1

  VPC1SG4:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: SGEFS
      Tags:
      - Key : Name
        Value : SGEFS
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '2049'
        ToPort: '2049'
        SourceSecurityGroupId: !Ref VPC1SG1

# EFS
  ElasticFileSystem:
    Type: AWS::EFS::FileSystem
    Properties:
      FileSystemTags:
        - Key: Name
          Value: WebSrv-EFS
  ElasticFileSystemMountTarget0:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref ElasticFileSystem
      SecurityGroups:
      - !Ref VPC1SG4
      SubnetId: !Ref VPC1Subnet1
  ElasticFileSystemMountTarget1:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref ElasticFileSystem
      SecurityGroups:
      - !Ref VPC1SG4
      SubnetId: !Ref VPC1Subnet2

# ALB
  ALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Name: ALB-WP
      SecurityGroups:
        - !Ref VPC1SG2
      Subnets:
        - !Ref VPC1Subnet1
        - !Ref VPC1Subnet2

  ALBTG:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: ALB-TG
      Port: 80
      Protocol: HTTP
      HealthCheckPath: /info.php
      HealthCheckIntervalSeconds: 30
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 6
      Matcher:
        HttpCode: 200-299
      Targets:
        - Id: !Ref VPC1Instance1
          Port: 80
      TargetGroupAttributes: 
      - Key : deregistration_delay.timeout_seconds
        Value : '60'
      VpcId: !Ref VPC1
      Tags:
      - Key : Name
        Value : VPC1-ALBTG

  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref ALBTG
      LoadBalancerArn: !Ref ALB
      Port: 80
      Protocol: HTTP

# AWS RDS
  myDBSubnetGroup:
    DependsOn: VPC1Subnet3
    Type: AWS::RDS::DBSubnetGroup
    Properties: 
      DBSubnetGroupDescription: DBLab-Subnet34
      SubnetIds: 
        - !Ref VPC1Subnet3
        - !Ref VPC1Subnet4
      Tags: 
        - 
          Key: Name
          Value: WPHa2Lab-Subnet34

  myDBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties: 
      Description: my mysql 8
      Family: mysql8.0
      Parameters: 
        character_set_database: utf8
        character_set_server: utf8
      Tags: 
      - Key : Name
        Value : mymysql8

  myDBInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      Engine: mysql
      #EngineVersion: "8.0.32"
      DBInstanceIdentifier: wpdb
      DBName: wpdb
      MasterUsername: root
      MasterUserPassword: qwe12345
      AllocatedStorage: 20
      #AvailabilityZone: ap-northeast-2a
      BackupRetentionPeriod: 0
      DBInstanceClass: db.t4g.micro
      MultiAZ: true
      PubliclyAccessible: false
      StorageType: gp3
      VPCSecurityGroups:
        - !Ref VPC1SG3
      DBSubnetGroupName: !Ref myDBSubnetGroup
      Tags:
        - Key: Name
          Value: wpdb-instance

# Instances1
  VPC1Instance1:
    Type: AWS::EC2::Instance
    DependsOn: ElasticFileSystem
    Properties:
      ImageId: !Ref LatestAmiId
      IamInstanceProfile : WPHa2LabInstanceProfile
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      Tags:
        - Key: Name
          Value: WebSrv-Leader
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref VPC1Subnet1
          GroupSet:
          - !Ref VPC1SG1
          PrivateIpAddress: 10.1.1.10
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          hostnamectl --static set-hostname WebSrv-Leader
          echo "sudo su -" >> /home/ec2-user/.bashrc

          # Install Apache
          yum update -y
          yum install jq htop tree gcc amazon-efs-utils mariadb -y
          yum install httpd -y
          systemctl start httpd && systemctl enable httpd

          # Install PHP
          amazon-linux-extras install php8.2 -y
          yum install -y php-xml php-mbstring ImageMagick ImageMagick-devel php-pear php-devel
          printf "\n" | pecl install imagick
          echo "extension = imagick.so" > /etc/php.d/40-imagick.ini
          systemctl restart php-fpm && systemctl restart httpd

          # Setting EFS Filesystem
          mkdir -p /var/www/wordpress/
          sleep 1m
          mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${ElasticFileSystem}.efs.ap-northeast-2.amazonaws.com:/ /var/www/wordpress
          echo "<?php phpinfo(); ?>" > /var/www/wordpress/info.php
          curl -o /var/www/wordpress/xff.php https://cloudneta-aws-book.s3.ap-northeast-2.amazonaws.com/chapter11/xff.php --silent

          # Install Wordpress
          wget https://wordpress.org/wordpress-6.2.zip
          unzip wordpress-6.2.zip
          cp wordpress/wp-config-sample.php wordpress/wp-config.php
          sed -i "s/database_name_here/wordpressdb/g" wordpress/wp-config.php
          sed -i "s/username_here/root/g" wordpress/wp-config.php
          sed -i "s/password_here/qwe12345/g" wordpress/wp-config.php
          cp -r wordpress/* /var/www/wordpress/
          chown -R apache:apache /var/www
          chmod 2775 /var/www
          find /var/www -type d -exec chmod 2775 {} \;
          find /var/www -type f -exec chmod 0664 {} \;
          chmod u+wrx /var/www/wordpress/wp-content/*
          echo 'ServerName 127.0.0.1:80' >> /etc/httpd/conf.d/MyBlog.conf
          echo 'DocumentRoot /var/www/wordpress' >> /etc/httpd/conf.d/MyBlog.conf
          echo '<Directory /var/www/wordpress>' >> /etc/httpd/conf.d/MyBlog.conf
          echo '  Options Indexes FollowSymLinks' >> /etc/httpd/conf.d/MyBlog.conf
          echo '  AllowOverride All' >> /etc/httpd/conf.d/MyBlog.conf
          echo '  Require all granted' >> /etc/httpd/conf.d/MyBlog.conf
          echo '</Directory>' >> /etc/httpd/conf.d/MyBlog.conf
          systemctl restart php-fpm && systemctl restart httpd

# CloudFront
  MyCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    DependsOn: ALB
    Properties:
      DistributionConfig:
        Origins:
        - DomainName: !GetAtt ALB.DNSName
          Id: elb
          CustomOriginConfig:
            OriginProtocolPolicy: http-only
        DefaultCacheBehavior:
          AllowedMethods:
          - DELETE
          - GET
          - HEAD
          - OPTIONS
          - PATCH
          - POST
          - PUT
          DefaultTTL: 0
          MaxTTL: 0
          MinTTL: 0
          ForwardedValues:
            Headers:
            - '*'
            Cookies:
              Forward: all
            QueryString: true
          TargetOriginId: elb
          ViewerProtocolPolicy: allow-all
          Compress: true
        Comment: WordPress CDN
        Enabled: true
        PriceClass: PriceClass_200
        IPV6Enabled: false

# Output
Outputs:
  CloudFrontDNS:
    Description: CloudFront DNS address
    Value: !Join ['', ['http://', !GetAtt MyCloudFrontDistribution.DomainName]]
  WebSrvLeaderEC2IP:
    Value: !GetAtt VPC1Instance1.PublicIp
  EfsFileSystemID:
    Value: !Ref ElasticFileSystem