def _create_user_pool(self) -> cognito.UserPool: pool = cognito.UserPool( scope=self, id="orbit-user-pool", account_recovery=cognito.AccountRecovery.EMAIL_ONLY, auto_verify=cognito.AutoVerifiedAttrs(email=True, phone=False), custom_attributes=None, email_settings=None, lambda_triggers=None, mfa=cognito.Mfa.OFF, mfa_second_factor=None, password_policy=cognito.PasswordPolicy( min_length=8, require_digits=True, require_lowercase=True, require_symbols=True, require_uppercase=True, temp_password_validity=Duration.days(5), ), self_sign_up_enabled=False, sign_in_aliases=cognito.SignInAliases(email=True, phone=False, preferred_username=False, username=True), sign_in_case_sensitive=True, sms_role=None, sms_role_external_id=None, standard_attributes=cognito.StandardAttributes( email=cognito.StandardAttribute(required=True, mutable=True)), user_invitation=cognito.UserInvitationConfig( email_subject="Invite to join Orbit Workbench!", email_body= "Hello, you have been invited to join Orbit Workbench!<br/><br/>" "Username: {username}<br/>" "Temporary password: {####}<br/><br/>" "Regards", ), user_pool_name=f"orbit-{self.env_name}-user-pool", ) pool.apply_removal_policy(policy=core.RemovalPolicy.DESTROY) pool.add_domain( id="orbit-user-pool-domain", cognito_domain=cognito.CognitoDomainOptions( domain_prefix=f"orbit-{self.context.account_id}-{self.env_name}" ), ) return pool
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) servu_userpool = aws_cognito.UserPool( self, 'servu-userpool', user_pool_name='ServU Users', sign_in_aliases=aws_cognito.SignInAliases(email=True), standard_attributes=aws_cognito.StandardAttributes( email=aws_cognito.StandardAttribute(required=True, mutable=True), fullname=aws_cognito.StandardAttribute(required=True, mutable=True), address=aws_cognito.StandardAttribute(required=True, mutable=True), phone_number=aws_cognito.StandardAttribute(required=True, mutable=True)), password_policy=aws_cognito.PasswordPolicy( min_length=8, require_digits=True, require_lowercase=True, require_symbols=True, require_uppercase=True, temp_password_validity=core.Duration.days(1)), sign_in_case_sensitive=False) servu_userpool_web_client = aws_cognito.UserPoolClient( self, 'servu-userpool-web-client', user_pool=servu_userpool, auth_flows=aws_cognito.AuthFlow(custom=True, refresh_token=True, user_srp=True), user_pool_client_name='ServU Web Client') # TODO: Manually configure the domain and callback URLs. Look at CFN for the Pool ID and Client ID core.CfnOutput(self, 'servu-userpool-id', value=servu_userpool.user_pool_id, export_name='servu-userpool-id') core.CfnOutput(self, 'servu-userpool-client-id', value=servu_userpool_web_client.user_pool_client_id, export_name='servu-userpool-client-id')
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # ----------------------------------- # Cognito User Pool # ----------------------------------- userpool = cognito.UserPool( self, "ServerlessTodoUserPool", user_pool_name="ServerlessTodoUserPool", sign_in_aliases=cognito.SignInAliases(username=True, email=True), password_policy=cognito.PasswordPolicy( min_length=6, require_digits=True, require_lowercase=True, require_symbols=True, require_uppercase=True, temp_password_validity=core.Duration.days(7)), auto_verify=cognito.AutoVerifiedAttrs(email=True), standard_attributes=cognito.StandardAttributes( email=cognito.StandardAttribute(mutable=True, required=True), family_name=cognito.StandardAttribute(mutable=True, required=True), given_name=cognito.StandardAttribute(mutable=True, required=True))) user_pool_client = userpool.add_client( "UserPoolClient", auth_flows=cognito.AuthFlow(admin_user_password=True)) # ----------------------------------- # dynamodb # ----------------------------------- dynamodbTable = dynamodb.Table( self, "TaskTable", partition_key=dynamodb.Attribute( name="id", type=dynamodb.AttributeType.STRING), sort_key=dynamodb.Attribute(name="meta", type=dynamodb.AttributeType.STRING), billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST, point_in_time_recovery=True, server_side_encryption=True) dynamodbTable.add_global_secondary_index( partition_key=dynamodb.Attribute( name="meta", type=dynamodb.AttributeType.STRING), sort_key=dynamodb.Attribute(name="id", type=dynamodb.AttributeType.STRING), index_name="meta-id-index") dynamodbTable.add_global_secondary_index( partition_key=dynamodb.Attribute( name="owner", type=dynamodb.AttributeType.STRING), sort_key=dynamodb.Attribute(name="meta", type=dynamodb.AttributeType.STRING), index_name="owner-meta-index") # ----------------------------------- # apigateway # ----------------------------------- acm_arn = self.node.try_get_context('acm_arn') domain_name = self.node.try_get_context("domain_name") hosted_zone = self.node.try_get_context("hosted_zone") api_policy = iam.PolicyDocument( statements=iam.PolicyStatement(actions=["lambda:InvokeFunction"], ) .add_resources("arn:aws:lambda:{}:{}:function:*".format( self.region, self.account))) if acm_arn and domain_name and hosted_zone: api = apigw.RestApi( self, 'API', domain_name=apigw.DomainNameOptions( certificate=acm.Certificate.from_certificate_arn( self, 'ApiCertificate', acm_arn), domain_name=domain_name, endpoint_type=apigw.EndpointType.REGIONAL), deploy_options=apigw.StageOptions(metrics_enabled=True), policy=api_policy, rest_api_name="Serverless TODO API", endpoint_types=[apigw.EndpointType.REGIONAL], default_cors_preflight_options=apigw.CorsOptions( allow_origins=apigw.Cors. ALL_ORIGINS, # TODO: Temporary for development allow_headers=[ "Content-Type", "X-Amz-Date", "Authorization", "X-Api-Key", "X-Amz-Security-Token", "X-Tracing-Id", "x-jeffy-correlation-id", "x-amzn-trace-id" ], allow_methods=apigw.Cors.ALL_METHODS, allow_credentials=True)) route53.CfnRecordSet( self, "apiDomainRecord", name=domain_name, type="A", alias_target={ "dnsName": api.domain_name.domain_name_alias_domain_name, "hostedZoneId": api.domain_name.domain_name_alias_hosted_zone_id }, hosted_zone_id=hosted_zone, ) else: api = apigw.RestApi( self, 'API', deploy_options=apigw.StageOptions(metrics_enabled=True), policy=api_policy, rest_api_name="Serverless TODO API", endpoint_types=[apigw.EndpointType.REGIONAL], default_cors_preflight_options=apigw.CorsOptions( allow_origins=apigw.Cors. ALL_ORIGINS, # TODO: Temporary for development allow_headers=[ "Content-Type", "X-Amz-Date", "Authorization", "X-Api-Key", "X-Amz-Security-Token", "X-Tracing-Id", "x-jeffy-correlation-id", "x-amzn-trace-id" ], allow_methods=apigw.Cors.ALL_METHODS, allow_credentials=True)) cognito_authorizer = apigw.CognitoUserPoolsAuthorizer( self, "CognitoAuthorizer", cognito_user_pools=[userpool], authorizer_name='todo_cognito_authorizer', identity_source='method.request.header.Authorization', results_cache_ttl=core.Duration.minutes(60)) api_role = iam.Role(self, "ApiRole", assumed_by=iam.ServicePrincipal( service="apigateway.amazonaws.com")) api_statement = iam.PolicyStatement( actions=["lambda:InvokeFunction"], resources=[ "arn:aws:lambda:{}:{}:function:*".format( self.region, self.account) ]) api_role.add_to_policy(api_statement) # ----------------------------------- # lambda common configure # ----------------------------------- env = { "TABLE_NAME": dynamodbTable.table_name, "USER_POOL_ID": userpool.user_pool_id, "USER_POOL_NAME": userpool.user_pool_provider_name, "CLIENT_ID": user_pool_client.user_pool_client_id } # ----------------------------------- # get handler # ----------------------------------- get_resource_base_name = "getTaskFunction" get_task_func = lambda_.Function( self, get_resource_base_name, code=lambda_.Code.from_asset( 'function/src/task', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="get.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) get_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['dynamodb:*'], resources=[ dynamodbTable.table_arn, dynamodbTable.table_arn + '/*' ])) logs.LogGroup(self, get_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + get_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) task_path = api.root.add_resource("task") task_id_path = task_path.add_resource("{task_id}") get_task_integration = apigw.LambdaIntegration( get_task_func, credentials_role=api_role) task_id_path.add_method( "GET", integration=get_task_integration, authorization_type=apigw.AuthorizationType.COGNITO, authorizer=cognito_authorizer, ) # ----------------------------------- # create handler # ----------------------------------- create_resource_base_name = "createTaskFunction" create_task_func = lambda_.Function( self, create_resource_base_name, code=lambda_.Code.from_asset( 'function/src/task', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="create.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) create_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['dynamodb:*'], resources=[ dynamodbTable.table_arn, dynamodbTable.table_arn + '/*' ])) logs.LogGroup(self, create_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + create_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) create_task_integration = apigw.LambdaIntegration( create_task_func, credentials_role=api_role) task_path.add_method( "POST", integration=create_task_integration, authorization_type=apigw.AuthorizationType.COGNITO, authorizer=cognito_authorizer, ) # ----------------------------------- # update handler # ----------------------------------- update_resource_base_name = "updateTaskFunction" update_task_func = lambda_.Function( self, update_resource_base_name, code=lambda_.Code.from_asset( 'function/src/task', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="update.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) update_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['dynamodb:*'], resources=[ dynamodbTable.table_arn, dynamodbTable.table_arn + '/*' ])) logs.LogGroup(self, update_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + update_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) update_task_integration = apigw.LambdaIntegration( update_task_func, credentials_role=api_role) task_id_path.add_method( "POST", integration=update_task_integration, authorization_type=apigw.AuthorizationType.COGNITO, authorizer=cognito_authorizer, ) # ----------------------------------- # delete handler # ----------------------------------- delete_resource_base_name = "deleteTaskFunction" delete_task_func = lambda_.Function( self, delete_resource_base_name, code=lambda_.Code.from_asset( 'function/src/task', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="delete.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) delete_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['dynamodb:*'], resources=[ dynamodbTable.table_arn, dynamodbTable.table_arn + '/*' ])) logs.LogGroup(self, delete_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + delete_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) delete_task_integration = apigw.LambdaIntegration( delete_task_func, credentials_role=api_role) task_id_path.add_method( "DELETE", integration=delete_task_integration, authorization_type=apigw.AuthorizationType.COGNITO, authorizer=cognito_authorizer, ) # ----------------------------------- # search handler # ----------------------------------- search_resource_base_name = "searchTaskFunction" search_task_func = lambda_.Function( self, search_resource_base_name, code=lambda_.Code.from_asset( 'function/src/task', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="search.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) search_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['dynamodb:*'], resources=[ dynamodbTable.table_arn, dynamodbTable.table_arn + '/*' ])) logs.LogGroup(self, search_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + search_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) search_task_integration = apigw.LambdaIntegration( search_task_func, credentials_role=api_role) tasks_path = api.root.add_resource("tasks") tasks_path.add_method( "GET", integration=search_task_integration, authorization_type=apigw.AuthorizationType.COGNITO, authorizer=cognito_authorizer, ) # ----------------------------------- # login handler # ----------------------------------- login_resource_base_name = "loginFunction" login_task_func = lambda_.Function( self, login_resource_base_name, code=lambda_.Code.from_asset( 'function/src/user', bundling=core.BundlingOptions( image=lambda_.Runtime.PYTHON_3_8.bundling_docker_image, command=[ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -a . /asset-output' ], )), handler="login.lambda_handler", runtime=lambda_.Runtime.PYTHON_3_8, environment=env, tracing=lambda_.Tracing.ACTIVE, timeout=core.Duration.seconds(29), memory_size=512) login_task_func.add_to_role_policy(statement=iam.PolicyStatement( actions=['cognito-idp:AdminInitiateAuth'], resources=[userpool.user_pool_arn])) logs.LogGroup(self, login_resource_base_name + 'LogGroup', log_group_name='/aws/lambda/' + login_task_func.function_name, retention=logs.RetentionDays.TWO_WEEKS) login_task_integration = apigw.LambdaIntegration(login_task_func) auth_path = api.root.add_resource("auth") auth_login_path = auth_path.add_resource("login") auth_login_path.add_method("POST", integration=login_task_integration)
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # S3: Create a Bucket for Unicorn Pursuit web page, and grant public read: bucket = s3.Bucket( self, "www.unicornpursuit.com", bucket_name="www.unicornpursuit.com", access_control=s3.BucketAccessControl.PUBLIC_READ, ) # Grant public read access to the bucket bucket.grant_public_access() # DynamoDB: Create Table for Project Info (ID, Owner, Content, Photo and Votes) voting = ddb.CfnTable( self, "UnicornDynamoDBVoting", table_name="UnicornDynamoDBVoting", key_schema=[ ddb.CfnTable.KeySchemaProperty(attribute_name="id", key_type="HASH"), ddb.CfnTable.KeySchemaProperty(attribute_name="owner", key_type="RANGE"), ], # In the new DynamoDB, you can't create AttDefProperty for non-key attributes. attribute_definitions=[ ddb.CfnTable.AttributeDefinitionProperty(attribute_name="id", attribute_type="N"), ddb.CfnTable.AttributeDefinitionProperty( attribute_name="owner", attribute_type="S"), ], provisioned_throughput=ddb.CfnTable.ProvisionedThroughputProperty( read_capacity_units=5, write_capacity_units=5)) # Grant RW writes for Unicorn App in Fargate and relevant Lambdas invoked from API Gateway # voting.grant_read_write_data(user) # Second DynamoDB table called "users" for storing who voted for whom # Example: [email protected] gave 5 points to project 323, 4 points to 111 etc. users = ddb.Table(self, "UnicornDynamoDBUsers", table_name="UnicornDynamoDBUsers", partition_key=ddb.Attribute( name="owner", type=ddb.AttributeType.STRING)) # Cognito: Create User Pool userpool = cognito.UserPool( self, "CognitoUnicornUserPool", user_pool_name="CognitoUnicornUserPool", self_sign_up_enabled=True, ## Require username or email for users to sign in sign_in_aliases=cognito.SignInAliases( username=False, email=True, ), # Require users to give their full name when signing up required_attributes=cognito.RequiredAttributes(fullname=True, email=True, phone_number=True), # Verify new sign ups using email auto_verify=cognito.AutoVerifiedAttrs( email=False, phone=True, ), # Configure OTP Settings () user_verification=cognito.UserVerificationConfig( sms_message= "Hey Unicorn Hunter, welcome to Unicorn Pursuit! Your OTP is {####}", ), # Set up required password policy password_policy=cognito.PasswordPolicy( min_length=12, require_symbols=True, require_lowercase=True, require_uppercase=True, require_digits=True, )) ## Cognito: Create App Client & create Authentication Flow with User and Password client = userpool.add_client( "UnicornAppClient", user_pool_client_name="UnicornAppClient", generate_secret=False, ## We'll allow both Flows, Implicit and Authorization Code, and decide in the app which to use. auth_flows=cognito.AuthFlow(admin_user_password=False, custom=False, refresh_token=True, user_password=True, user_srp=False), )
def add_cognito(self): password_policy = _cognito.PasswordPolicy( require_lowercase=False, require_digits=False, require_symbols=False, require_uppercase=False, ) user_pool = _cognito.UserPool( self, 'UserPool', password_policy=password_policy, user_pool_name='UserPool', self_sign_up_enabled=True, user_verification={ "email_subject": "Verify your email for our awesome app!", "email_body": "Hello {username}, Thanks for signing up to our awesome app! Your verification code is {####}", "email_style": _cognito.VerificationEmailStyle.CODE, }, user_invitation={ "email_subject": "Invite to join our awesome app!", "email_body": "Hello {username}, you have been invited to join our awesome app! Your temporary password is {####}", }, sign_in_aliases={"email": True}, auto_verify={"email": True}, ) user_pool_client = user_pool.add_client("AppClient", auth_flows={ "user_password": True, "user_srp": True, "refresh_token": True, "admin_user_password": True }) idp = _cognito.CfnIdentityPool.CognitoIdentityProviderProperty( client_id=user_pool_client.user_pool_client_id, provider_name=user_pool.user_pool_provider_name) identity_pool = _cognito.CfnIdentityPool( self, "IdPool", allow_unauthenticated_identities=False, cognito_identity_providers=[idp]) authenticated_principal = _iam.FederatedPrincipal( 'cognito-identity.amazonaws.com', { "StringEquals": { "cognito-identity.amazonaws.com:aud": identity_pool.ref }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" }, }, "sts:AssumeRoleWithWebIdentity") unauthenticated_principal = _iam.FederatedPrincipal( 'cognito-identity.amazonaws.com', { "StringEquals": { "cognito-identity.amazonaws.com:aud": identity_pool.ref }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" }, }, "sts:AssumeRoleWithWebIdentity") authenticated_role = _iam.Role(self, "CognitoDefaultAuthenticatedRole", assumed_by=authenticated_principal) unauthenticated_role = _iam.Role(self, "CognitoDefaultUnAuthenticatedRole", assumed_by=unauthenticated_principal) authenticated_policy = _iam.PolicyStatement( effect=_iam.Effect.ALLOW, actions=[ "mobileanalytics:PutEvents", "cognito-sync:*", "cognito-identity:*" ], resources=["*"]) unauthenticated_policy = _iam.PolicyStatement( effect=_iam.Effect.ALLOW, actions=[ "mobileanalytics:PutEvents", "cognito-sync:*", ], resources=["*"]) authenticated_role.add_to_policy(authenticated_policy) unauthenticated_role.add_to_policy(unauthenticated_policy) _cognito.CfnIdentityPoolRoleAttachment(self, "DefaultValidRoleAttachment", identity_pool_id=identity_pool.ref, roles={ "authenticated": authenticated_role.role_arn, "unauthenticated": unauthenticated_role.role_arn }) return user_pool, identity_pool, user_pool_client
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Let's start with creating an IAM Service Role, later to be assumed by our ECS Fargate Container # After creating any resource, we'll be attaching IAM policies to this role using the `fargate_role`. fargate_role = iam.Role( self, "ecsTaskExecutionRole", role_name="ecsTaskExecutionRole", assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"), description="Custom Role assumed by ECS Fargate (container)" ) # S3: Create a Bucket for Unicorn Pursuit web page, and grant public read: bucket = s3.Bucket(self, "www.unicornpursuit.com", bucket_name="www.unicornpursuit.com", access_control=s3.BucketAccessControl.PUBLIC_READ, ) # Grant public read access to the bucket bucket.grant_public_access() # Grant S3 Read/Write access to our Fargate Container fargate_role.add_to_policy(statement=iam.PolicyStatement( resources=[bucket.bucket_arn], actions=["s3:*"] )) # DynamoDB: Create Table for Project Info (ID, Owner, Content, Photo and Votes) voting_ddb = ddb.CfnTable( self, "UnicornDynamoDBVoting", table_name="UnicornDynamoDBVoting", key_schema=[ ddb.CfnTable.KeySchemaProperty(attribute_name="id",key_type="HASH"), ddb.CfnTable.KeySchemaProperty(attribute_name="owner",key_type="RANGE"), ], # In the new DynamoDB, you can't create AttDefProperty for non-key attributes. attribute_definitions=[ ddb.CfnTable.AttributeDefinitionProperty(attribute_name="id",attribute_type="N"), ddb.CfnTable.AttributeDefinitionProperty(attribute_name="owner",attribute_type="S"), ], provisioned_throughput=ddb.CfnTable.ProvisionedThroughputProperty( read_capacity_units=5, write_capacity_units=5 ) ) # Second DynamoDB table called "users" for storing who voted for whom # Example: [email protected] gave 5 points to project 323, 4 points to 111 etc. users_ddb = ddb.Table( self, "UnicornDynamoDBUsers", table_name="UnicornDynamoDBUsers", partition_key=ddb.Attribute( name="Owner", type=ddb.AttributeType.STRING ) ) # Grant RW writes for Unicorn App in Fargate fargate_role.add_to_policy(statement=iam.PolicyStatement( resources=[voting_ddb.attr_arn, users_ddb.table_arn], actions=["dynamodb:*"] )) # Cognito: Create User Pool userpool = cognito.UserPool( self, "CognitoUnicornUserPool", user_pool_name="CognitoUnicornUserPool", self_sign_up_enabled=True, ## Require username or email for users to sign in sign_in_aliases=cognito.SignInAliases( username=False, email=True, ), # Require users to give their full name when signing up required_attributes=cognito.RequiredAttributes( fullname=True, email=True, phone_number=True ), # Verify new sign ups using email auto_verify=cognito.AutoVerifiedAttrs( email=False, phone=True, ), # Configure OTP Settings () user_verification=cognito.UserVerificationConfig( sms_message="Hey Unicorn Hunter, welcome to Unicorn Pursuit! Your OTP is {####}", ), # Set up required password policy password_policy=cognito.PasswordPolicy( min_length=12, require_symbols=True, require_lowercase=True, require_uppercase=True, require_digits=True, ) ) ## Cognito: Create App Client & create Authentication Flow with User and Password userpool.add_client( "UnicornAppClient", user_pool_client_name="UnicornAppClient", generate_secret=False, ## We'll allow both Flows, Implicit and Authorization Code, and decide in the app which to use. auth_flows=cognito.AuthFlow( admin_user_password=False, custom=False, refresh_token=True, user_password=True, user_srp=False ), ) # Grant Cognito Access to Fargate. Include SSM, so Client App ID can be retrived. fargate_role.add_to_policy(statement=iam.PolicyStatement( resources=["*"], actions=["ssm:*"] )) fargate_role.add_to_policy(statement=iam.PolicyStatement( resources=[userpool.user_pool_arn], actions=["cognito-identity:*","cognito-idp:*","cognito-sync:*"] )) ## Fargate: Create ECS:Fargate with ECR uploaded image vpc = ec2.Vpc(self, "UnicornVPC", max_azs=2, nat_gateways=None) """ VPC with optimal NAT GW usage vpc_lowcost = ec2.Vpc(self, "LowCostVPC", max_azs=2, cidr="10.7.0.0/16", nat_gateways=None, subnet_configuration=[ec2.SubnetConfiguration( subnet_type=ec2.SubnetType.PUBLIC, name="Public", cidr_mask=24, ), ec2.SubnetConfiguration( subnet_type=ec2.SubnetType.ISOLATED, name="Private", cidr_mask=24, ) ], ) """ linux_ami = ec2.AmazonLinuxImage(generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX, edition=ec2.AmazonLinuxEdition.STANDARD, virtualization=ec2.AmazonLinuxVirt.HVM, storage=ec2.AmazonLinuxStorage.GENERAL_PURPOSE ) nat_ec2 = ec2.Instance(self, "NAT", instance_name="NAT", vpc=vpc, vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC), instance_type=ec2.InstanceType(instance_type_identifier="t3.nano"), machine_image=linux_ami, user_data=ec2.UserData.for_linux(), source_dest_check=False, ) # Configure Linux Instance to act as NAT Instance nat_ec2.user_data.add_commands("sysctl -w net.ipv4.ip_forward=1") nat_ec2.user_data.add_commands("/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE") # Add a static route to the ISOLATED subnet, pointing 0.0.0.0/0 to a NAT EC2 selection = vpc.select_subnets( subnet_type=ec2.SubnetType.PRIVATE ) for subnet in selection.subnets: subnet.add_route("DefaultNAT", router_id=nat_ec2.instance_id, router_type=ec2.RouterType.INSTANCE, destination_cidr_block="0.0.0.0/0") # Create ECS Cluster cluster = ecs.Cluster(self, "UnicornCluster", vpc=vpc) ecr.Repository(self, "unicorn", repository_name="unicorn") fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(self, "UnicornFargateService", cluster=cluster, cpu=512, desired_count=1, task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions( image=ecs.ContainerImage.from_registry("057097267726.dkr.ecr.eu-west-1.amazonaws.com/unicorn"), # image=ecs.ContainerImage.from_registry(repo.repository_uri_for_tag()), container_port=8080, container_name="unicorn", execution_role=fargate_role, ), memory_limit_mib=1024, public_load_balancer=True ) fargate_service.service.connections.security_groups[0].add_ingress_rule( peer = ec2.Peer.ipv4(vpc.vpc_cidr_block), connection = ec2.Port.tcp(8080), description="Allow http inbound from VPC" ) # Update NAT EC2 Security Group, to allow only HTTPS from Fargate Service Security Group. nat_ec2.connections.security_groups[0].add_ingress_rule( peer = fargate_service.service.connections.security_groups[0], connection = ec2.Port.tcp(443), description="Allow https from Fargate Service" ) # Grant ECR Access to Fargate by attaching an existing ReadOnly policy. so that Unicorn Docker Image can be pulled. #fargate_role.add_managed_policy(iam.ManagedPolicy("AmazonEC2ContainerRegistryReadOnly")) fargate_role.add_to_policy(statement=iam.PolicyStatement( resources=["*"], actions=["ecr:*"] ))
def __init__(self, scope: core.Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) prj_name = self.node.try_get_context('project_name') env_name = self.node.try_get_context('env') user_pool2 = cognito.UserPool( self, id=f'{env_name}-precog', auto_verify=cognito.AutoVerifiedAttrs(email=True), sign_in_aliases=cognito.SignInAliases(email=True, phone=True), self_sign_up_enabled=True, user_pool_name=f'{env_name}-cdk-2-user-pool', custom_attributes={ "param1": cognito.StringAttribute(mutable=True) }, password_policy=cognito.PasswordPolicy(min_length=10, require_lowercase=True, require_digits=True, require_symbols=False, require_uppercase=True)) user_pool = cognito.CfnUserPool( self, id=f'{env_name}-cognito-user-pool', auto_verified_attributes=['email'], username_attributes=['email', 'phone_number'], user_pool_name=f'{env_name}-cdk-user-pool', schema=[{ "attributeDataType": "String", "name": "param1", "mutable": True }], policies=cognito.CfnUserPool.PoliciesProperty( password_policy=cognito.CfnUserPool.PasswordPolicyProperty( minimum_length=10, require_lowercase=True, require_numbers=True, require_symbols=False, require_uppercase=True))) user_pool_client2 = cognito.UserPoolClient( self, id=f'{env_name}-pool-client2', user_pool=user_pool2, user_pool_client_name=f'{env_name}-cdk-app-client2') identity_pool2 = cognito.CfnIdentityPool( self, id=f'{env_name}-identify-pool-2', allow_unauthenticated_identities=False, cognito_identity_providers=[ cognito.CfnIdentityPool.CognitoIdentityProviderProperty( client_id=user_pool_client2.user_pool_client_id, provider_name=user_pool.attr_provider_name) ], identity_pool_name=f'{env_name}-cdk-identity-pool2') user_pool_client = cognito.CfnUserPoolClient( self, id=f'{env_name}-pool-client', user_pool_id=user_pool.ref, client_name=f'{env_name}-cdk-app-client') identity_pool = cognito.CfnIdentityPool( self, id=f'{env_name}-identify-pool', allow_unauthenticated_identities=False, cognito_identity_providers=[ cognito.CfnIdentityPool.CognitoIdentityProviderProperty( client_id=user_pool_client.ref, provider_name=user_pool.attr_provider_name) ], identity_pool_name=f'{env_name}-cdk-identity-pool') ssm.StringParameter( self, id='app-id', parameter_name=f"/{env_name}/cognito-app-client-id", string_value=user_pool_client.ref) ssm.StringParameter(self, id='user-pool-id', parameter_name=f"/{env_name}/cognito-user-pool-id", string_value=user_pool_client.user_pool_id) ssm.StringParameter( self, id='identity-pool-id', parameter_name=f"/{env_name}/cognito-identity-pool-id", string_value=identity_pool.ref # ref returns the id )
def base_cognito_user_pool(construct, **kwargs): """ Function that generates a Cognito User Pool. :param construct: Custom construct that will use this function. From the external construct is usually 'self'. :param kwargs: Consist of required 'queue_name' and optionals 'queue_delivery_delay' and 'queue_visibility_timeout'. :return: DynamoDB Table Construct. """ user_pool_name = construct.prefix + "_" + kwargs[ "pool_name"] + "_pool_" + construct.environment_ if kwargs.get("email") is not None: email_settings = cognito.EmailSettings( from_=kwargs["email"]["from"], reply_to=kwargs["email"].get("reply_to")) else: email_settings = None password_policy_settings = kwargs.get("password_policy") temporary_password_validation_time = ( core.Duration.days( password_policy_settings.get("temporary_password_duration")) if password_policy_settings.get("temporary_password_duration") is not None else None) password_policy = cognito.PasswordPolicy( min_length=password_policy_settings.get("minimum_length"), temp_password_validity=temporary_password_validation_time, require_lowercase=password_policy_settings.get("require", {}).get("lower_case"), require_uppercase=password_policy_settings.get("require", {}).get("upper_case"), require_digits=password_policy_settings.get("require", {}).get("digits"), require_symbols=password_policy_settings.get("require", {}).get("symbols"), ) sign_up_info = kwargs["sign_up"] self_sing_up = sign_up_info["enabled"] user_verification_info = base_user_verification( sign_up_info=sign_up_info["user_verification"]) user_invitation = kwargs.get("invitation") user_invitation_configuration = cognito.UserInvitationConfig( email_subject=user_invitation.get("email", {}).get("subject"), email_body=user_invitation.get("email", {}).get("body"), sms_message=user_invitation.get("sms", {}).get("body"), ) trigger_functions = kwargs.get("triggers", {}) lambda_triggers = base_lambda_triggers(construct, trigger_functions=trigger_functions) sign_in_list = kwargs.get("sign_in").get("order", list()) sing_in_kwargs = dict() for element in sign_in_list: sing_in_kwargs[element] = True sign_in_aliases = cognito.SignInAliases(**sing_in_kwargs) attributes = kwargs.get("attributes") standard_attributes_list = attributes.get("standard", list()) standard_attributes_dict = dict() for element in standard_attributes_list: standard_attributes_dict[element["name"]] = cognito.StandardAttribute( mutable=element.get("mutable"), required=element.get("required")) standard_attributes = cognito.StandardAttributes( **standard_attributes_dict) custom_attributes_list = attributes.get("custom", list()) if len(custom_attributes_list) > 0: custom_attributes = base_custom_attributes( custom_attributes_list=custom_attributes_list) else: custom_attributes = None user_pool = cognito.UserPool( construct, id=user_pool_name, user_pool_name=user_pool_name, email_settings=email_settings, password_policy=password_policy, self_sign_up_enabled=self_sing_up, user_verification=user_verification_info, user_invitation=user_invitation_configuration, sign_in_aliases=sign_in_aliases, standard_attributes=standard_attributes, custom_attributes=custom_attributes, lambda_triggers=lambda_triggers, ) user_pool_client = None if kwargs.get("app_client", {}).get("enabled") is True: client_name = kwargs["app_client"]["client_name"] generate_secret = kwargs["app_client"]["generate_secret"] user_pool_client_name = construct.prefix + "_" + client_name + "_client_" + construct.environment_ auth_flows = None auth_flows_configuration = kwargs["app_client"].get("auth_flows") if auth_flows_configuration is not None: auth_flows = cognito.AuthFlow(**auth_flows_configuration) user_pool_client = cognito.UserPoolClient( construct, id=user_pool_client_name, user_pool_client_name=user_pool_client_name, generate_secret=generate_secret, auth_flows=auth_flows, user_pool=user_pool, ) return user_pool, user_pool_client
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) pool = cognito.UserPool(scope=self, id="user-pool", mfa=cognito.Mfa.OPTIONAL, mfa_second_factor=cognito.MfaSecondFactor( otp=True, sms=True), password_policy=cognito.PasswordPolicy( min_length=12, require_lowercase=True, require_uppercase=False, require_digits=False, require_symbols=False, )) client = pool.add_client( id="customer-app-client", auth_flows=cognito.AuthFlow( user_password=True, refresh_token=True, user_srp=True, ), ) graphql_api = appsync.GraphqlApi( scope=self, id="graphql-api", name="todo-api", schema=appsync.Schema.from_asset( file_path=os.path.join("graphQL", "schema.graphql")), authorization_config=appsync.AuthorizationConfig( default_authorization=appsync.AuthorizationMode( authorization_type=appsync.AuthorizationType.USER_POOL, user_pool_config=appsync.UserPoolConfig(user_pool=pool, ))), xray_enabled=True) todo_table = dynamodb.Table( scope=self, id="todo-table", removal_policy=core.RemovalPolicy.DESTROY, partition_key=dynamodb.Attribute( name="id", type=dynamodb.AttributeType.STRING), ) commnet_table = dynamodb.Table( scope=self, id="comment-table", removal_policy=core.RemovalPolicy.DESTROY, partition_key=dynamodb.Attribute( name="commentid", type=dynamodb.AttributeType.STRING), sort_key=dynamodb.Attribute(name="todoid", type=dynamodb.AttributeType.STRING), ) commnet_table.add_global_secondary_index( partition_key=dynamodb.Attribute( name="todoid", type=dynamodb.AttributeType.STRING), index_name="todoid-index") todo_dS = graphql_api.add_dynamo_db_data_source( id="todoDS", table=todo_table, ) todo_dS.create_resolver( type_name="Query", field_name="getTodos", request_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "getItemsRequest.vtl")), response_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "getItemsResponse.vtl")), ) todo_dS.create_resolver( type_name="Mutation", field_name="addTodo", request_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "addTodoRequest.vtl")), response_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "addTodoResponse.vtl")), ) comment_dS = graphql_api.add_dynamo_db_data_source( id="commentDS", table=commnet_table, ) comment_dS.create_resolver( type_name="Todo", field_name="contents", request_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "getCommentsRequest.vtl")), response_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "getCommentsResponse.vtl")), ) comment_dS.create_resolver( type_name="Mutation", field_name="addComment", request_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "addCommentRequest.vtl")), response_mapping_template=appsync.MappingTemplate.from_file( os.path.join("graphQL", "addCommentResponse.vtl")), )
def __init__(self, scope: core.Construct, id: str, artifact_bucket: s3.Bucket, **kwargs) -> None: super().__init__(scope, id, **kwargs) pool = cognito.UserPool(scope=self, id="user-pool", mfa=cognito.Mfa.OPTIONAL, mfa_second_factor=cognito.MfaSecondFactor( otp=True, sms=True), password_policy=cognito.PasswordPolicy( min_length=12, require_lowercase=True, require_uppercase=False, require_digits=False, require_symbols=False, )) client = pool.add_client( id="customer-app-client", auth_flows=cognito.AuthFlow(user_password=True, refresh_token=True), ) backend = _lambda.Function( scope=self, id="api-function", runtime=_lambda.Runtime.GO_1_X, handler="main", memory_size=500, timeout=core.Duration.seconds(10), environment={ "USER_POOL_ID": pool.user_pool_id, "CLIENT_ID": client.user_pool_client_id, }, code=_lambda.Code.from_bucket( bucket=artifact_bucket, key="Server/main.zip", ), ) backend.add_to_role_policy( statement=iam.PolicyStatement(actions=[ "cognito-idp:RespondToAuthChallenge", "cognito-idp:InitiateAuth", "cognito-idp:SetUserMFAPreference", "cognito-idp:AssociateSoftwareToken", "cognito-idp:VerifySoftwareToken" ], resources=[pool.user_pool_arn])) api = apigateway.LambdaRestApi( scope=self, id="mfa-api", handler=backend, endpoint_types=[apigateway.EndpointType.REGIONAL], default_cors_preflight_options=apigateway.CorsOptions( allow_origins=["*"])) self.api = api self.backend_fn = backend static_website_bucket = s3.Bucket( scope=self, id="static-website-bucket", ) self.static_website_bucket = static_website_bucket distribution = cloudfront.CloudFrontWebDistribution( scope=self, id="static-website-distribution", default_root_object="index.html", origin_configs=[ cloudfront.SourceConfiguration( s3_origin_source=cloudfront.S3OriginConfig( s3_bucket_source=static_website_bucket, origin_access_identity=cloudfront.OriginAccessIdentity( scope=self, id="origin-access-identity", )), behaviors=[cloudfront.Behavior(is_default_behavior=True)]) ], )
def __init__(self, scope: core.Construct, construct_id: str, cognito_prefix: str, stack_log_level: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here # Cognito User Pool for Kibana Access self.es_user_pool = _cognito.UserPool( self, "esCognitoUserPool", user_pool_name=f"{cognito_prefix}-log-parser-es-users", self_sign_up_enabled=False, sign_in_aliases=_cognito.SignInAliases(username=True, email=True), sign_in_case_sensitive=False, standard_attributes={ "email": { "required": True, "mutable": False }, "fullname": { "required": False, "mutable": True } }, password_policy=_cognito.PasswordPolicy(min_length=8), auto_verify=_cognito.AutoVerifiedAttrs(email=True)) # Create User Pool Domain to enable SignUp, SignIn, Auth & Callback Urls es_auth_domain = _cognito.UserPoolDomain( self, "esCognitoUserPoolDomain", user_pool=self.es_user_pool, cognito_domain=_cognito.CognitoDomainOptions( domain_prefix=f"{cognito_prefix}-{core.Aws.ACCOUNT_ID}")) # Role Authenticated Cognito Users will assume in ES Service self.es_role = _iam.Role( self, "esKibanaIamRole", assumed_by=_iam.ServicePrincipal("es.amazonaws.com"), managed_policies=[ _iam.ManagedPolicy.from_aws_managed_policy_name( managed_policy_name="AmazonESCognitoAccess") ], ) # Create Cognito Federated Identity Pool to exchange Cognito auth token for AWS Token self.es_id_pool = _cognito.CfnIdentityPool( self, "esIdentityPool", allow_unauthenticated_identities=False, cognito_identity_providers=[], ) # Role For Cognito Federated Idenity Pool Authenticated Users self.es_auth_role = _iam.Role( self, "esAuthIamRole", assumed_by=_iam.FederatedPrincipal( federated="cognito-identity.amazonaws.com", conditions={ "StringEquals": { "cognito-identity.amazonaws.com:aud": self.es_id_pool.ref }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" }, }, assume_role_action="sts:AssumeRoleWithWebIdentity"), ) # Attach a Role to Cognito Federated Idenity Pool Authenticated Users _cognito.CfnIdentityPoolRoleAttachment( self, "cognitoFederatedIdentityPoolRoleAttachment", identity_pool_id=self.es_id_pool.ref, roles={"authenticated": self.es_auth_role.role_arn}) ########################################### ################# OUTPUTS ################# ########################################### output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description= "To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "CreateCognitoUserConsole", value= f"https://{core.Aws.REGION}.console.aws.amazon.com/cognito/users?region={core.Aws.REGION}#/pool/{self.es_user_pool.user_pool_id}/users", description="Create a new user in the user pool here.")