#*
#* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#* SPDX-License-Identifier: MIT-0
#*
#* Permission is hereby granted, free of charge, to any person obtaining a copy of this
#* software and associated documentation files (the "Software"), to deal in the Software
#* without restriction, including without limitation the rights to use, copy, modify,
#* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
#* permit persons to whom the Software is furnished to do so.
#*
#* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
#* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
#* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
#* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
#* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#*

#------------------------------------------------------------------------------
#
# Template: opsmgmt-deploy-test-instances.yaml
# Purpose:  AWS CloudFormation template to create a test Windows EC2 instance and IAM role for Systems Manager.
#
#
#------------------------------------------------------------------------------

AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation template to create a test Windows EC2 instance and IAM role for Systems Manager.

#-----------------------------------------------------------
# Parameters
#-----------------------------------------------------------
Parameters :
  LatestWindowsAmiId :
    # Use public Systems Manager Parameter
    Type : 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base'

Resources:
  #-------------------------------------------------
  # IAM role and instance profile to enable Systems Manager registration on EC2 instances
  #-------------------------------------------------
  ManagedInstanceRole:
    Type: AWS::IAM::Role
    DependsOn: SystemAssociationForEnablingExplorer
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action: sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Path: "/"
      RoleName: !Join [ '-', ['AmazonSSMManagedInstanceCore', !Ref 'AWS::Region'] ]
      Policies:
      - PolicyName: KMS_Permissions
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - kms:Decrypt
            Resource: !Sub 'arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key:*'
              
  ManagedInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref ManagedInstanceRole
      InstanceProfileName: !Sub 'ManagedInstanceProfile-${AWS::Region}'
      
  #-------------------------------------------------
  # Key used to encrypt CloudWatch and Session Manager related data
  #-------------------------------------------------
  SessionManagerDataEncryptionKey:
    DependsOn: ManagedInstanceRole
    Type: AWS::KMS::Key
    Properties:
      Description: Key used to encrypt Session Manager related data
      Enabled: True
      EnableKeyRotation: True
      KeyPolicy:
        Version: '2012-10-17'
        Id: AccountPolicy
        Statement:
        - Sid: Enable IAM User Permissions
          Effect: Allow
          Principal:
            AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
          Action: kms:*
          Resource: '*'
        - Sid: Allow use of the key by the instance
          Effect: Allow
          Principal:
            AWS: 
            - !Join [ '', ['arn',':', !Ref 'AWS::Partition',':', 'iam','::', !Ref 'AWS::AccountId',':', 'role/AmazonSSMManagedInstanceCore-', !Ref 'AWS::Region'] ]
          Action:
            - kms:DescribeKey
            - kms:Encrypt
            - kms:Decrypt
            - kms:ReEncrypt*
            - kms:GenerateDataKey
            - kms:GenerateDataKeyWithoutPlaintext
          Resource: '*'

  SessionManagerDataEncryptionKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/fleet-manager
      TargetKeyId: !Ref SessionManagerDataEncryptionKey

  #-------------------------------------------------
  # VPC and required resources to enable network connectivity to AWS Systems Manager
  #-------------------------------------------------
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
      - Key: Name
        Value: SSM-Workshop-CF
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
      - Key: Name
        Value: SSM-Workshop-CF
      - Key: SSMWorkshop
        Value: true
  VPCGatewayAttachment:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  SubnetPublic:
    Type: 'AWS::EC2::Subnet'
    Properties:
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: 10.0.0.0/20
      MapPublicIpOnLaunch: true
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: SSM-Workshop-CF
      - Key: SSMWorkshop
        Value: true
  RouteTablePublic:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: SSM-Workshop-CF
      - Key: SSMWorkshop
        Value: true
  RouteTableAssociationPublic:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic
      RouteTableId: !Ref RouteTablePublic
  RouteTablePublicInternetRoute:
    Type: 'AWS::EC2::Route'
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTablePublic
      DestinationCidrBlock: '0.0.0.0/0'
      GatewayId: !Ref InternetGateway
  NetworkAclPublic:
    Type: 'AWS::EC2::NetworkAcl'
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: SSM-Workshop-CF
      - Key: SSMWorkshop
        Value: true
  SubnetNetworkAclAssociationPublic:
    Type: 'AWS::EC2::SubnetNetworkAclAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic
      NetworkAclId: !Ref NetworkAclPublic
  NetworkAclEntryInPublicAllowAll:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId: !Ref NetworkAclPublic
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      Egress: false
      CidrBlock: '0.0.0.0/0'
  NetworkAclEntryOutPublicAllowAll:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId: !Ref NetworkAclPublic
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      Egress: true
      CidrBlock: '0.0.0.0/0'
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Security Group for SSM Workshop test instances"
      GroupName: SSM-Workshop-CF
      SecurityGroupEgress: 
        - IpProtocol: -1
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0
      Tags: 
        - Key: Name
          Value: SSM-Workshop-CF
        - Key: SSMWorkshop
          Value: true
      VpcId: !Ref VPC
      
  #-------------------------------------------------
  # One Windows EC2 instance using the latest versions of Windows 2019
  #-------------------------------------------------
  WindowsEc2Instance: 
    Type: AWS::EC2::Instance
    Properties: 
      InstanceType: t3.medium
      ImageId: !Ref LatestWindowsAmiId
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          GroupSet: 
            - Ref: "InstanceSecurityGroup"
          SubnetId: 
            Ref: "SubnetPublic"
      IamInstanceProfile: !Sub 'ManagedInstanceProfile-${AWS::Region}'
      Tags:
        - Key: Name
          Value: TestWindowsInstance
        - Key: SSMWorkshop
          Value: true
      UserData:
        Fn::Base64: !Sub |
          <powershell>
          $url="https://raw.githubusercontent.com/aws-samples/aws-cloud-and-hybrid-operations-workshop/main/misc/loop-and-stress.ps1"
          Invoke-WebRequest $url -OutFile "c:\loop-and-stress.ps1"
          New-Item -Path HKLM:\SOFTWARE -Name \"SampleApp\"
          Set-ItemProperty -Path HKLM:\SOFTWARE\SampleApp -Type DWORD -Name CrazyLogs -Value 1
          $trigger = New-JobTrigger -AtStartup -RandomDelay 00:00:30
          Register-ScheduledJob -Trigger $trigger -FilePath c:\loop-and-stress.ps1 -Name StressCPU
          Restart-Computer
          </powershell>

  #-------------------------------------------------
  # Automation Service IAM role and State Manager Association to enable Explorer
  #-------------------------------------------------
  EnableExplorerAutomationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ssm.amazonaws.com
          Action:
          - sts:AssumeRole
      Policies:
      - PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - iam:ListRoles
            - config:DescribeConfigurationRecorders
            - compute-optimizer:GetEnrollmentStatus
            - support:DescribeTrustedAdvisorChecks
            Resource: "*"
          - Effect: Allow
            Action:
            - ssm:UpdateServiceSetting
            - ssm:GetServiceSetting
            Resource:
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsitem/ssm-patchmanager"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsitem/EC2"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/ExplorerOnboarded"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/Association"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/ComputeOptimizer"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/ConfigCompliance"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/OpsData-TrustedAdvisor"
            - Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":ssm:*:*:servicesetting/ssm/opsdata/SupportCenterCase"
          - Effect: Allow
            Action:
            - iam:CreateServiceLinkedRole
            Resource:
              Fn::Join:
              - ''
              - - 'arn:'
                - Ref: AWS::Partition
                - ":iam::*:role/aws-service-role/ssm."
                - Ref: AWS::URLSuffix
                - "/AWSServiceRoleForAmazonSSM"
            Condition:
              StringEquals:
                iam:AWSServiceName: ssm.amazonaws.com
        PolicyName: SSMQuickSetupEnableExplorerInlinePolicy
      RoleName: SSM-Workshop-EnableExplorerRole

  SystemAssociationForEnablingExplorer:
    Type: AWS::SSM::Association
    Properties:
      Name: AWS-EnableExplorer
      AssociationName: SSM-Workshop-EnableExplorer
      Parameters:
        AutomationAssumeRole: 
        - !GetAtt EnableExplorerAutomationRole.Arn
          
Outputs:
  KMSKeyArn:
    Description: The ARN of the custom KMS key.
    Value: !GetAtt SessionManagerDataEncryptionKey.Arn