--- AWSTemplateFormatVersion: '2010-09-09' Description: >- CloudGen Access Proxy Cloudformation template Creates ECS containers in AWS Fargate infrastructure Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: CloudGen Access Configuration Parameters: - cloudgenAccessProxyToken - cloudgenAccessProxyPublicPort - Label: default: Network Configuration Parameters: - vpcId - publicSubnets - Label: default: Container Configuration Parameters: - orchestratorDesiredCapacity - envoyDesiredCapacity - Label: default: Logging Parameters: - cloudgenAccessProxyLoglevel - logRetentionDays ParameterLabels: cloudgenAccessProxyToken: default: CloudGen Access Proxy Token cloudgenAccessProxyPublicPort: default: CloudGen Access Proxy public port vpcId: default: Vpc Id publicSubnets: default: Public subnets for containers orchestratorDesiredCapacity: default: Number of containers for Orchestrator envoyDesiredCapacity: default: Number of containers for Envoy cloudgenAccessProxyLoglevel: default: Log level for the application logRetentionDays: default: Log Retention Parameters: cloudgenAccessProxyToken: Description: CloudGen Access Proxy Token for this proxy (obtained from the console after proxy creation) Type: String MinLength: 20 NoEcho: true # yamllint disable-line rule:line-length AllowedPattern: ^https:\/\/[a-zA-Z0-9.-]+\.(fyde\.com|access\.barracuda\.com)\/proxies/v[0-9]+\/enrollment\/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\?proxy_auth_token=[0-9a-zA-Z]+&tenant_id=[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$ cloudgenAccessProxyPublicPort: Description: Public port for this proxy (must match the value configured in the console for this proxy) Default: 443 Type: Number MinValue: 1 MaxValue: 65535 cloudgenAccessProxyLoglevel: Description: >- Set the CloudGen Access Proxy orchestrator log level. Default is info. Type: String Default: info AllowedValues: - debug - info - warning - error - critical vpcId: Type: AWS::EC2::VPC::Id Description: Select the Virtual Private Cloud (VPC) to use ConstraintDescription: >- must be the VPC Id of an existing Virtual Private Cloud. Outbound traffic for the default security group associated with this VPC should be enabled. publicSubnets: Type: 'List' Description: 'Select the SubnetIds to use. NOTE: Use Public Subnets only' ConstraintDescription: >- recomended to be a list of at least two existing subnets associated with at least two different availability zones. They should be residing in the selected Virtual Private Cloud and should allow access to internet orchestratorDesiredCapacity: Description: Enter the desired capacity for the Orchestrator nodes Default: 2 Type: Number MinValue: 1 envoyDesiredCapacity: Description: Enter the desired capacity for the Envoy nodes Default: 2 Type: Number MinValue: 1 logRetentionDays: Description: Days to keep container logs on Cloudwatch (0 = never delete) Type: Number Default: 7 AllowedValues: - 0 - 1 - 3 - 5 - 7 - 14 - 30 - 60 - 90 - 120 - 150 - 180 - 365 - 400 - 545 - 731 - 1827 - 3653 Conditions: logGroupNoDelete: !Equals [!Ref logRetentionDays, 0] createRedis: !Not [!Equals [!Ref orchestratorDesiredCapacity, 1]] Resources: ## ## Secrets ## cloudGenAccessEnrollmentToken: Type: AWS::SecretsManager::Secret DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: Name: !Join [ '_', !Split [ '-', !Sub '${AWS::StackName}_enrollment_token' ] ] Description: CloudGen Access Proxy Enrollment Token SecretString: !Ref cloudgenAccessProxyToken Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: orchestrator - Key: Platform Value: ecsFargate ## ## Discovery and Logging ## privateNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Sub '${AWS::StackName}-cloudgenaccessproxy' Vpc: !Ref vpcId logGroup: Type: AWS::Logs::LogGroup DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: LogGroupName: !Sub '/aws/ecs/${AWS::StackName}-CloudGenAccessProxy' RetentionInDays: !If [logGroupNoDelete, !Ref 'AWS::NoValue', !Ref logRetentionDays] ## ## Network Load Balancer ## nlb: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: !Ref publicSubnets Scheme: internet-facing Type: network Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate nlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref nlbTargetGroup LoadBalancerArn: !Ref nlb Port: !Ref cloudgenAccessProxyPublicPort Protocol: TCP nlbTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup DependsOn: nlb Properties: HealthCheckIntervalSeconds: 30 HealthyThresholdCount: 3 Port: !Ref cloudgenAccessProxyPublicPort Protocol: TCP UnhealthyThresholdCount: 3 TargetType: ip VpcId: !Ref vpcId Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate ## ## Security Groups ## inboundSg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow inbound access to CloudGen Access Proxy on the configured port SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref cloudgenAccessProxyPublicPort ToPort: !Ref cloudgenAccessProxyPublicPort CidrIp: 0.0.0.0/0 VpcId: !Ref vpcId Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate orchestratorSg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow access to Orchestrator SecurityGroupIngress: - IpProtocol: tcp FromPort: 50051 ToPort: 50051 SourceSecurityGroupId: !Ref envoySg VpcId: !Ref vpcId Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: orchestrator - Key: Platform Value: ecsFargate redisSg: Type: AWS::EC2::SecurityGroup Condition: createRedis Properties: GroupDescription: Allow access to redis SecurityGroupIngress: - IpProtocol: tcp FromPort: 6379 ToPort: 6379 SourceSecurityGroupId: !Ref orchestratorSg VpcId: !Ref vpcId Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: redis - Key: Platform Value: ecsFargate envoySg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow Envoy proxy access to internal resources VpcId: !Ref vpcId Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate ## ## ECS Cluster and Global Role ## ecsCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub '${AWS::StackName}-CloudGenAccessProxy' Tags: - Key: Name Value: !Sub '${AWS::StackName}-CloudGenAccessProxy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: cloudGenAccessProxy - Key: Platform Value: ecsFargate taskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - 'sts:AssumeRole' ## ## Orchestrator ## orchestratorEcsTask: Type: AWS::ECS::TaskDefinition Metadata: cfn-lint: config: ignore_checks: - E3012 Properties: Cpu: '256' Memory: '0.5GB' ExecutionRoleArn: !GetAtt orchestratorRole.Arn NetworkMode: awsvpc RequiresCompatibilities: - FARGATE TaskRoleArn: !Ref taskRole ContainerDefinitions: - Name: !Sub '${AWS::StackName}-cloudgenAccessOrchestrator' Image: fydeinc/fydeproxy:latest Environment: - Name: FYDE_PREFIX Value: !Join [ '_', !Split [ '-', !Sub '${AWS::StackName}' ] ] - Name: FYDE_ENVOY_LISTENER_PORT Value: !Ref cloudgenAccessProxyPublicPort - Name: FYDE_LOGLEVEL Value: !Ref cloudgenAccessProxyLoglevel - !If - createRedis - Name: FYDE_REDIS_HOST Value: !Sub - ${redisDiscoveryService}.${AWS::StackName}-cloudgenaccessproxy - { redisDiscoveryService: !GetAtt redisDiscoveryService.Name } - !Ref AWS::NoValue - !If - createRedis - Name: FYDE_REDIS_PORT Value: 6379 - !Ref AWS::NoValue PortMappings: - ContainerPort: 50051 HostPort: 50051 Protocol: tcp Secrets: - Name: FYDE_ENROLLMENT_TOKEN ValueFrom: !Ref cloudGenAccessEnrollmentToken HealthCheck: Command: - CMD-SHELL - /usr/bin/nc -zv 127.0.0.1 50051 Interval: 5 Retries: 3 StartPeriod: 15 Timeout: 10 Essential: true LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref logGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: !Sub '/aws/ecs/${AWS::StackName}-CloudGenAccessProxy' Tags: - Key: Name Value: !Sub '${AWS::StackName}-cloudgenAccessOrchestrator' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: orchestrator - Key: Platform Value: ecsFargate orchestratorEcsService: Type: AWS::ECS::Service Properties: ServiceName: !Sub '${AWS::StackName}-cloudgenAccessOrchestrator' Cluster: !Ref ecsCluster NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref orchestratorSg Subnets: !Ref publicSubnets DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: !Ref orchestratorDesiredCapacity EnableECSManagedTags: false LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt orchestratorDiscoveryService.Arn ContainerName: orchestrator SchedulingStrategy: REPLICA TaskDefinition: !Ref orchestratorEcsTask Tags: - Key: Name Value: !Sub '${AWS::StackName}-cloudgenAccessOrchestrator' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: orchestrator - Key: Platform Value: ecsFargate orchestratorDiscoveryService: Type: AWS::ServiceDiscovery::Service Properties: Name: orchestrator Description: Discovery service for the CloudGen orchestrator service DnsConfig: RoutingPolicy: WEIGHTED DnsRecords: - TTL: 60 Type: A HealthCheckCustomConfig: FailureThreshold: 1 NamespaceId: !Ref privateNamespace orchestratorRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: - I3042 Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - 'sts:AssumeRole' Policies: - PolicyName: orchestratorSecrets PolicyDocument: Statement: - Effect: Allow Action: - 'secretsmanager:DescribeSecret' - 'secretsmanager:GetSecretValue' Resource: !Sub - 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Value}_*' - { Value: !Join [ '_', !Split [ '-', !Sub '${AWS::StackName}' ] ] } - Effect: Allow Action: - 'secretsmanager:ListSecrets' Resource: '*' - PolicyName: orchestratorLogStream PolicyDocument: Statement: - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: !GetAtt logGroup.Arn ## ## redis ## redisEcsTask: Type: AWS::ECS::TaskDefinition Condition: createRedis Properties: Cpu: '256' Memory: '0.5GB' ExecutionRoleArn: !GetAtt redisRole.Arn NetworkMode: awsvpc RequiresCompatibilities: - FARGATE TaskRoleArn: !Ref taskRole ContainerDefinitions: - Name: !Sub '${AWS::StackName}-cloudgenAccessRedis' Image: redis:5 PortMappings: - ContainerPort: 6379 HostPort: 6379 Protocol: tcp HealthCheck: Command: - redis-cli - PING Interval: 5 Retries: 3 StartPeriod: 15 Timeout: 10 Essential: true LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref logGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: !Sub '/aws/ecs/${AWS::StackName}-CloudGenAccessProxy' Tags: - Key: Name Value: !Sub '${AWS::StackName}-cloudgenAccessRedis' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: redis - Key: Platform Value: ecsFargate redisEcsService: Type: AWS::ECS::Service Condition: createRedis Properties: ServiceName: !Sub '${AWS::StackName}-cloudgenAccessRedis' Cluster: !Ref ecsCluster NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref redisSg Subnets: !Ref publicSubnets DesiredCount: 1 EnableECSManagedTags: false LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt redisDiscoveryService.Arn ContainerName: redis SchedulingStrategy: REPLICA TaskDefinition: !Ref redisEcsTask Tags: - Key: Name Value: !Sub '${AWS::StackName}-cloudgenAccessRedis' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: redis - Key: Platform Value: ecsFargate redisDiscoveryService: Type: AWS::ServiceDiscovery::Service Condition: createRedis Properties: Name: redis Description: Discovery service for the CloudGen redis service DnsConfig: RoutingPolicy: WEIGHTED DnsRecords: - TTL: 60 Type: A HealthCheckCustomConfig: FailureThreshold: 1 NamespaceId: !Ref privateNamespace redisRole: Type: AWS::IAM::Role Condition: createRedis Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - 'sts:AssumeRole' Policies: - PolicyName: redisLogStream PolicyDocument: Statement: - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: !GetAtt logGroup.Arn ## ## Envoy ## envoyEcsTask: Type: AWS::ECS::TaskDefinition Properties: Cpu: '512' Memory: '1GB' ExecutionRoleArn: !GetAtt envoyRole.Arn NetworkMode: awsvpc RequiresCompatibilities: - FARGATE TaskRoleArn: !Ref taskRole ContainerDefinitions: - Name: !Sub '${AWS::StackName}-cloudgenAccessEnvoy' Image: fydeinc/envoyproxy-centos:latest Environment: - Name: FYDE_PROXY_HOST Value: !Sub - ${orchestratorDiscoveryService}.${AWS::StackName}-cloudgenaccessproxy - { orchestratorDiscoveryService: !GetAtt orchestratorDiscoveryService.Name } - Name: FYDE_PROXY_PORT Value: '50051' PortMappings: - ContainerPort: !Ref cloudgenAccessProxyPublicPort HostPort: !Ref cloudgenAccessProxyPublicPort Protocol: tcp HealthCheck: Command: - CMD-SHELL - !Sub - /usr/bin/cat < /dev/null > /dev/tcp/127.0.0.1/${publicPort} - { publicPort: !Ref cloudgenAccessProxyPublicPort } Interval: 5 Retries: 3 StartPeriod: 15 Timeout: 10 Essential: true LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref logGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: !Sub '/aws/ecs/${AWS::StackName}-CloudGenAccessProxy' Tags: - Key: Name Value: cloudGenAccessEnvoy - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate envoyEcsService: Type: AWS::ECS::Service Properties: ServiceName: !Sub '${AWS::StackName}-cloudgenAccessEnvoy' Cluster: !Ref ecsCluster NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref envoySg - !Ref inboundSg Subnets: !Ref publicSubnets LoadBalancers: - ContainerName: !Sub '${AWS::StackName}-cloudgenAccessEnvoy' ContainerPort: !Ref cloudgenAccessProxyPublicPort TargetGroupArn: !Ref nlbTargetGroup DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: !Ref envoyDesiredCapacity EnableECSManagedTags: false LaunchType: FARGATE SchedulingStrategy: REPLICA TaskDefinition: !Ref envoyEcsTask Tags: - Key: Name Value: !Sub '${AWS::StackName}-cloudgenAccessEnvoy' - Key: Application Value: cloudGenAccessProxy - Key: Service Value: envoy - Key: Platform Value: ecsFargate envoyRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - 'sts:AssumeRole' Policies: - PolicyName: envoyLogStream PolicyDocument: Statement: - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: !GetAtt logGroup.Arn Outputs: networkLoadBalancerDnsName: Description: Update the CloudGen Access Proxy in the Console with this DNS name Value: !GetAtt nlb.DNSName securityGroupforResources: Description: Use this group to allow CloudGen Access Proxy access to internal resources Value: !Ref envoySg