def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Retrieves the ACM certificate arn from an SSM parameter
        certificate_arn = aws_ssm.StringParameter.value_from_lookup(self, 
            'cognito_certificate_arn')

        # Retrieves the domain name from an SSM parameter
        domain_name = aws_ssm.StringParameter.value_from_lookup(self, 
            'kubeflow-cognito-domain-name')

        # Creates the cognito user pool
        user_pool = aws_cognito.UserPool(self, 'UserPool',
            user_pool_name = 'mlplatform-user-pool',
            mfa = aws_cognito.Mfa.OFF,
            sign_in_aliases = aws_cognito.SignInAliases(
                username=True,
                email=True))

        # Creates the cognito user pool client
        user_pool_client = aws_cognito.UserPoolClient(self, 'UserPoolClient',
            user_pool = user_pool,
            generate_secret = True,
            o_auth = aws_cognito.OAuthSettings(
                flows = aws_cognito.OAuthFlows(
                    authorization_code_grant = True
                ),
                scopes = [
                    aws_cognito.OAuthScope.EMAIL, 
                    aws_cognito.OAuthScope.OPENID, 
                    aws_cognito.OAuthScope.PROFILE, 
                    aws_cognito.OAuthScope.COGNITO_ADMIN
                ],
                callback_urls = ['https://kubeflow.' + domain_name + '/oauth2/idpresponse']
            ),
            user_pool_client_name = 'mlplatform-user-pool-client')

        
        # Initialises the ACM certificate
        cognito_custom_domain_certificate = aws_certificatemanager.Certificate.from_certificate_arn(self, 'DomainCertificate', 
            certificate_arn)

        # Creates the cognito user pool domain
        user_pool_domain = aws_cognito.UserPoolDomain(self, 'UserPoolDomain',
            user_pool = user_pool,
            custom_domain = aws_cognito.CustomDomainOptions(
                certificate = cognito_custom_domain_certificate,
                domain_name = 'auth.' + domain_name
            )
        )
Exemplo n.º 2
0
    def _create_userpool(self):
        user_pool = cognito.UserPool(
            self,
            "movio",
            account_recovery=cognito.AccountRecovery.EMAIL_ONLY,
            auto_verify=cognito.AutoVerifiedAttrs(email=True, phone=False),
            mfa=cognito.Mfa.OFF,
            mfa_second_factor=cognito.MfaSecondFactor(otp=True, sms=False),
            self_sign_up_enabled=False,
            sign_in_aliases=cognito.SignInAliases(email=True, username=True),
            standard_attributes=cognito.StandardAttributes(
                email=cognito.StandardAttribute(mutable=False,
                                                required=True), ),
            user_invitation=cognito.UserInvitationConfig(
                email_subject="Moshan email verification",
                email_body=
                "Thanks for signing up to moshan! Your username is {username} and temporary password is {####}\nYou can now login at https://moshan.tv",
            ),
            user_verification=cognito.UserVerificationConfig(
                email_subject="Moshan email verification",
                email_body=
                "Thanks for signing up to moshan! Verify your account by clicking on {##Verify Email##}",
                email_style=cognito.VerificationEmailStyle.LINK),
        )

        user_pool.add_client(
            "moshan",
            auth_flows=cognito.AuthFlow(refresh_token=True),
            o_auth=cognito.OAuthSettings(
                flows=cognito.OAuthFlows(authorization_code_grant=True),
                callback_urls=[
                    "https://moshan.tv/callback.html",
                    "https://beta.moshan.tv/callback.html"
                ],
                scopes=[
                    cognito.OAuthScope.EMAIL, cognito.OAuthScope.OPENID,
                    cognito.OAuthScope.PROFILE
                ]),
            prevent_user_existence_errors=True,
        )

        cert = Certificate.from_certificate_arn(self, "domainCert",
                                                self.cert_arn)
        user_pool.add_domain("CognitoDomain",
                             custom_domain=cognito.CustomDomainOptions(
                                 domain_name=self.domain_name,
                                 certificate=cert))
Exemplo n.º 3
0
    def __init__(self, scope: cdk.Construct, id: str,
                 cognito_user_pool: cognito.UserPool, s3_bucket_name: str,
                 create_configuration_lambda_role_arn: str,
                 redis: ec.CfnCacheCluster, domain_name: str,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        config_yaml = yaml.load(open("config.yaml"), Loader=yaml.FullLoader)
        spoke_accounts = config_yaml.get("spoke_accounts", [])

        cognito_user_pool_client = cognito.UserPoolClient(
            self,
            "UserPoolClient",
            user_pool=cognito_user_pool,
            generate_secret=True,
            supported_identity_providers=[
                cognito.UserPoolClientIdentityProvider.COGNITO
            ],
            prevent_user_existence_errors=True,
            o_auth=cognito.OAuthSettings(
                callback_urls=[
                    "https://" + domain_name + "/auth",
                    "https://" + domain_name + "/oauth2/idpresponse",
                ],
                logout_urls=["https://" + domain_name + "/logout"],
                flows=cognito.OAuthFlows(authorization_code_grant=True,
                                         implicit_code_grant=True),
                scopes=[cognito.OAuthScope.OPENID, cognito.OAuthScope.EMAIL],
            ),
            auth_flows=cognito.AuthFlow(user_password=True, user_srp=True),
        )

        describe_cognito_user_pool_client = cr.AwsCustomResource(
            self,
            "UserPoolClientIDResource",
            policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
                resources=cr.AwsCustomResourcePolicy.ANY_RESOURCE),
            on_create=cr.AwsSdkCall(
                service="CognitoIdentityServiceProvider",
                action="describeUserPoolClient",
                parameters={
                    "UserPoolId": cognito_user_pool.user_pool_id,
                    "ClientId": cognito_user_pool_client.user_pool_client_id,
                },
                physical_resource_id=cr.PhysicalResourceId.of(
                    cognito_user_pool_client.user_pool_client_id),
            ),
            install_latest_aws_sdk=True,
            log_retention=logs.RetentionDays.ONE_WEEK,
        )

        cognito_user_pool_client_secret = (
            describe_cognito_user_pool_client.get_response_field(
                "UserPoolClient.ClientSecret"))

        imported_create_configuration_lambda_role = iam.Role.from_role_arn(
            self,
            "ImportedCreateConfigurationFileLambdaRole",
            role_arn=create_configuration_lambda_role_arn,
        )

        jwt_secret = config_yaml["jwt_secret"]

        config_secret_dict = {
            "oidc_secrets": {
                "client_id": cognito_user_pool_client.user_pool_client_id,
                "secret": cognito_user_pool_client_secret,
                "client_scope": ["email", "openid"],
            },
            "jwt_secret": jwt_secret,
        }

        config_secret_yaml = yaml.dump(
            config_secret_dict,
            explicit_start=True,
            default_flow_style=False,
        )

        config_secret = cr.AwsCustomResource(
            self,
            "ConfigSecretResource",
            policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
                resources=cr.AwsCustomResourcePolicy.ANY_RESOURCE),
            on_update=cr.AwsSdkCall(
                service="SecretsManager",
                action="updateSecret",
                parameters={
                    "SecretId": CONFIG_SECRET_NAME,
                    "SecretString": config_secret_yaml,
                },
                physical_resource_id=cr.PhysicalResourceId.from_response(
                    "Name"),
            ),
            on_create=cr.AwsSdkCall(
                service="SecretsManager",
                action="createSecret",
                parameters={
                    "Name": CONFIG_SECRET_NAME,
                    "Description":
                    "Sensitive configuration parameters for ConsoleMe",
                    "SecretString": config_secret_yaml,
                },
                physical_resource_id=cr.PhysicalResourceId.from_response(
                    "Name"),
            ),
            on_delete=cr.AwsSdkCall(
                service="SecretsManager",
                action="deleteSecret",
                parameters={
                    "SecretId": CONFIG_SECRET_NAME,
                    "ForceDeleteWithoutRecovery": True,
                },
            ),
            install_latest_aws_sdk=True,
            log_retention=logs.RetentionDays.ONE_WEEK,
        )

        create_configuration_lambda = lambda_.Function(
            self,
            "CreateConfigurationFileLambda",
            code=lambda_.Code.from_asset("resources/create_config_lambda"),
            handler="index.handler",
            timeout=cdk.Duration.seconds(30),
            layers=[create_dependencies_layer(self, "create_config_lambda")],
            runtime=lambda_.Runtime.PYTHON_3_8,
            role=imported_create_configuration_lambda_role,
            environment={
                "DEPLOYMENT_BUCKET":
                s3_bucket_name,
                "OIDC_METADATA_URL":
                "https://cognito-idp." + self.region + ".amazonaws.com/" +
                cognito_user_pool.user_pool_id +
                "/.well-known/openid-configuration",
                "REDIS_HOST":
                redis.attr_redis_endpoint_address,
                "SES_IDENTITY_ARN":
                "arn:aws:ses:" + self.region + ":" + self.account +
                ":identity/" + domain_name,
                "SUPPORT_CHAT_URL":
                "https://discord.gg/nQVpNGGkYu",
                "APPLICATION_ADMIN":
                "consoleme_admin",
                "ACCOUNT_NUMBER":
                self.account,
                "ISSUER":
                domain_name,
                "SPOKE_ACCOUNTS":
                ",".join(spoke_accounts),
                "CONFIG_SECRET_NAME":
                CONFIG_SECRET_NAME,
            },
        )

        create_configuration_resource_provider = cr.Provider(
            self,
            "CreateConfigurationFileProvider",
            on_event_handler=create_configuration_lambda,
            log_retention=logs.RetentionDays.ONE_WEEK,
        )

        create_configuration_lambda_resource = cdk.CustomResource(
            self,
            "CreateConfigurationFile",
            service_token=create_configuration_resource_provider.service_token,
            removal_policy=cdk.RemovalPolicy.DESTROY,
            properties={"UUID": str(uuid4())},
        )

        create_configuration_lambda_resource.node.add_dependency(config_secret)
    def add_cognito(self):
        """
        Sets up the cognito infrastructure with the user pool, custom domain
        and app client for use by the ALB.
        """
        # Create the user pool that holds our users
        self.user_pool = cognito.UserPool(
            self,
            "user-pool",
            account_recovery=cognito.AccountRecovery.
            EMAIL_AND_PHONE_WITHOUT_MFA,
            auto_verify=cognito.AutoVerifiedAttrs(email=True, phone=True),
            self_sign_up_enabled=True,
            standard_attributes=cognito.StandardAttributes(
                email=cognito.StandardAttribute(mutable=True, required=True),
                given_name=cognito.StandardAttribute(mutable=True,
                                                     required=True),
                family_name=cognito.StandardAttribute(mutable=True,
                                                      required=True)))

        # Add a lambda function that automatically confirms new users without
        # email/phone verification, just for this demo
        auto_confirm_function = _lambda.Function(
            self,
            "auto-confirm-function",
            code=_lambda.Code.from_asset(path=os.path.join(
                os.path.dirname(__file__), "..", "auto_confirm_function")),
            handler="lambda_handler.lambda_handler",
            runtime=_lambda.Runtime.PYTHON_3_8,
        )

        self.user_pool.add_trigger(
            operation=cognito.UserPoolOperation.PRE_SIGN_UP,
            fn=auto_confirm_function)

        # Add a custom domain for the hosted UI
        self.user_pool_custom_domain = self.user_pool.add_domain(
            "user-pool-domain",
            cognito_domain=cognito.CognitoDomainOptions(
                domain_prefix=self.config.cognito_custom_domain))

        # Create an app client that the ALB can use for authentication
        self.user_pool_client = self.user_pool.add_client(
            "alb-app-client",
            user_pool_client_name="AlbAuthentication",
            generate_secret=True,
            o_auth=cognito.OAuthSettings(
                callback_urls=[
                    # This is the endpoint where the ALB accepts the
                    # response from Cognito
                    f"https://{self.config.application_dns_name}/oauth2/idpresponse",

                    # This is here to allow a redirect to the login page
                    # after the logout has been completed
                    f"https://{self.config.application_dns_name}"
                ],
                flows=cognito.OAuthFlows(authorization_code_grant=True),
                scopes=[cognito.OAuthScope.OPENID]),
            supported_identity_providers=[
                cognito.UserPoolClientIdentityProvider.COGNITO
            ])

        # Logout URLs and redirect URIs can't be set in CDK constructs natively ...yet
        user_pool_client_cf: cognito.CfnUserPoolClient = self.user_pool_client.node.default_child
        user_pool_client_cf.logout_ur_ls = [
            # This is here to allow a redirect to the login page
            # after the logout has been completed
            f"https://{self.config.application_dns_name}"
        ]

        self.user_pool_full_domain = self.user_pool_custom_domain.base_url()
        redirect_uri = urllib.parse.quote('https://' +
                                          self.config.application_dns_name)
        self.user_pool_logout_url = f"{self.user_pool_full_domain}/logout?" \
                                    + f"client_id={self.user_pool_client.user_pool_client_id}&" \
                                    + f"logout_uri={redirect_uri}"

        self.user_pool_user_info_url = f"{self.user_pool_full_domain}/oauth2/userInfo"
    def __init__(self, scope: core.Construct, id: str,
                 cognito_domain_name: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here):

        svc_name = self.node.try_get_context("service_name")

        url_name = core.CfnParameter(
            self,
            id="cognitoDomainName",
            description="Enter the name the domain you want to use",
            type="String",
            default="mystique")

        # Create an Identity Pool
        self.unicorn_user_pool = _cognito.UserPool(
            self,
            "unicornUserPool",
            user_pool_name="Miztiik-Unicorn-App-User-Pool",
            # sign_in_aliases={"username": True,"email": True}
            sign_in_aliases=_cognito.SignInAliases(username=True, email=True),
            standard_attributes={
                "email": {
                    "required": True,
                    "mutable": False
                },
                "fullname": {
                    "required": False,
                    "mutable": True
                }
            },
            auto_verify=_cognito.AutoVerifiedAttrs(email=True))

        # OAuth Scopes
        self.unicorn_user_pool_res_srv_identifier = f"premium_api"
        self.unicorn_read_scope = f"read"
        self.unicorn_write_scope = f"write"

        unicorn_users_auth_domain = _cognito.UserPoolDomain(
            self,
            "userPoolDomain",
            user_pool=self.unicorn_user_pool,
            cognito_domain=_cognito.CognitoDomainOptions(
                domain_prefix=f"{cognito_domain_name}"))

        self.unicorn_user_pool.user_pool_arn

        user_pool_res_srv = _cognito.CfnUserPoolResourceServer(
            self,
            "ResourceServer",
            # Having URL format is recommended
            # identifier=f"{premium_content.url}",
            identifier=f"{self.unicorn_user_pool_res_srv_identifier}",
            name=f"premium-api-authorizer",
            user_pool_id=self.unicorn_user_pool.user_pool_id,
            scopes=[{
                "scopeName": f"{self.unicorn_read_scope}",
                "scopeDescription": "Get Premium Api Content"
            }, {
                "scopeName": f"{self.unicorn_write_scope}",
                "scopeDescription": "Put Premium Api Content"
            }])

        user_pool_client = _cognito.UserPoolClient(
            self,
            "AppClient",
            user_pool=self.unicorn_user_pool,
            user_pool_client_name="premium_app_users",
            generate_secret=True,
            # 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=True,
                                         refresh_token=True,
                                         user_password=False,
                                         user_srp=True),
            prevent_user_existence_errors=True,
            o_auth=_cognito.OAuthSettings(
                flows=_cognito.OAuthFlows(authorization_code_grant=False,
                                          implicit_code_grant=False,
                                          client_credentials=True),
                scopes=[
                    # _cognito.OAuthScope.EMAIL,
                    # _cognito.OAuthScope.OPENID,
                    # _cognito.OAuthScope.COGNITO_ADMIN,
                    # _cognito.OAuthScope.PROFILE,
                    # https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_cognito/OAuthScope.html#aws_cdk.aws_cognito.OAuthScope
                    _cognito.OAuthScope.custom(
                        f"{self.unicorn_user_pool_res_srv_identifier}/{self.unicorn_read_scope}"
                    ),
                    _cognito.OAuthScope.custom(
                        f"{self.unicorn_user_pool_res_srv_identifier}/{self.unicorn_write_scope}"
                    )
                ]))

        # Add dependency so that ResourceServer is deployed before App Client
        user_pool_client.node.add_dependency(user_pool_res_srv)

        # Retrieve Cognito App Client Secret and Add to Secrets Manager
        app_secrets = CognitoAppClientSecretRetrieverStack(
            self,
            "appClientSecrets",
            user_pool_id=self.unicorn_user_pool.user_pool_id,
            user_pool_client_id=user_pool_client.user_pool_client_id,
            user_pool_oauth2_endpoint=
            f"https://{unicorn_users_auth_domain.domain_name}.auth.{core.Aws.REGION}.amazoncognito.com/oauth2/token",
            unicorn_user_pool_res_srv_identifier=
            f"{self.unicorn_user_pool_res_srv_identifier}",
            unicorn_read_scope=f"{self.unicorn_read_scope}",
            unicorn_write_scope=f"{self.unicorn_write_scope}")

        # Export Value
        self.unicorn_user_pool_secrets_arn = app_secrets.response

        ###########################################
        ################# OUTPUTS #################
        ###########################################

        output_0 = core.CfnOutput(
            self,
            "AutomationFrom",
            value=f"{global_args.SOURCE_INFO}",
            description=
            "To know more about this automation stack, check out our github page."
        )
        # https://AUTH_DOMAIN/oauth2/token
        output_1 = core.CfnOutput(
            self,
            "UnicornIdentityAuthDomain",
            value=
            f"https://{unicorn_users_auth_domain.domain_name}.auth.{core.Aws.REGION}.amazoncognito.com/oauth2/token",
            description="Authenticate Against this endpoint")

        output_2 = core.CfnOutput(self,
                                  "AppPoolSecretsArn",
                                  value=f"{app_secrets.response}",
                                  description="AppPoolSecretsArn")