# 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.

AWSTemplateFormatVersion: "2010-09-09"
Description: Deploy Wickr Enterprise HA across three availability zones in your default region. This also includes an EC2 jump-box with the necessary tools pre-installed.


Parameters:
  LatestAmiId:
    Type:  'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
  SSHKeyName:
    Type: String
    Description: Name of the EC2 Key Pair for SSH access
  sourceIP:
    Type: String
    Default: 10.0.0.0/16
    Description: The public IP range that you want to allow access from (most likely set to 0.0.0.0/0 to allow all access)
  

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      Tags:
        - Key: Name
          Value: wickr-ha

  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: Name
          Value: wickr-ha

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

  PublicSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.0.0/24"
      AvailabilityZone: !Sub ${AWS::Region}a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: wickr-ha-public1

  PublicSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.1.0/24"
      AvailabilityZone: !Sub ${AWS::Region}b
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: wickr-ha-public2

  PublicSubnet3:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.2.0/24"
      AvailabilityZone: !Sub ${AWS::Region}c
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: wickr-ha-public3

  PrivateSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.3.0/24"
      AvailabilityZone: !Sub ${AWS::Region}a
      Tags:
        - Key: Name
          Value: wickr-ha-private1

  PrivateSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.4.0/24"
      AvailabilityZone: !Sub ${AWS::Region}b
      Tags:
        - Key: Name
          Value: wickr-ha-private2

  PrivateSubnet3:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.5.0/24"
      AvailabilityZone: !Sub ${AWS::Region}c
      Tags:
        - Key: Name
          Value: wickr-ha-private3

  NatGatewayEIP1:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"
      Tags:
        - Key: Name
          Value: wickr-ha-nat-eip1

  NatGatewayEIP2:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"
      Tags:
        - Key: Name
          Value: wickr-ha-nat-eip2
    
  NatGatewayEIP3:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"
      Tags:
        - Key: Name
          Value: wickr-ha-nat-eip3

  NatGateway1:
    Type: "AWS::EC2::NatGateway"
    Properties:
      SubnetId: !Ref PublicSubnet1
      AllocationId: !GetAtt NatGatewayEIP1.AllocationId

  NatGateway2:
    Type: "AWS::EC2::NatGateway"
    Properties:
      SubnetId: !Ref PublicSubnet2
      AllocationId: !GetAtt NatGatewayEIP2.AllocationId

  NatGateway3:
    Type: "AWS::EC2::NatGateway"
    Properties:
      SubnetId: !Ref PublicSubnet3
      AllocationId: !GetAtt NatGatewayEIP3.AllocationId

  RouteTablePublic:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: wickr-ha-public-rt

  PublicRoute:
    Type: "AWS::EC2::Route"
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTablePublic
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

  SubnetRouteTableAssociationPublic1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref RouteTablePublic

  SubnetRouteTableAssociationPublic2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref RouteTablePublic

  SubnetRouteTableAssociationPublic3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet3
      RouteTableId: !Ref RouteTablePublic

  RouteTablePrivate1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: wickr-ha-private-rt1

  RouteTablePrivate2:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: wickr-ha-private-rt2

  RouteTablePrivate3:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: wickr-ha-private-rt3

  PrivateRoute1:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref RouteTablePrivate1
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGateway1

  PrivateRoute2:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref RouteTablePrivate2
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGateway2

  PrivateRoute3:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref RouteTablePrivate3
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGateway3

  SubnetRouteTableAssociationPrivate1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref RouteTablePrivate1

  SubnetRouteTableAssociationPrivate2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref RouteTablePrivate2

  SubnetRouteTableAssociationPrivate3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet3
      RouteTableId: !Ref RouteTablePrivate3

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: 'jump-box egress only group'
      VpcId: !Ref VPC
      SecurityGroupEgress:
        - CidrIp: "0.0.0.0/0"
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: "Jump box security group"

  InstanceProfile: 
    Type: "AWS::IAM::InstanceProfile"
    Properties: 
      Path: "/"
      Roles:
        - !Ref InstanceRole

  InstanceRole:
    Type: 'AWS::IAM::Role'
    Properties: 
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore"
      Policies:
        - PolicyName: instanceAssumeEKSAdmin
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "sts:AssumeRole"
                Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/EKSAdminRole"

  Instance:
    Type: AWS::EC2::Instance
    Properties:
      SubnetId: !Ref PrivateSubnet1
      SecurityGroupIds: 
        - !GetAtt EC2SecurityGroup.GroupId
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref LatestAmiId
      InstanceType: t2.small
      KeyName: !Ref SSHKeyName
      UserData:
        Fn::Base64: |-
          #!/bin/bash
          yum update -y
          curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip
          unzip awscliv2.zip
          sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
          yum install jq -y
          curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.26.4/2023-05-11/bin/linux/amd64/kubectl
          chmod +x ./kubectl
          mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
          kubectl version --short --client
          curl https://kots.io/install | bash
          kubectl-kots version
          curl -sLO https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_Linux_amd64.tar.gz
          tar -xzf eksctl_Linux_amd64.tar.gz -C /tmp && rm eksctl_Linux_amd64.tar.gz
          sudo mv /tmp/eksctl /usr/local/bin
          cat > /usr/local/bin/configure-cluster.sh << __EOF__
            #!/bin/bash
            clear
            EKS_NAME=wickr-ha
            echo
            echo
            read -p "What region is your cluster deployed to? i.e us-east-1: " REGION
            if [[ \$REGION == us-gov-* ]]
              then
                PARTITION=\$REGION
              else
                PARTITION=aws
            fi
            echo -e "NOTE: If any of the following commands fail, check you have assumed an Administrative role in the CLI by running: aws sts get-caller-identity"
            sleep 1
            ADMINARN=\$(aws --region \$REGION iam get-role --role-name EKSAdminRole | jq .Role.Arn | tr -d '"')
            echo -e "Applying EKSAdminRole to the EKS cluster config"
            eksctl create iamidentitymapping \
                --cluster \$EKS_NAME \
                --region \$REGION \
                --arn \$ADMINARN \
                --group system:masters \
                --no-duplicate-arns \
                --username EKSAdminRole
            echo -e "Updating the EKS cluster config...."
            aws eks update-kubeconfig --name \$EKS_NAME --region \$REGION
            echo -e "...done!"
            echo -e "Adding storage drivers to the cluster..."
            eksctl utils associate-iam-oidc-provider --cluster wickr-ha --approve --region \$REGION
            eksctl create iamserviceaccount --name ebs-csi-controller-sa --namespace kube-system --cluster wickr-ha --region \$REGION --attach-policy-arn arn:\$PARTITION:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy --approve --role-only --role-name AmazonEKS_EBS_CSI_DriverRole
            CSIROLE=\$(aws iam get-role --role-name AmazonEKS_EBS_CSI_DriverRole | jq .Role.Arn | tr -d '"')
            eksctl create addon --name aws-ebs-csi-driver --cluster wickr-ha --region \$REGION --service-account-role-arn \$CSIROLE --force
            echo -e "...done!"
            echo
            echo -e "Now run the following command, replacing LICENCE.YAML with your licence file: "
            echo
            echo -e "  kubectl kots install enterprise-ha --namespace wickr --ensure-rbac --license-file LICENCE.YAML"
            echo
          __EOF__
          chmod +x /usr/local/bin/configure-cluster.sh

      Tags:
        - Key: Name
          Value: jumpbox

  DBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: 'DB Security Group'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - SourceSecurityGroupId: !GetAtt EKSCluster.ClusterSecurityGroupId
          IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
      SecurityGroupEgress:
        - CidrIp: "0.0.0.0/0"
          IpProtocol: "-1"
      Tags:
        - Key: Name
          Value: "Database security group"

  DBCluster:
    Type: "AWS::RDS::DBCluster"
    DeletionPolicy: Delete
    Properties:
      Engine: aurora-mysql
      DatabaseName: wickrdb
      MasterUsername: admin
      MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSSecret, ':SecretString:password}}' ]]
      DBSubnetGroupName: !Ref DBSubnetGroup
      StorageEncrypted: true
      KmsKeyId: !Ref rdsKey
      VpcSecurityGroupIds:
        - !Ref DBSecurityGroup
  DBInstance1:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier:
        Ref: DBCluster
      DBInstanceClass: db.r5.large
      Engine: aurora-mysql
      PubliclyAccessible: "false"
  DBInstance2:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier:
        Ref: DBCluster
      DBInstanceClass: db.r5.large
      Engine: aurora-mysql
      PubliclyAccessible: "false"
  DBInstance3:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier:
        Ref: DBCluster
      DBInstanceClass: db.r5.large
      Engine: aurora-mysql
      PubliclyAccessible: "false"

  DBSubnetGroup:
    Type: "AWS::RDS::DBSubnetGroup"
    Properties:
      DBSubnetGroupDescription: "RDS Aurora MySQL Subnet Group"
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
        - !Ref PrivateSubnet3

  RDSSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: 'This is the password for the Database Admin user'
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'
        GenerateStringKey: 'password'
        PasswordLength: 16
        ExcludeCharacters: '"@/\'
      KmsKeyId: !GetAtt SecretManagerKey.Arn
  SecretManagerKey:
    Type: AWS::KMS::Key
    Properties:
      Enabled: true
      EnableKeyRotation: true
      PendingWindowInDays: 7
      KeyPolicy:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root"
            Action: "*"
            Resource: "*"
  secretsManagerKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/secret
      TargetKeyId:
        Ref: SecretManagerKey

  rdsKey:
    Type: AWS::KMS::Key
    Properties:
      Enabled: true
      EnableKeyRotation: true
      PendingWindowInDays: 7
      KeyPolicy:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root"
            Action: "*"
            Resource: "*"
  rdsAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/rds
      TargetKeyId:
        Ref: rdsKey

  S3Bucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Sub "wickr-${AWS::AccountId}-${AWS::Region}"
      LoggingConfiguration:
        DestinationBucketName: !Ref LoggingBucket
        LogFilePrefix: wickr-ha
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: Only allow Secure Transport
            Action:
              - s3:*
            Effect: Deny
            Resource:
              - !Sub "arn:${AWS::Partition}:s3:::${S3Bucket}"
              - !Sub "arn:${AWS::Partition}:s3:::${S3Bucket}/*"
            Principal: "*"
            Condition:
              Bool:
                aws:SecureTransport:
                  false

  LoggingBucket:
    Type: AWS::S3::Bucket
    Properties:
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration:
        Rules:
          - Id: GlacierRule
            Status: Enabled
            ExpirationInDays: 730
            Transitions:
              - TransitionInDays: 180
                StorageClass: GLACIER
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: TRUE
        BlockPublicPolicy: TRUE
        IgnorePublicAcls: TRUE
        RestrictPublicBuckets: TRUE
  S3BucketPolicyLogging:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref LoggingBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: Logging Policy
            Effect: Allow
            Action: 
              - s3:PutObject
            Principal:
              Service: logging.s3.amazonaws.com
            Resource: 
              - !Sub "arn:${AWS::Partition}:s3:::${LoggingBucket}/*"
              - !Sub "arn:${AWS::Partition}:s3:::${LoggingBucket}"
          - Sid: Only allow Secure Transport
            Action:
              - s3:*
            Effect: Deny
            Resource:
              - !Sub "arn:${AWS::Partition}:s3:::${LoggingBucket}"
              - !Sub "arn:${AWS::Partition}:s3:::${LoggingBucket}/*"
            Principal: "*"
            Condition:
              Bool:
                aws:SecureTransport:
                  false


  EKSCluster:
    Type: AWS::EKS::Cluster
    Properties:
      Name: wickr-ha
      RoleArn: !GetAtt EKSClusterRole.Arn
      Version: 1.26
      EncryptionConfig:
        - Provider:
            KeyArn: !GetAtt EksKmsKey.Arn
          Resources:
            - secrets
      ResourcesVpcConfig:
        SubnetIds:
          - !Ref "PrivateSubnet1"
          - !Ref "PrivateSubnet2"
          - !Ref "PrivateSubnet3"
          - !Ref "PublicSubnet1"
          - !Ref "PublicSubnet2"
          - !Ref "PublicSubnet3"
        EndpointPublicAccess: false
        EndpointPrivateAccess: true
      Logging:
        ClusterLogging:
          EnabledTypes:
            - Type: api
            - Type: audit
            - Type: authenticator

  externalToClusterRule1:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: udp
      FromPort: 16384
      ToPort: 17384
      CidrIp: !Ref sourceIP
      GroupId: !GetAtt EKSCluster.ClusterSecurityGroupId

  externalToClusterRule2:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      CidrIp: !Ref sourceIP
      GroupId: !GetAtt EKSCluster.ClusterSecurityGroupId

  externalToClusterRule3:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 8001
      ToPort: 8001
      CidrIp: !Ref sourceIP
      GroupId: !GetAtt EKSCluster.ClusterSecurityGroupId

  jumpBoxToClusterRule:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      SourceSecurityGroupId: !GetAtt EC2SecurityGroup.GroupId
      GroupId: !GetAtt EKSCluster.ClusterSecurityGroupId

  Addon1:
    Type: AWS::EKS::Addon
    Properties: 
      AddonName: vpc-cni
      ClusterName: !Ref EKSCluster
  Addon2:
    Type: AWS::EKS::Addon
    Properties: 
      AddonName: coredns
      ClusterName: !Ref EKSCluster
  Addon3:
    Type: AWS::EKS::Addon
    Properties: 
      AddonName: kube-proxy
      ClusterName: !Ref EKSCluster

  WorkerNodeGroup:
    Type: AWS::EKS::Nodegroup
    Properties:
      ClusterName: !Ref EKSCluster
      NodegroupName: "worker-ng-01"
      InstanceTypes:
        - "m5.large"
      ScalingConfig:
        MinSize: 3
        DesiredSize: 3
        MaxSize: 6
      Subnets:
        - !Ref "PrivateSubnet1"
        - !Ref "PrivateSubnet2"
        - !Ref "PrivateSubnet3"
      DiskSize: 50
      NodeRole: !GetAtt EKSNodeRole.Arn

  CallingNodeGroup:
    Type: AWS::EKS::Nodegroup
    Properties:
      ClusterName: !Ref EKSCluster
      NodegroupName: "calling-ng-01"
      InstanceTypes:
        - "m5.large"
      ScalingConfig:
        MinSize: 2
        DesiredSize: 3
        MaxSize: 6
      Subnets:
        - !Ref "PublicSubnet1"
        - !Ref "PublicSubnet2"
        - !Ref "PublicSubnet3"
      DiskSize: 50
      NodeRole: !GetAtt EKSNodeRole.Arn
      Labels:
        role: calling

  EKSClusterRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: EKSClusterRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: eks.amazonaws.com
            Action: "sts:AssumeRole"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKSClusterPolicy"
      Policies:
        - PolicyName: kmsSecret
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "kms:Encrypt"
                  - "kms:Decrypt"
                  - "kms:ListGrants"
                  - "kms:DescribeKey"
                Resource: 
                  - !GetAtt EksKmsKey.Arn

  EksKmsKey:
    Type: AWS::KMS::Key
    Properties:
      Enabled: true
      EnableKeyRotation: true
      PendingWindowInDays: 7
      KeyPolicy:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root"
            Action: "*"
            Resource: "*"
  EksKmsKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/eksSecret
      TargetKeyId:
        Ref: EksKmsKey

  EKSNodeRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: EKSNodeRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: "sts:AssumeRole"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy"
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore"
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKS_CNI_Policy"
      Policies:
        - PolicyName: s3Policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "s3:PutObject"
                  - "s3:GetObject"
                  - "s3:DeleteObject"
                  - "s3:AbortMultipartUpload"
                  - "s3:GetObjectVersion"
                  - "s3:ListMultipartUploadParts"
                Resource:
                  - !Sub '${S3Bucket.Arn}/*'

  EKSAdminRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: EKSAdminRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: EKSAdminPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "iam:GetRole"
                  - "iam:ListRoles"
                  - "iam:CreateServiceLinkedRole"
                  - "iam:PassRole"
                Resource: !GetAtt EKSClusterRole.Arn
              - Effect: Allow
                Action:
                  - "eks:Create*"
                  - "eks:Associate*"
                  - "eks:RegisterCluster"
                  - "eks:TagResource"
                  - "eks:Update*"
                  - "eks:Describe*"
                  - "eks:List*"
                  - "eks:AccessKubernetesApi"
                Resource: !GetAtt EKSCluster.Arn

Outputs:
  EC2ID:
    Description: The instance ID of the jump-box
    Value: !Ref Instance
  EKSAdminArn:
    Description: The Arn of the EKS Admin role
    Value: !GetAtt EKSAdminRole.Arn
  S3BucketName:
    Description: The name of the S3 bucket
    Value: !Ref S3Bucket
  DBAddress:
    Description: The Database Endpoint value
    Value: !GetAtt DBCluster.Endpoint.Address