AWSTemplateFormatVersion: '2010-09-09'
Description: 'JFrog Artifactory Quick Start Deployment (qs-1qpmmjh61)'
Metadata:
  cfn-lint:
    config:
      ignore_checks:
        - W9006
        - W9002
        - W9003
        - W9004
Parameters:
  # AvailabilityZones:
  #   Description: List of Availability Zones to use for the subnets in the VPC. Two
  #     Availability Zones are used for this deployment.
  #   Type: List<AWS::EC2::AvailabilityZone::Name>
  VpcId:
    Type: AWS::EC2::VPC::Id
  VpcCidr:
    Description: CIDR block for the VPC
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.0.0/16
    Type: String
  PrivateSubnet1Cidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.0.0/19
    Type: String
  PrivateSubnet2Cidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.32.0/19
    Type: String
  PrivateSubnet3Cidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.64.0/19
    Type: String
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
  DatabaseAllocatedStorage:
    Type: Number
  DatabasePreferredAz:
    Type: String
  MultiAzDatabase:
    Description: Choose false to create an Amazon RDS instance in a single Availability Zone.
    ConstraintDescription: True or False
    AllowedValues:
      - "true"
      - "false"
    Type: String
  DatabaseUser:
    Type: String
  DatabasePassword:
    NoEcho: 'true'
    Type: String
  DatabaseInstance:
    Type: String
  DatabaseName:
    Type: String
  InstanceType:
    Default: m5.xlarge
    Type: String
  ArtifactoryHostRole:
    Type: String
  # VolumeSize:
  #   Type: Number
  EfsSecurityGroup:
    Type: String

Mappings:
  DatabaseMap:
    Postgres:
      Name: postgresql
      DatabaseVersion: 11.5
      Driver: "org.postgresql.Driver"
      Plugin: postgresql-42.2.9.jar
      PluginURL: https://jdbc.postgresql.org/download/
      port: "5432"
      extraDatabaseOps: ""
  JavaOptionstoInstance:
    c5.2xlarge:
      Min: 8
      Max: 12
      DeploymentSize: Small
    c5.4xlarge:
      Min: 16
      Max: 24
      DeploymentSize: Large
    m5.large:
      Min: 4
      Max: 4
      DeploymentSize: xxSmall
    m5.xlarge:
      Min: 8
      Max: 12
      DeploymentSize: xSmall
    m5.2xlarge:
      Min: 16
      Max: 24
      DeploymentSize: Small
    m5.4xlarge:
      Min: 32
      Max: 48
      DeploymentSize: Medium
    m5.8xlarge:
      Min: 64
      Max: 96
      DeploymentSize: Large
    m5.12xlarge:
      Min: 96
      Max: 144
      DeploymentSize: xLarge
    m5.16xlarge:
      Min: 128
      Max: 192
      DeploymentSize: xxLarge
    m5.24xlarge:
      Min: 192
      Max: 288
      DeploymentSize: xxxLarge
    m5.metal:
      Min: 192
      Max: 288
      DeploymentSize: xxxLarge
    m5d.large:
      Min: 4
      Max: 4
      DeploymentSize: xxSmall
    m5d.xlarge:
      Min: 8
      Max: 12
      DeploymentSize: xSmall
    m5d.2xlarge:
      Min: 16
      Max: 24
      DeploymentSize: Small
    m5d.4xlarge:
      Min: 32
      Max: 48
      DeploymentSize: Medium
    m5d.8xlarge:
      Min: 64
      Max: 96
      DeploymentSize: Large
    m5d.12xlarge:
      Min: 96
      Max: 144
      DeploymentSize: xLarge
    m5d.16xlarge:
      Min: 128
      Max: 192
      DeploymentSize: xxLarge
    m5d.24xlarge:
      Min: 192
      Max: 288
      DeploymentSize: xxxLarge
    m5d.metal:
      Min: 192
      Max: 288
      DeploymentSize: xxxLarge
    m5a.large:
      Min: 4
      Max: 4
      DeploymentSize: xxSmall
    m5a.xlarge:
      Min: 8
      Max: 12
      DeploymentSize: xSmall
    m5a.2xlarge:
      Min: 16
      Max: 24
      DeploymentSize: Small
    m5a.4xlarge:
      Min: 32
      Max: 48
      DeploymentSize: Medium
    m5a.8xlarge:
      Min: 64
      Max: 96
      DeploymentSize: Large
    m5a.12xlarge:
      Min: 96
      Max: 144
      DeploymentSize: xLarge
    m5a.16xlarge:
      Min: 128
      Max: 192
      DeploymentSize: xxLarge
    m5a.24xlarge:
      Min: 192
      Max: 288
      DeploymentSize: xxxLarge

Conditions:
  IsMultiAzDatabase: !Equals [!Ref MultiAzDatabase, 'true']

Resources:
  ArtifactoryDatabaseSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Private Subnets available to the RDS Instance(s)
      SubnetIds: !Ref SubnetIds
  ArtifactoryDatabase:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: !Ref DatabaseAllocatedStorage
      AvailabilityZone: !If [IsMultiAzDatabase, !Ref AWS::NoValue, !Ref DatabasePreferredAz]
      BackupRetentionPeriod: 30
      DBInstanceClass: !Ref DatabaseInstance
      DBName: !Ref DatabaseName
      DBSubnetGroupName: !Ref  ArtifactoryDatabaseSubnetGroup
      Engine: "Postgres"
      EngineVersion: !FindInMap
        - DatabaseMap
        - "Postgres"
        - DatabaseVersion
      MasterUsername: !Ref DatabaseUser
      MasterUserPassword: !Ref DatabasePassword
      MultiAZ: !Ref MultiAzDatabase
      StorageEncrypted: true
      VPCSecurityGroups:
        - !Ref ArtifactoryDatabaseSG
  ArtifactoryDatabaseSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      Tags:
        - Key: Name
          Value: artifactory-rds-sg
      GroupDescription: SG for RDS Instance to allow communication from the Bastion and Artifactory servers.
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref VpcCidr
        - IpProtocol: tcp
          FromPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          ToPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          CidrIp: !Ref PrivateSubnet1Cidr
        - IpProtocol: tcp
          FromPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          ToPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          CidrIp: !Ref PrivateSubnet2Cidr
        - IpProtocol: tcp
          FromPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          ToPort: !FindInMap
            - DatabaseMap
            - "Postgres"
            - port
          CidrIp: !Ref PrivateSubnet3Cidr
      SecurityGroupEgress:
        - 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: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
  ArtifactoryS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: Private
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
  ArtifactoryS3IAMPolicy:
    Type: AWS::IAM::Policy
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - EIAMPolicyActionWildcard
          ignore_reasons:
            - EIAMPolicyWildcardResource: excluding for s3:Get*, s3:Put*, s3:List*
    Properties:
      PolicyName: S3BucketPermissions
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: S3BucketPermissions
            Effect: Allow
            Action:
              - s3:AbortMultipartUpload
              - s3:BypassGovernanceRetention
              - s3:CreateAccessPoint
              - s3:CreateAccessPointForObjectLambda
              - s3:CreateBucket
              - s3:CreateJob
              - s3:DeleteAccessPoint
              - s3:DeleteAccessPointForObjectLambda
              - s3:DeleteAccessPointPolicy
              - s3:DeleteAccessPointPolicyForObjectLambda
              - s3:DeleteBucket
              - s3:DeleteBucketOwnershipControls
              - s3:DeleteBucketPolicy
              - s3:DeleteBucketWebsite
              - s3:DeleteJobTagging
              - s3:DeleteObject
              - s3:DeleteObjectTagging
              - s3:DeleteObjectVersion
              - s3:DeleteObjectVersionTagging
              - s3:DeleteStorageLensConfiguration
              - s3:DeleteStorageLensConfigurationTagging
              - s3:DescribeJob
              - s3:Get*
              - s3:List*
              - s3:ObjectOwnerOverrideToBucketOwner
              - s3:Put*
              - s3:ReplicateDelete
              - s3:ReplicateObject
              - s3:ReplicateTags
              - s3:RestoreObject
              - s3:UpdateJobPriority
              - s3:UpdateJobStatus
            Resource:
              - Fn::Join:
                - ''
                - - !Sub "arn:${AWS::Partition}:s3:::"
                  - !Ref ArtifactoryS3Bucket
              - Fn::Join:
                - ''
                - - !Sub "arn:${AWS::Partition}:s3:::"
                  - !Ref ArtifactoryS3Bucket
                  - "/*"
      Roles:
        - !Ref ArtifactoryHostRole
  # ArtifactoryEbsVolume:
  #   Type: AWS::EC2::Volume
  #   Properties:
  #     AvailabilityZone:
  #       !If
  #         - IsMultiAzDatabase
  #         - !Select
  #           - '0'
  #           - !Ref AvailabilityZones
  #         - !Ref DatabasePreferredAz
  #     Encrypted: false
  #     Size: !Ref VolumeSize
  #     Tags:
  #       - Key: Name
  #         Value: !Sub "Artifactory-${AWS::StackName}"
  #     VolumeType: gp2
  #   DeletionPolicy: Snapshot
  #   UpdateReplacePolicy: Snapshot
  ArtifactoryEfsFileSystem:
    Type: AWS::EFS::FileSystem
    Properties:
      BackupPolicy:
        Status: DISABLED
      Encrypted: true
      FileSystemTags:
        - Key: Name
          Value: !Sub "Artifactory-${AWS::StackName}"
      PerformanceMode: generalPurpose
      ThroughputMode: bursting
  ArtifactoryEfsMountTarget1:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref ArtifactoryEfsFileSystem
      SecurityGroups:
        - !Ref EfsSecurityGroup
      SubnetId: !Select ['0', !Ref SubnetIds]
  ArtifactoryEfsMountTarget2:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref ArtifactoryEfsFileSystem
      SecurityGroups:
        - !Ref EfsSecurityGroup
      SubnetId: !Select ['1', !Ref SubnetIds]
Outputs:
  S3Bucket:
    Value: !Ref ArtifactoryS3Bucket
    Description: Actual S3 bucket created for Artifactory
  DatabaseDriver:
    Value: !FindInMap [DatabaseMap, "Postgres", Driver]
  DatabasePlugin:
    Value: !FindInMap [DatabaseMap, "Postgres", Plugin]
  DatabasePluginUrl:
    Value: !Sub
      - "${MainURL}${PluginVersion}"
      - {
        MainURL: !FindInMap [DatabaseMap, "Postgres", PluginURL],
        PluginVersion: !FindInMap [DatabaseMap, "Postgres", Plugin]
        }
  DatabaseType:
    Value: !FindInMap [DatabaseMap, "Postgres", Name]
  DatabaseUrl:
    Value: !Sub
      - "jdbc:${DatabaseType}://${ArtifactoryDatabaseEndpointAddress}:${port}/${DatabaseName}${extraDatabaseOps}"
      - {
        DatabaseType: !FindInMap [DatabaseMap, "Postgres", Name],
        ArtifactoryDatabaseEndpointAddress: !GetAtt ArtifactoryDatabase.Endpoint.Address,
        port: !FindInMap [DatabaseMap, "Postgres", port],
        extraDatabaseOps: !FindInMap [DatabaseMap, "Postgres", extraDatabaseOps],
        }
  XrayMasterDatabaseUrl:
    Value: !Sub
      - "${ArtifactoryDatabaseEndpointAddress}:${port}/${DatabaseName}?sslmode=disable"
      - {
        ArtifactoryDatabaseEndpointAddress: !GetAtt ArtifactoryDatabase.Endpoint.Address,
        port: !FindInMap [DatabaseMap, "Postgres", port],
        }
  XrayDatabaseUrl:
    Value: !Sub
      - "${ArtifactoryDatabaseEndpointAddress}:${port}/xraydb?sslmode=disable"
      - {
        ArtifactoryDatabaseEndpointAddress: !GetAtt ArtifactoryDatabase.Endpoint.Address,
        port: !FindInMap [DatabaseMap, "Postgres", port],
        }
  JavaOpts:
    Value: !Sub
      - "-Xms${min}g -Xmx${max}g"
      - {
        min: !FindInMap [JavaOptionstoInstance, !Ref InstanceType, Min],
        max: !FindInMap [JavaOptionstoInstance, !Ref InstanceType, Max]
      }
  DeploymentSize:
    Value: !FindInMap [JavaOptionstoInstance, !Ref InstanceType, DeploymentSize]
  ArtifactoryEfsFileSystem:
    Value: !Ref ArtifactoryEfsFileSystem
