--- AWSTemplateFormatVersion: '2010-09-09' Description: 'Atlan AWS Infrastructure CloudFormation Template' Metadata: AWS::CloudFormation::Interface: ParameterLabels: VPCCIDR: default: "VPC CIDR" PublicSubnet1ACIDR: default: "CIDR for Public Subnet A" PublicSubnet1BCIDR: default: "CIDR for Public Subnet B" PrivateSubnet1ACIDR: default: "CIDR for Private Subnet A" PrivateSubnet1BCIDR: default: "CIDR for Private Subnet B" KeyName: default: "Key Name" licenseSignedUrl: default: "License URL" AdditionalEKSAdminArns: default: "AWS IAM User ARN to access EKS cluster through Kubectl. provide comma separated list" atlanInstanceType: default: "EC2 instance type" atlanMinNode: default: "Minimum EC2 instance count to run in EKS" atlanMaxNode: default: "Maximum EC2 instance count to run in EKS" atlansparkInstanceType: default: "Spark EC2 instance type" atlansparkMinNode: default: "Minimum EC2 instance count to run for Spark" atlansparkMaxNode: default: "Maximum EC2 instance count to run for Spark" EksServiceIPCIDR: default: "IP CIDR to be used by EKS cluster" ParameterGroups: - Label: default: "General Configurations" Parameters: - KeyName - licenseSignedUrl - Label: default: "Advanced Configurations" - Label: default: "Network Configuration" Parameters: - VPCCIDR - PublicSubnet1ACIDR - PublicSubnet1BCIDR - PrivateSubnet1ACIDR - PrivateSubnet1BCIDR - Label: default: "EKS Configuration" Parameters: - AdditionalEKSAdminArns - EksServiceIPCIDR - atlanInstanceType - atlanMinNode - atlanMaxNode - atlansparkInstanceType - atlansparkMinNode - atlansparkMaxNode Parameters: VPCCIDR: Description: | Creates New VPC CIDR block. Please ensure the CIDR Range is different from that of your existing VPC that might need to be peered with Atlan's VPC. Also do not overlap with any CIDR block assigned to the IP CIDR to be used by the EKS cluster. Type: String Default: 10.0.0.0/16 AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ PublicSubnet1ACIDR: Description: Public Subnet 1a CIDR block for New VPC Type: String Default: 10.0.0.0/24 AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ PublicSubnet1BCIDR: Description: Public Subnet 1b CIDR block for New VPC Type: String Default: 10.0.1.0/24 AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ PrivateSubnet1ACIDR: Description: Private Subnet 1a CIDR block for New VPC Type: String Default: 10.0.2.0/24 AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ PrivateSubnet1BCIDR: Description: Private Subnet 1b CIDR block for New VPC Type: String Default: 10.0.3.0/24 AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ KeyName: Description: EC2 Key Name Type: AWS::EC2::KeyPair::KeyName AllowedPattern: ".+" AdditionalEKSAdminArns: Type: CommaDelimitedList licenseSignedUrl: Type: String Description: 'HTTP URL of License which you received from Atlan like https://atlan.s3.ap-south-1.amazonaws.com/trial-lite.yaml?X-Amz-Algorithm=A............' atlanInstanceType: Type: String Default: t3a.2xlarge Description: "Instance Type for Atlan Nodes" AllowedValues: - t2.2xlarge - t3.2xlarge - t3a.2xlarge - m4.2xlarge - m5.2xlarge - m5a.2xlarge - m4.4xlarge - m5.4xlarge - m5a.4xlarge atlanMinNode: Type: Number Default: 4 MinValue: 3 atlanMaxNode: Type: Number Default: 10 MinValue: 6 atlansparkInstanceType: Type: String Default: t3a.xlarge Description: "Instance Type for Spark Nodes" AllowedValues: - t2.xlarge - t3.xlarge - t3a.xlarge - m4.xlarge - m5.xlarge - m5a.xlarge - t2.2xlarge - t3.2xlarge - t3a.2xlarge - m4.2xlarge - m5.2xlarge - m5a.2xlarge - m4.4xlarge - m5.4xlarge - m5a.4xlarge atlansparkMinNode: Type: Number Default: 1 MinValue: 1 atlansparkMaxNode: Type: Number Default: 5 MinValue: 1 EksServiceIPCIDR: Type: String Default: "172.20.0.0/16" AllowedPattern: ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,3}$ Description: "The CIDR block to assign Kubernetes service IP addresses from. If you don't specify a block, Kubernetes assigns addresses 172.20.0.0/16 CIDR. We recommend that you specify a block that does not overlap with resources in other networks that are peered or connected to your VPC. The block must meet the following requirements: A)Within one of the following private IP address blocks: 10.0.0.0/8, 172.16.0.0.0/12, or 192.168.0.0/16. B)Doesn't overlap with any CIDR block assigned to the VPC that you selected for VPC. C)Between /24 and /12." Resources: # Permissions needed but not tied to a specific resource on the Stack: #aws-permission @cft cloudformation:CreateStack VPC: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/vpc.yaml Parameters: environment: "production" VPCCIDR: !Ref VPCCIDR PublicSubnet1BCIDR: !Ref PublicSubnet1BCIDR PublicSubnet1ACIDR: !Ref PublicSubnet1ACIDR PrivateSubnet1BCIDR: !Ref PrivateSubnet1BCIDR PrivateSubnet1ACIDR: !Ref PrivateSubnet1ACIDR PrimaryStackName: !Sub ${AWS::StackName} validationLambda: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-lambda-validation.yaml Parameters: licenseSignedUrl: !Ref licenseSignedUrl PrimaryStackName: !Sub ${AWS::StackName} minNode: !Ref atlanMinNode maxNode: !Ref atlanMaxNode ODpercentage: "30" registerEksResource: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-resource.template.yaml Parameters: EksResourceCreateLambdaArn: !GetAtt validationLambda.Outputs.EksResourceCreateLambdaArn createLogDelivaryRole: !GetAtt validationLambda.Outputs.createLogDelivaryRole createExecutionRole: !GetAtt validationLambda.Outputs.createExecutionRole environment: "production" PrimaryStackName: !Sub ${AWS::StackName} S3DatalakeBucket: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/s3-datalake.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} s3BucketNamePrefix: !GetAtt validationLambda.Outputs.transformedBucketName VpcId: !GetAtt VPC.Outputs.VPCID PublicRouteTable: !GetAtt VPC.Outputs.PublicRouteTable PrivateRouteTable: !GetAtt VPC.Outputs.PrivateRouteTable KubernetesEbsTaggingLambda: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-lambda-k8s-ebs-tagging.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} EKSIamStack: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-iam.template.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} BucketName: atlan-aws-marketplace S3BackupBucket: !GetAtt S3DatalakeBucket.Outputs.S3BackupBucket S3DatalakeBucket: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket vpcId: !GetAtt VPC.Outputs.VPCID EKSFunctionStack: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-functions.template.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} EKSProvisionRoleArn: !GetAtt EKSIamStack.Outputs.ControlPlaneProvisionRoleArn ControlPlaneSecurityGroup: !GetAtt VPC.Outputs.ControlPlaneSecurityGroup EKSSubnetIds: !Join - ',' - - !GetAtt VPC.Outputs.PrivateSubnet1a - !GetAtt VPC.Outputs.PrivateSubnet1b QuickStartStackMakerRoleArn: !GetAtt EKSIamStack.Outputs.QuickStartStackMakerRoleArn DeleteLambdaZipsBucketContents: "False" VPCID: !GetAtt VPC.Outputs.VPCID KubeConfigUploadRoleArn: !GetAtt EKSIamStack.Outputs.KubeConfigUploadRoleArn CleanupLoadBalancersRoleArn: !GetAtt EKSIamStack.Outputs.CleanupLoadBalancersRoleArn CleanupSecurityGroupDependenciesRoleArn: !GetAtt EKSIamStack.Outputs.CleanupSecurityGroupDependenciesRoleArn GetCallerArnRoleArn: !GetAtt EKSIamStack.Outputs.GetCallerArnRoleArn KmsKey: Type: "AWS::KMS::Key" DependsOn: EKSIamStack Properties: Tags: - { Key: Name, Value: !Sub "atlan-kms" } - { Key: "atlan:resource", Value: "kms" } - { Key: "atlan:owner", Value: "atlan" } - { Key: "atlan:environment", Value: "production" } - { Key: "stack:name", Value: !Sub "${AWS::StackName}" } EnableKeyRotation: true KeyPolicy: { "Version": "2012-10-17", "Id": "key-default-1", "Statement": [ { "Sid": "root access", "Effect": "Allow", "Principal": {"AWS": !Sub "arn:aws:iam::${AWS::AccountId}:root"}, "Action": "kms:*", "Resource": "*" }, { "Sid": "lambda encrypt", "Effect": "Allow", "Principal": {"AWS": !GetAtt EKSIamStack.Outputs.KubeConfigUploadRoleArn}, "Action": "kms:encrypt", "Resource": "*" }, { "Sid": "lambda decrypt", "Effect": "Allow", "Principal": {"AWS": !GetAtt EKSIamStack.Outputs.ControlPlaneProvisionRoleArn}, "Action": "kms:decrypt", "Resource": "*" } ] } NodeSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress DependsOn: EKSControlPlane Properties: Description: Allow EKS managed nodegroup nodes to communicate with each other in the cluster GroupId: !GetAtt VPC.Outputs.NodeSecurityGroup SourceSecurityGroupId: !GetAtt EKSControlPlane.Outputs.EksSecurityGroup IpProtocol: '-1' FromPort: 0 ToPort: 65535 EksNodeSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress DependsOn: EKSControlPlane Properties: Description: Allow EKS managed nodegroup nodes to communicate with each other in the cluster GroupId: !GetAtt EKSControlPlane.Outputs.EksSecurityGroup SourceSecurityGroupId: !GetAtt VPC.Outputs.NodeSecurityGroup IpProtocol: '-1' FromPort: 0 ToPort: 65535 EKSControlPlane: Type: "AWS::CloudFormation::Stack" DependsOn: registerEksResource Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-controlplane.template.yaml Parameters: environment: "production" SecurityGroupIds: !GetAtt VPC.Outputs.ControlPlaneSecurityGroup SubnetIds: !Join - ',' - - !GetAtt VPC.Outputs.PublicSubnet1a - !GetAtt VPC.Outputs.PublicSubnet1b RoleArn: !GetAtt EKSIamStack.Outputs.ControlPlaneRoleArn EKSProvisionRoleArn: !GetAtt EKSIamStack.Outputs.ControlPlaneProvisionRoleArn NodeInstanceRoleArn: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleArn KubeManifestAtlanLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeManifestAtlanLambdaArn KmsKeyArn: !GetAtt KmsKey.Arn KubeConfigUploadRoleArn: !GetAtt EKSIamStack.Outputs.KubeConfigUploadRoleArn KubeConfigUploadLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeConfigUploadLambdaArn KubeConfigS3Bucket: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket AdditionalEKSAdminArns: !Join [ ",", !Ref AdditionalEKSAdminArns ] KubernetesVersion: 1.19 KmsContext: "Atlan" CleanupLoadBalancersLambdaArn: !GetAtt EKSFunctionStack.Outputs.CleanupLoadBalancersLambdaArn GetCallerArnLambdaArn: !GetAtt EKSFunctionStack.Outputs.GetCallerArnLambdaArn PrimaryStackName: !Sub ${AWS::StackName} ServiceIpCidr: !Ref EksServiceIPCIDR # Managed Nodegroups atlanManagedGroupStackSPOT: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-managednodegroup.template.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} KeyPairName: !Ref 'KeyName' PrivateSubnet1ID: !GetAtt VPC.Outputs.PrivateSubnet1a PrivateSubnet2ID: !GetAtt VPC.Outputs.PrivateSubnet1b VPCID: !GetAtt VPC.Outputs.VPCID NodeInstanceType: !Ref atlanInstanceType NumberOfNodes: !GetAtt validationLambda.Outputs.minNodeSpot MaxNumberOfNodes: !GetAtt validationLambda.Outputs.maxNodeSpot NodeGroupName: atlan-node-spot NodeVolumeSize: 25 NodeInstanceCapacity: SPOT #!Ref atlanInstanceCapacity EKSControlPlane: !GetAtt EKSControlPlane.Outputs.EKSName ControlPlaneSecurityGroup: !GetAtt VPC.Outputs.ControlPlaneSecurityGroup NodeSecurityGroup: !GetAtt VPC.Outputs.NodeSecurityGroup NodeInstanceProfile: !GetAtt EKSIamStack.Outputs.NodeInstanceProfileArn NodeInstanceRoleName: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleName NodeInstanceRoleArn: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleArn atlanManagedGroupStackOD: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-managednodegroup.template.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} KeyPairName: !Ref 'KeyName' PrivateSubnet1ID: !GetAtt VPC.Outputs.PrivateSubnet1a PrivateSubnet2ID: !GetAtt VPC.Outputs.PrivateSubnet1b VPCID: !GetAtt VPC.Outputs.VPCID NodeInstanceType: !Ref atlanInstanceType NumberOfNodes: !GetAtt validationLambda.Outputs.minNodeOD MaxNumberOfNodes: !GetAtt validationLambda.Outputs.maxNodeOD NodeGroupName: atlan-node-od NodeVolumeSize: 25 NodeInstanceCapacity: ON_DEMAND #!Ref atlanInstanceCapacity EKSControlPlane: !GetAtt EKSControlPlane.Outputs.EKSName ControlPlaneSecurityGroup: !GetAtt VPC.Outputs.ControlPlaneSecurityGroup NodeSecurityGroup: !GetAtt VPC.Outputs.NodeSecurityGroup NodeInstanceProfile: !GetAtt EKSIamStack.Outputs.NodeInstanceProfileArn NodeInstanceRoleName: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleName NodeInstanceRoleArn: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleArn atlanSparkManagedGroupStack: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/amazon-eks-managednodegroup.template.yaml Parameters: environment: "production" PrimaryStackName: !Sub ${AWS::StackName} KeyPairName: !Ref 'KeyName' PrivateSubnet1ID: !GetAtt VPC.Outputs.PrivateSubnet1a PrivateSubnet2ID: !GetAtt VPC.Outputs.PrivateSubnet1b VPCID: !GetAtt VPC.Outputs.VPCID NodeInstanceType: !Ref atlansparkInstanceType NumberOfNodes: !Ref atlansparkMinNode MaxNumberOfNodes: !Ref atlansparkMaxNode NodeGroupName: atlan-spark NodeVolumeSize: 25 NodeInstanceCapacity: SPOT #!Ref atlanInstanceCapacity EKSControlPlane: !GetAtt EKSControlPlane.Outputs.EKSName ControlPlaneSecurityGroup: !GetAtt VPC.Outputs.ControlPlaneSecurityGroup NodeSecurityGroup: !GetAtt VPC.Outputs.NodeSecurityGroup NodeInstanceProfile: !GetAtt EKSIamStack.Outputs.NodeInstanceProfileArn NodeInstanceRoleName: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleName NodeInstanceRoleArn: !GetAtt EKSIamStack.Outputs.NodeInstanceRoleArn installNginx: Type: "AWS::CloudFormation::Stack" DependsOn: [EKSControlPlane] Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/nginx-kots-service.yaml Parameters: KubeManifestLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeManifestAtlanLambdaArn KubeGetLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeGetLambdaArn sleepFunctionArnLambdaArn: !GetAtt EKSFunctionStack.Outputs.sleepFunctionArnLambdaArn tagElbLambdaArn: !GetAtt EKSFunctionStack.Outputs.tagElbLambdaArn environment: "production" PrimaryStackname: !Sub ${AWS::StackName} KubeConfigS3Bucket: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket KubeConfigS3Key: ".kube/config.enc" KmsContext: "Atlan" natgateway: !GetAtt VPC.Outputs.NATGATEWAYIP createCloudfront: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/cloudfront.yaml Parameters: environment: "production" PrimaryStackname: !Sub ${AWS::StackName} NginxElbAddress: !GetAtt installNginx.Outputs.nginxElbDns AdminConsoleElbAddress: !GetAtt installNginx.Outputs.KotsAdmEndPoint BucketName: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket installKots: Type: "AWS::CloudFormation::Stack" Properties: TemplateURL: https://atlan.s3.ap-south-1.amazonaws.com/deploy/marketplace/container/templates/kots-deployment.yaml Parameters: PrimaryStackname: !Sub ${AWS::StackName} licenseSignedUrl: !Ref licenseSignedUrl KubeManifestLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeManifestAtlanLambdaArn KubeConfigS3Bucket: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket KubeConfigS3Key: ".kube/config.enc" KmsContext: "Atlan" KubeGetLambdaArn: !GetAtt EKSFunctionStack.Outputs.KubeGetLambdaArn domainName: !GetAtt createCloudfront.Outputs.Cloudfrontdomain BackupBucket: !GetAtt S3DatalakeBucket.Outputs.S3BackupBucket BackupIamRole: !GetAtt EKSIamStack.Outputs.BackupRole BucketName: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket sleepFunctionArnLambdaArn: !GetAtt EKSFunctionStack.Outputs.sleepFunctionArnLambdaArn deploymentType: "production" KeycloakUUID: !GetAtt validationLambda.Outputs.keycloakuuid Outputs: ReleasePortalURL: Description: Release portal is used to manage and configure Atlan product releases. Value: !GetAtt createCloudfront.Outputs.CloudfrontAdminConsoleDomain ReleasePortalPassword: Description: Password for the Atlan Release Portal. Value: !GetAtt installKots.Outputs.ReleasePortalPassword VPCID: Description: VPC ID for the Atlan VPC used to deploy all AWS resources. Value: !GetAtt VPC.Outputs.VPCID NATGatewayIP: Description: Used to allow internet connectivity to the instances in the private subnet. Value: !GetAtt VPC.Outputs.NATGATEWAYIP AtlanProductURL: Description: Domain name for Atlan product. Value: !GetAtt createCloudfront.Outputs.Cloudfrontdomain S3BackupBucket: Description: S3 bucket used to store Atlan databases backup. Value: !GetAtt S3DatalakeBucket.Outputs.S3BackupBucket S3IAMRole: Description: IAM Role used to sync data from Atlan EC2 instance to Atlan S3 buckets. Value: !GetAtt EKSIamStack.Outputs.BackupRole EKSClusterName: Description: Name of the Atlan EKS cluster, where all services are deployed. Value: !Sub ${AWS::StackName} S3Bucket: Description: S3 Bucket used to store Atlan services logs and images. Value: !GetAtt S3DatalakeBucket.Outputs.S3DatalakeBucket DefaultBucketRegion: Description: AWS Region in which bucket is created. Value: !Sub "${AWS::Region}" KeycloakUUID: Description: UUID(Universally unique identifier) for Keycloak, used in product configuration. Value: !GetAtt validationLambda.Outputs.keycloakuuid