AWSTemplateFormatVersion: '2010-09-09' Description: OpenSearchDomain resource Parameters: DomainName: Description: User defined OpenSearch Domain name Type: String Default: 'clip-domain' OpenSearchInstanceType: Description: Instance type of the opensearch domain Type: String Default: 't3.small.search' EnvironmentName: Description: An environment name that is prefixed to resource names Type: String Default: clip-env- VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Default: 10.192.0.0/16 PublicSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone Type: String Default: 10.192.10.0/24 PublicSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone Type: String Default: 10.192.11.0/24 PrivateSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone Type: String Default: 10.192.20.0/24 PrivateSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone Type: String Default: 10.192.21.0/24 Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Ref EnvironmentName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref EnvironmentName InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PublicSubnet1CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Subnet (AZ1) PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PublicSubnet2CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Subnet (AZ2) PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet1CIDR MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub ${EnvironmentName} Private Subnet (AZ1) PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet2CIDR MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub ${EnvironmentName} Private Subnet (AZ2) NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName} Public Routes DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName} Private Routes (AZ1) DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName} Private Routes (AZ2) DefaultPrivateRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable2 SubnetId: !Ref PrivateSubnet2 SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: "self-security-group" GroupDescription: "Security group with a self-referencing inbound rule." VpcId: !Ref VPC SecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref SecurityGroup IpProtocol: "-1" SourceSecurityGroupId: !Ref SecurityGroup SelfDefaultSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt VPC.DefaultSecurityGroup IpProtocol: "-1" SourceSecurityGroupId: !GetAtt VPC.DefaultSecurityGroup Key: Type: AWS::KMS::Key Properties: Enabled: true KeyPolicy: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: "*" Action: - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey* - kms:CreateGrant - kms:DescribeKey Resource: "*" Condition: StringEquals: kms:ViaService: !Sub "es.${AWS::Region}.amazonaws.com" kms:CallerAccount: !Ref AWS::AccountId - Effect: Allow Principal: AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" Action: "*" Resource: "*" - Effect: Allow Principal: Service: es.amazonaws.com Action: - kms:Describe* - kms:Get* - kms:List* Resource: "*" SlowLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: 90 LogGroupName: /aws/opensearch/domains/opensearch-slow-logs CloudWatchApplicationResourcePolicy: Type: AWS::Logs::ResourcePolicy Properties: PolicyName: "EsResourcePolicy" PolicyDocument: '{"Version": "2012-10-17","Statement":[{"Effect":"Allow","Principal": {"Service": ["es.amazonaws.com"]},"Action":["logs:PutLogEvents","logs:CreateLogStream"],"Resource":"*"}]}' OpensearchDomain: Type: 'AWS::OpenSearchService::Domain' Properties: DomainName: Ref: DomainName EngineVersion: 'OpenSearch_1.3' ClusterConfig: InstanceCount: '2' ZoneAwarenessEnabled: true DedicatedMasterEnabled: true InstanceType: Ref: OpenSearchInstanceType EBSOptions: EBSEnabled: 'true' Iops: 0 VolumeSize: 10 VolumeType: gp2 SnapshotOptions: AutomatedSnapshotStartHour: '0' AccessPolicies: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' Action: 'es:*' Resource: !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${DomainName}/*' - Effect: Allow Principal: AWS: !GetAtt SageMakerExecutionRole.Arn Action: 'es:*' Resource: !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/${DomainName}/*' AdvancedOptions: rest.action.multi.allow_explicit_index: 'true' EncryptionAtRestOptions: Enabled: true KmsKeyId: !Ref Key NodeToNodeEncryptionOptions: Enabled: true VPCOptions: SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 LogPublishingOptions: SEARCH_SLOW_LOGS: CloudWatchLogsLogGroupArn: !GetAtt SlowLogGroup.Arn Enabled: true Tags: - Key: Name Value: Ref: DomainName #================================================================================ # IAM ROLES #================================================================================ SageMakerExecutionRole: Type: AWS::IAM::Role Properties: Policies: - PolicyName: s3-access PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:GetObject - s3:PutObject - s3:DeleteObject - s3:ListBucket Resource: arn:aws:s3:::* - PolicyName: iam-access PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - iam:GetRole - iam:GetRolePolicy Resource: '*' - PolicyName: opensearch-access PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - es:ESHttpDelete - es:ESHttpGet - es:ESHttpHead - es:ESHttpPost - es:ESHttpPut Resource: '*' AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - sagemaker.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess - arn:aws:iam::aws:policy/AmazonS3FullAccess - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess StudioDomain: Type: AWS::SageMaker::Domain Properties: AppNetworkAccessType: VpcOnly AuthMode: IAM DefaultUserSettings: ExecutionRole: !GetAtt SageMakerExecutionRole.Arn SecurityGroups: - !GetAtt VPC.DefaultSecurityGroup DomainName: studio-domain SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 VpcId: !Ref VPC StudioUser: Type: AWS::SageMaker::UserProfile Properties: DomainId: !GetAtt StudioDomain.DomainId UserProfileName: clip-user Outputs: DomainArn: Value: 'Fn::GetAtt': - OpensearchDomain - DomainArn DomainEndpoint: Value: 'Fn::GetAtt': - OpensearchDomain - DomainEndpoint SageMakerExecutionRoleArn: Value: 'Fn::GetAtt': - SageMakerExecutionRole - Arn