AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS ParallelCluster Policies'

Parameters:
  Region:
    Description: When set to a given region name (e.g. eu-west-1), the API can control resources in that region only. Set to '*' to control all regions.
    Type: String
    Default: '*'

  EnableFSxS3Access:
    Description: |
      When set to true the ParallelCluster ParallelClusterFSxS3AccessPolicy is created which can access, write to the S3 buckets
      specified in the Filed FsxS3Bucket, it is needed to import/export from/to S3 when creating an FSx filesystem. NOTE - setting this
      to true grants the Lambda function S3 Get*, List* and PutObject privileges on the buckets specified in FsxS3Buckets.
    Type: String
    Default: false
    AllowedValues:
      - true
      - false

  EnableIamAdminAccess:
    Description: |
      When set to true the ParallelCluster API takes care of IAM resource creation when deploying clusters or generating custom AMIs.
      WARNING - setting this to true grants IAM admin privileges to the Lambda function
    Type: String
    Default: false
    AllowedValues:
      - true
      - false

  FsxS3Buckets:
    Description: |
      Comma separated list of S3 bucket ARNs, to allow the lambda function to import/export from/to S3 when creating an FSx filesystem.
      NOTE - The setting is used only when EnableFSxS3Access is set to true. (example arn:aws:s3:::<S3_BUCKET_1>,arn:aws:s3:::<S3_BUCKET_2>)
    Type: String
    Default: ''
    AllowedPattern: ^((arn:[a-z\-\*]*:s3:[a-z0-9\-]*:([0-9]{12})*:[^,\s\/]+)?(,arn:[a-z\-\*]*:s3:[a-z0-9\-]*:([0-9]{12})*:[^,\s\/]+)*)$|^\*$
    ConstraintDescription: |
      The list of S3 buckets is incorrectly formatted. The list should have the format: arn:<PARTITION>:s3:<REGION>:<ACCOUNT_ID>:<BUCKET_NAME>[,arn:<PARTITION>:s3:<REGION>:<ACCOUNT_ID>:<BUCKET_NAME>,...]
      Example: arn:aws:s3:::test-bucket-1,arn:aws:s3:::test-bucket-2,arn:aws:s3:::test-bucket-3

  PermissionsBoundaryPolicy:
    Description: |
      ARN of a IAM policy to use as PermissionsBoundary for all IAM resources created by ParallelCluster API.
      When specified, IAM permissions assumed by the API are conditionally restricted to the usage of the given PermissionsBoundary
    Type: String
    Default: ''
    ConstraintDescription: "The value must be a valid ARN in the format: arn:{AWS::Partition}:iam::{AWS::AccountId}:policy/PolicyNameParameter"
    AllowedPattern: "^(arn:.*:iam::.*:policy\\/([a-zA-Z0-9_-]+))|()$"

  EnableBatchAccess:
    Description: |
      When set to true the ParallelCluster ParallelClusterClusterPolicyBatch is created which can access Batch actions and resources.
    Type: String
    Default: false
    AllowedValues:
      - true
      - false
  IAMRoleAndPolicyPrefix:
    Type: String
    Description: 'Prefix for IAM roles and policies'
    Default: ''
    MaxLength: 10

  AdditionalPolicies:
    Description: |
      (OPTIONAL) ARN of the additional IAM policy to be attached to the default execution role for the ParallelCluster Lambda function.
      Only one policy can be specified.
    Type: String
    Default: ''
    AllowedPattern: "^(arn:.*:iam::.*:policy\\/([a-zA-Z0-9_-]+))|()$"

Outputs:
  ParallelClusterLogRetrievalPolicy:
    Value: !Ref ParallelClusterLogRetrievalPolicy

  ParallelClusterImageManagedPolicy:
    Value: !Ref ParallelClusterImageManagedPolicy

  ParallelClusterClusterPolicy1:
    Value: !Ref ParallelClusterClusterPolicy1

  ParallelClusterClusterPolicy2:
    Value: !Ref ParallelClusterClusterPolicy2

  FSxS3AccessPolicy:
    Condition: EnableFSxS3AccessCondition
    Value: !Ref ParallelClusterFSxS3AccessPolicy

  ParallelClusterLambdaRoleArn:
    Value: !GetAtt ParallelClusterLambdaRole.Arn

  DefaultParallelClusterIamAdminPolicy:
    Condition: EnableIamPolicy
    Value: !Ref DefaultParallelClusterIamAdminPolicy

  ParallelClusterClusterPolicyBatch:
    Condition: EnableBatchAccessCondition
    Value: !Ref ParallelClusterClusterPolicyBatch



Conditions:
  IsMultiRegion: !Equals [!Ref Region, '*']
  EnableFSxS3AccessCondition: !Equals [!Ref EnableFSxS3Access, true]
  EnableBatchAccessCondition: !Equals [!Ref EnableBatchAccess, true]
  EnablePermissionsBoundary: !Not [!Equals [!Ref PermissionsBoundaryPolicy, '']]
  UseAdditionalPolicies: !Not [!Equals [!Ref AdditionalPolicies, '']]
  UseAllBucketsForFSxS3: !Equals [!Ref FsxS3Buckets, "*"]
  EnableIamPolicy: !Or
    - !Equals [!Ref EnableIamAdminAccess, true]
    - !Condition EnablePermissionsBoundary
  InIsolatedRegion: !Or
    - !Equals [!Ref AWS::Partition, 'aws-iso']
    - !Equals [!Ref AWS::Partition, 'aws-iso-b']

Resources:
  ### IAM POLICIES

  # Every policy name comes with a suffix derived from the Stack ID to avoid name collisions.
  # Given a stack id arn:aws:cloudformation:REGION:ACCOUNT:stack/STACK_NAME/8131d980-7fb5-11ee-9589-0a6424944f95,
  # the resulting StackIdSuffix will be 8131d980.
  DefaultParallelClusterIamAdminPolicy:
    Type: AWS::IAM::ManagedPolicy
    Condition: EnableIamPolicy
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}DefaultParallelClusterIamAdminPolicy-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      Roles:
        - !Ref ParallelClusterLambdaRole
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - iam:CreateServiceLinkedRole
              - iam:DeleteRole
              - iam:TagRole
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*
            Effect: Allow
            Sid: IamRole
          - Action:
              - iam:CreateRole
              - iam:PutRolePolicy
              - iam:DeleteRolePolicy
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*
            Effect: Allow
            Condition: !If
              - EnablePermissionsBoundary
              - StringEquals:
                  iam:PermissionsBoundary:
                    - !Ref PermissionsBoundaryPolicy
              - !Ref AWS::NoValue
            Sid: IamInlinePolicyAndCreateRole
          - Action:
              - iam:AttachRolePolicy
              - iam:DetachRolePolicy
            Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*
            Condition:
              ArnLike:
                iam:PolicyARN:
                  - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/parallelcluster*
                  - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/parallelcluster/*
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/AWSBatchFullAccess
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonS3ReadOnlyAccess
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSBatchServiceRole
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/EC2InstanceProfileForImageBuilder
                  - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
              StringEquals: !If
                - EnablePermissionsBoundary
                - iam:PermissionsBoundary:
                    - !Ref PermissionsBoundaryPolicy
                - !Ref AWS::NoValue
            Effect: Allow
            Sid: IamPolicy


  ParallelClusterLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      PermissionsBoundary: !If [EnablePermissionsBoundary, !Ref PermissionsBoundaryPolicy, !Ref 'AWS::NoValue']
      RoleName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterLambdaRole-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId']]]] }
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service: lambda.amazonaws.com
      ManagedPolicyArns:
        # Required for Lambda logging and XRay
        - !If
          - InIsolatedRegion
          - !Ref AWS::NoValue
          - !Sub arn:${AWS::Partition}:iam::aws:policy/AWSXRayDaemonWriteAccess
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        # Required to run ParallelCluster functionalities
        - !Ref ParallelClusterClusterPolicy1
        - !Ref ParallelClusterClusterPolicy2
        - !If
          - EnableBatchAccessCondition
          - !Ref ParallelClusterClusterPolicyBatch
          - !Ref AWS::NoValue
        - !Ref ParallelClusterImageManagedPolicy
        - !Ref ParallelClusterLogRetrievalPolicy
        - !If
          - UseAdditionalPolicies
          - !Ref AdditionalPolicies
          - !Ref AWS::NoValue

  ### CLUSTER ACTIONS POLICIES

  ParallelClusterClusterPolicyBatch:
    Type: AWS::IAM::ManagedPolicy
    Condition: EnableBatchAccessCondition
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterClusterPolicyBatch-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - iam:PassRole
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*
            Effect: Allow
            Condition:
              StringEqualsIfExists:
                iam:PassedToService:
                  - ecs-tasks.amazonaws.com
                  - batch.amazonaws.com
                  - codebuild.amazonaws.com
            Sid: IamPassRole
          - Action:
              - iam:CreateServiceLinkedRole
              - iam:DeleteServiceLinkedRole
            Resource:
              # AWS Batch creates a service linked role automatically for the ComputeEnvironment
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/batch.amazonaws.com/*
            Effect: Allow
            Condition:
              StringEquals:
                iam:AWSServiceName:
                  - batch.amazonaws.com
          - Action:
              - codebuild:*
            Resource: !Sub arn:${AWS::Partition}:codebuild:${Region}:${AWS::AccountId}:project/pcluster-*
            Effect: Allow
          - Action:
              - ecr:*
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: ECR
          - Action:
              - batch:*
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: Batch
          - Action:
              - events:*
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Resource: '*'
            Sid: AmazonCloudWatchEvents
          - Action:
              - ecs:DescribeContainerInstances
              - ecs:ListContainerInstances
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: ECS

  ParallelClusterFSxS3AccessPolicy:
    Type: AWS::IAM::Policy
    Condition: EnableFSxS3AccessCondition
    Properties:
      PolicyName: !Sub ${IAMRoleAndPolicyPrefix}ParallelClusterFSxS3AccessPolicy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - iam:CreateServiceLinkedRole
              - iam:AttachRolePolicy
              - iam:PutRolePolicy
            Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/s3.data-source.lustre.fsx.amazonaws.com/*
            Effect: Allow
            Sid: FSxS3PoliciesAttach
          - Action:
              - s3:Get*
              - s3:List*
              - s3:PutObject
            Resource: !Split
              - ","
              - !If
                - UseAllBucketsForFSxS3
                - "*"
                - !Sub ["${FsxS3Buckets},${FsxS3BucketsObjects}", FsxS3BucketsObjects: !Join ["/*,", !Split [",", !Sub "${FsxS3Buckets}/*"]]]
            Effect: Allow
            Sid: EnableFSxS3Access
      Roles:
        - !Ref ParallelClusterLambdaRole

  ParallelClusterClusterPolicy1:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterClusterPolicy1-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - ec2:Describe*
              - ec2:AllocateAddress
              - ec2:AssociateAddress
              - ec2:AttachNetworkInterface
              - ec2:AuthorizeSecurityGroupEgress
              - ec2:AuthorizeSecurityGroupIngress
              - ec2:CreateFleet
              - ec2:CreateLaunchTemplate
              - ec2:CreateLaunchTemplateVersion
              - ec2:CreateNetworkInterface
              - ec2:CreatePlacementGroup
              - ec2:CreateSecurityGroup
              - ec2:CreateSnapshot
              - ec2:CreateTags
              - ec2:DeleteTags
              - ec2:CreateVolume
              - ec2:DeleteLaunchTemplate
              - ec2:DeleteNetworkInterface
              - ec2:DeletePlacementGroup
              - ec2:DeleteSecurityGroup
              - ec2:DeleteVolume
              - ec2:DisassociateAddress
              - ec2:ModifyLaunchTemplate
              - ec2:ModifyNetworkInterfaceAttribute
              - ec2:ModifyVolume
              - ec2:ModifyVolumeAttribute
              - ec2:ReleaseAddress
              - ec2:RevokeSecurityGroupEgress
              - ec2:RevokeSecurityGroupIngress
              - ec2:RunInstances
              - ec2:TerminateInstances
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: EC2ReadAndWrite
          - Action:
              - dynamodb:DescribeTable
              - dynamodb:ListTagsOfResource
              - dynamodb:CreateTable
              - dynamodb:DeleteTable
              - dynamodb:GetItem
              - dynamodb:PutItem
              - dynamodb:UpdateItem
              - dynamodb:Query
              - dynamodb:TagResource
            Resource: !Sub arn:${AWS::Partition}:dynamodb:${Region}:${AWS::AccountId}:table/parallelcluster-*
            Effect: Allow
            Sid: DynamoDB
          - Action:
              - route53:ChangeResourceRecordSets
              - route53:ChangeTagsForResource
              - route53:CreateHostedZone
              - route53:DeleteHostedZone
              - route53:GetChange
              - route53:GetHostedZone
              - route53:ListResourceRecordSets
              - route53:ListQueryLoggingConfigs
            Resource: '*'
            Effect: Allow
            Sid: Route53HostedZones
          - Action:
              - cloudformation:CreateStack
              - cloudformation:UpdateStack
            Resource: !Sub
              - arn:${AWS::Partition}:cloudformation:${RequestedRegion}:${AWS::AccountId}:stack/*
              - RequestedRegion: !If [IsMultiRegion, '*', !Ref Region]
            Effect: Allow
            Condition:
              ForAnyValue:StringEquals:
                aws:TagKeys: ["parallelcluster:cluster-name"]
            Sid: CloudFormationCreateAndUpdate
          - Action:
              - cloudformation:DeleteStack
              - cloudformation:DescribeStacks
              - cloudformation:DescribeStackEvents
              - cloudformation:DescribeStackResources
              - cloudformation:GetTemplate
              - cloudformation:ListStacks
            Resource: !Sub
              - arn:${AWS::Partition}:cloudformation:${RequestedRegion}:${AWS::AccountId}:stack/*
              - RequestedRegion: !If [IsMultiRegion, '*', !Ref Region]
            Effect: Allow
            Sid: CloudFormationReadAndDelete
          - Action:
              - cloudwatch:PutDashboard
              - cloudwatch:ListDashboards
              - cloudwatch:DeleteDashboards
              - cloudwatch:GetDashboard
              - cloudwatch:PutMetricAlarm
              - cloudwatch:DeleteAlarms
              - cloudwatch:DescribeAlarms
              - cloudwatch:PutCompositeAlarm
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: CloudWatch

  ParallelClusterClusterPolicy2:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterClusterPolicy2-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - iam:GetRole
              - iam:GetRolePolicy
              - iam:GetPolicy
              - iam:SimulatePrincipalPolicy
              - iam:GetInstanceProfile
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/*
              - !Sub arn:${AWS::Partition}:iam::aws:policy/*
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/*
            Effect: Allow
            Sid: IamRead
          - Action:
              - iam:CreateInstanceProfile
              - iam:DeleteInstanceProfile
              - iam:AddRoleToInstanceProfile
              - iam:RemoveRoleFromInstanceProfile
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/parallelcluster/*
            Effect: Allow
            Sid: IamInstanceProfile
          - Action:
              - iam:PassRole
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*
            Effect: Allow
            Condition:
              StringEqualsIfExists:
                iam:PassedToService:
                  - lambda.amazonaws.com
                  - ec2.amazonaws.com
                  - ec2.amazonaws.com.cn
                  - spotfleet.amazonaws.com
            Sid: IamPassRole
          - Action:
              - iam:CreateServiceLinkedRole
              - iam:DeleteServiceLinkedRole
            Resource: '*'
            Effect: Allow
            Condition:
              StringEquals:
                iam:AWSServiceName:
                  - fsx.amazonaws.com
                  - s3.data-source.lustre.fsx.amazonaws.com
                  - elasticloadbalancing.amazonaws.com
                  - autoscaling.amazonaws.com
          - Action:
              - lambda:CreateFunction
              - lambda:TagResource
              - lambda:DeleteFunction
              - lambda:GetFunctionConfiguration
              - lambda:GetFunction
              - lambda:InvokeFunction
              - lambda:AddPermission
              - lambda:RemovePermission
              - lambda:UpdateFunctionConfiguration
              - lambda:ListTags
              - lambda:UntagResource
            Resource:
              - !Sub arn:${AWS::Partition}:lambda:${Region}:${AWS::AccountId}:function:parallelcluster-*
              - !Sub arn:${AWS::Partition}:lambda:${Region}:${AWS::AccountId}:function:pcluster-*
            Effect: Allow
            Sid: Lambda
          - Action:
              - s3:*
            Resource:
              - !Sub arn:${AWS::Partition}:s3:::parallelcluster-*
              - !Sub arn:${AWS::Partition}:s3:::aws-parallelcluster-*
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: S3ResourcesBucket
          - Action:
              - s3:Get*
              - s3:List*
            Resource: !Sub arn:${AWS::Partition}:s3:::${Region}-aws-parallelcluster*
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: S3ParallelClusterReadOnly
          - Action:
              - fsx:*
            Resource:
              - !Sub arn:${AWS::Partition}:fsx:${Region}:${AWS::AccountId}:*
            Effect: Allow
            Sid: FSx
          - Action:
              - elasticfilesystem:*
            Resource:
              - !Sub arn:${AWS::Partition}:elasticfilesystem:${Region}:${AWS::AccountId}:*
            Effect: Allow
            Sid: EFS
          - Action:
              - logs:DeleteLogGroup
              - logs:PutRetentionPolicy
              - logs:DescribeLogGroups
              - logs:CreateLogGroup
              - logs:TagResource
              - logs:UntagResource
              - logs:DescribeMetricFilters
              - logs:PutMetricFilter
              - logs:deleteMetricFilter
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
            Sid: CloudWatchLogs
          - Action:
              - resource-groups:ListGroupResources
              - resource-groups:GetGroupConfiguration
            Resource: '*'
            Effect: Allow
            Sid: ResourceGroupRead
          - Action:
              - autoscaling:DeleteAutoScalingGroup
              - autoscaling:DeleteLifecycleHook
              - autoscaling:DescribeAutoScalingGroups
              - autoscaling:DescribeLifecycleHooks
              - autoscaling:DescribeScalingActivities
              - autoscaling:PutLifecycleHook
              - autoscaling:UpdateAutoScalingGroup
              - elasticloadbalancing:CreateListener
              - elasticloadbalancing:CreateTargetGroup
              - elasticloadbalancing:DescribeTags
              - elasticloadbalancing:DeleteListener
              - elasticloadbalancing:DeleteLoadBalancer
              - elasticloadbalancing:DeleteTargetGroup
              - elasticloadbalancing:DescribeListeners
              - elasticloadbalancing:DescribeLoadBalancers
              - elasticloadbalancing:DescribeTargetGroups
              - elasticloadbalancing:DescribeTargetHealth
              - elasticloadbalancing:ModifyLoadBalancerAttributes
            Resource: '*'
            Condition:
              ForAllValues:StringEquals:
                aws:TagKeys: [ "parallelcluster:cluster-name" ]
            Effect: Allow
            Sid: LoginNodesFunctionalities
          - Action:
              - autoscaling:CreateAutoScalingGroup
              - elasticloadbalancing:AddTags
              - elasticloadbalancing:CreateLoadBalancer
            Resource: '*'
            Effect: Allow
            Sid: LoginNodesFunctionalitiesNoCondition


  # ### IMAGE ACTIONS POLICIES

  ParallelClusterImageManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterImageManagedPolicy-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      Description: Managed policy to execute pcluster build-image, delete-image, list-images and describe-image commands
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: EC2BuildAndDeleteImage
            Effect: Allow
            Action:
              - ec2:DescribeImages
              - ec2:DescribeInstanceTypeOfferings
              - ec2:DescribeInstanceTypes
              - ec2:DeregisterImage
              - ec2:DeleteSnapshot
            Resource: '*'
          - Sid: IAMBuildImage
            Effect: Allow
            Action:
              - iam:CreateInstanceProfile
              - iam:AddRoleToInstanceProfile
              - iam:GetRole
              - iam:GetRolePolicy
              - iam:GetInstanceProfile
            Resource:
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/parallelcluster/*'
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/ParallelClusterImage*'
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*'
          - Sid: IAMPassRoleBuildImage
            Effect: Allow
            Action:
              - iam:PassRole
            Resource:
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/parallelcluster/*'
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*'
            Condition:
              StringEquals:
                iam:PassedToService:
                  - lambda.amazonaws.com
                  - ec2.amazonaws.com
                  - ec2.amazonaws.com.cn
          - Sid: CloudWatchBuildImage
            Effect: Allow
            Action:
              - logs:CreateLogGroup
              - logs:TagResource
              - logs:UntagResource
            Resource:
              - !Sub 'arn:${AWS::Partition}:logs:${Region}:${AWS::AccountId}:log-group:/aws/lambda/ParallelClusterImage-*'
          - Sid: CloudFormationBuildAndDeleteImage
            Effect: Allow
            Action:
              - cloudformation:DescribeStacks
              - cloudformation:CreateStack
              - cloudformation:DeleteStack
            Resource:
              - !Sub 'arn:${AWS::Partition}:cloudformation:${Region}:${AWS::AccountId}:stack/*'
          - Sid: LambdaBuildAndDeleteImage
            Effect: Allow
            Action:
              - lambda:RemovePermission
              - lambda:DeleteFunction
              - lambda:CreateFunction
              - lambda:TagResource
              - lambda:GetFunction
              - lambda:AddPermission
            Resource:
              - !Sub 'arn:${AWS::Partition}:lambda:${Region}:${AWS::AccountId}:function:ParallelClusterImage-*'
          - Sid: ImageBuilderGetBuildImage
            Effect: Allow
            Action:
              - imagebuilder:Get*
            Resource: '*'
          - Sid: ImageBuilderBuildAndDeleteImage
            Effect: Allow
            Action:
              - imagebuilder:CreateImage
              - imagebuilder:TagResource
              - imagebuilder:CreateImageRecipe
              - imagebuilder:CreateComponent
              - imagebuilder:CreateDistributionConfiguration
              - imagebuilder:CreateInfrastructureConfiguration
              - imagebuilder:DeleteImage
              - imagebuilder:GetImage
              - imagebuilder:CancelImageCreation
              - imagebuilder:DeleteComponent
              - imagebuilder:DeleteImageRecipe
              - imagebuilder:DeleteInfrastructureConfiguration
              - imagebuilder:DeleteDistributionConfiguration
            Resource:
              - !Sub 'arn:${AWS::Partition}:imagebuilder:${Region}:${AWS::AccountId}:image/parallelclusterimage-*'
              - !Sub 'arn:${AWS::Partition}:imagebuilder:${Region}:${AWS::AccountId}:image-recipe/parallelclusterimage-*'
              - !Sub 'arn:${AWS::Partition}:imagebuilder:${Region}:${AWS::AccountId}:component/parallelclusterimage-*'
              - !Sub 'arn:${AWS::Partition}:imagebuilder:${Region}:${AWS::AccountId}:distribution-configuration/parallelclusterimage-*'
              - !Sub 'arn:${AWS::Partition}:imagebuilder:${Region}:${AWS::AccountId}:infrastructure-configuration/parallelclusterimage-*'
          - Sid: SNSBuildAndDeleteImage
            Effect: Allow
            Action:
              - sns:GetTopicAttributes
              - sns:TagResource
              - sns:CreateTopic
              - sns:Subscribe
              - sns:Publish
              - SNS:DeleteTopic
              - SNS:Unsubscribe
            Resource:
              - !Sub 'arn:${AWS::Partition}:sns:${Region}:${AWS::AccountId}:ParallelClusterImage-*'
          - Sid: IAMSLRBuildImage
            Action:
              - iam:CreateServiceLinkedRole
            Resource:
              - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/imagebuilder.amazonaws.com/AWSServiceRoleForImageBuilder
            Effect: Allow
            Condition:
              StringLike:
                iam:AWSServiceName:
                  - imagebuilder.amazonaws.com
          - Sid: IAMDeleteImage
            Effect: Allow
            Action:
              - iam:RemoveRoleFromInstanceProfile
            Resource:
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/parallelcluster/*'
              - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/parallelcluster/*'
          - Sid: S3BucketBuildAndDeleteImage
            Effect: Allow
            Action:
              - s3:PutObject
              - s3:GetObject
              - s3:GetObjectVersion
              - s3:DeleteObject
              - s3:DeleteObjectVersion
              - s3:CreateBucket
              - s3:ListBucket
              - s3:ListBucketVersions
            Resource:
              - !Sub 'arn:${AWS::Partition}:s3:::parallelcluster-*/*'
          - Sid: CloudWatchDeleteImage
            Effect: Allow
            Action:
              - logs:DeleteLogGroup
            Resource:
              - !Sub 'arn:${AWS::Partition}:logs:${Region}:${AWS::AccountId}:log-group:/aws/imagebuilder/ParallelClusterImage-*'
              - !Sub 'arn:${AWS::Partition}:logs:${Region}:${AWS::AccountId}:log-group:/aws/lambda/ParallelClusterImage-*'
          - Sid: CloudFormationListImages
            Effect: Allow
            Action:
              - cloudformation:DescribeStacks
            Resource:
              - '*'

  ### LOG COMMANDS

  ParallelClusterLogRetrievalPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub
        - ${IAMRoleAndPolicyPrefix}ParallelClusterLogRetrievalPolicy-${StackIdSuffix}
        - { StackIdSuffix: !Select [ 0, !Split [ '-', !Select [ 2, !Split [ '/', !Ref 'AWS::StackId' ] ] ] ] }
      Description: Policies needed to retrieve cluster and images logs
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
            - logs:DescribeLogGroups
            - logs:FilterLogEvents
            - logs:GetLogEvents
            - logs:CreateExportTask
            - logs:DescribeLogStreams
            - logs:DescribeExportTasks
            Resource: '*'
            Effect: Allow
            Condition: !If
              - IsMultiRegion
              - !Ref AWS::NoValue
              - StringEquals:
                  aws:RequestedRegion:
                    - !Ref Region
