コード例 #1
0
def handler(event, context):

    props = properties.load(
        event, {
            'ConfigurationBucket': properties.String(),
            'ConfigurationKey': properties.String(),
            'ResourceGroupName': properties.String()
        })

    data = {
        'ConfigurationBucket':
        props.ConfigurationBucket,
        'ConfigurationKey':
        '{}/resource-group/{}'.format(props.ConfigurationKey,
                                      props.ResourceGroupName),
        'TemplateURL':
        'https://s3.amazonaws.com/{}/{}/resource-group/{}/resource-template.json'
        .format(props.ConfigurationBucket, props.ConfigurationKey,
                props.ResourceGroupName)
    }

    physical_resource_id = 'CloudCanvas:LambdaConfiguration:{stack_name}:{resource_group_name}'.format(
        stack_name=aws_utils.get_stack_name_from_stack_arn(event['StackId']),
        resource_group_name=props.ResourceGroupName)

    response.succeed(event, context, data, physical_resource_id)
コード例 #2
0
def handler(event, context):
    '''Entry point for the Custom::AccessControl resource handler.'''

    props = properties.load(
        event,
        {
            'ConfigurationBucket': properties.String(),  # Currently not used
            'ConfigurationKey': properties.String()
        }
    )  # Depend on unique upload id in key to force Cloud Formation to call handler

    # Validate RequestType
    request_type = event['RequestType']
    if request_type not in ['Create', 'Update', 'Delete']:
        raise RuntimeError('Unexpected request type: {}'.format(request_type))

    # Get stack_info for the AccessControl resource's stack.
    stack_arn = event['StackId']
    stack = stack_info.get_stack_info(stack_arn)

    # Physical ID is always the same.
    physical_resource_id = aws_utils.get_stack_name_from_stack_arn(
        stack_arn) + '-' + event['LogicalResourceId']

    # The AccessControl resource has no output values.
    data = {}

    # Accumlate problems encountered so we can give a full report.
    problems = ProblemList()

    # Apply access control as determined by the Cloud Canvas stack type.
    if stack.stack_type == stack.STACK_TYPE_RESOURCE_GROUP:
        were_changes = _apply_resource_group_access_control(
            request_type, stack, problems)
    elif stack.stack_type == stack.STACK_TYPE_DEPLOYMENT_ACCESS:
        were_changes = _apply_deployment_access_control(
            request_type, stack, problems)
    elif stack.stack_type == stack.STACK_TYPE_PROJECT:
        were_changes = _apply_project_access_control(request_type, stack,
                                                     problems)
    else:
        raise RuntimeError(
            'The Custom::AccessControl resource can only be used in resource group, deployment access, or project stack templates.'
        )

    # If there were any problems, provide an error message with all the details.
    if problems:
        raise RuntimeError(
            'Found invalid AccessControl metadata:\n    {}'.format(problems))

    # If there were changes, wait a few seconds for them to propagate
    if were_changes:
        print 'Delaying {} seconds for change propagation'.format(
            PROPAGATION_DELAY_SECONDS)
        time.sleep(PROPAGATION_DELAY_SECONDS)

    # Successful execution.
    custom_resource_response.succeed(event, context, data,
                                     physical_resource_id)
コード例 #3
0
def handler(event, context):

    props = properties.load(event, {
        'Input': properties.Dictionary(),
    })

    stack_name = aws_utils.get_stack_name_from_stack_arn(event['StackId'])
    physical_resource_id = stack_name + '-' + event['LogicalResourceId']

    output = _process_dict(props.Input)

    custom_resource_response.succeed(event, context, output,
                                     physical_resource_id)
コード例 #4
0
def handler(event, context):

    # This resource does nothing. It exists so that deployment stacks can be created
    # before any resource groups have been defined. In such cases the Resources list
    # would be empty, which CloudFormation doesn't allow, so the lmbr_aws client inserts
    # this resource into the deployment template when no other resources are defined
    # by the template.

    props = properties.load(event, {})

    data = {}

    physical_resource_id = 'CloudCanvas:EmptyDeployment:{}'.format(
        aws_utils.get_stack_name_from_stack_arn(event['StackId']))

    custom_resource_response.succeed(event, context, data,
                                     physical_resource_id)
コード例 #5
0
def get_access_control_role_name(stack_arn, logical_role_name):
    '''Generates a role name based on a stack name and a logical role name.

    Args:

        stack_arn - The arn of the stack.

        logical_role_name: Appended to the stack name to construct the actual role name.

    '''

    # Expecting stack names like: {project-name}-{deployment-name}-{resource-group-name}-{random-stuff}.
    # We shorten the {project-name}-{deployment-name}-{resource-group-name} part to the point that we
    # can append {random-stuff} and the role's logical name and end up with a name that meets the max
    # role name length requirement.

    stack_name = aws_utils.get_stack_name_from_stack_arn(stack_arn)

    if len(stack_name) + len(logical_role_name) + 1 <= MAX_ROLE_NAME_LENGTH:

        role_name = stack_name + '-' + logical_role_name

    else:

        last_dash = stack_name.rfind('-')
        if last_dash == -1:
            raise RuntimeError(
                'Stack name does not have the expected format: {}'.format(
                    stack_name))

        root_part = stack_name[:last_dash]
        random_part = stack_name[last_dash + 1:]

        root_part_len = MAX_ROLE_NAME_LENGTH - (len(random_part) +
                                                len(logical_role_name) + 2)
        if root_part_len < 0:
            raise RuntimeError('The logical role name is too long: {}'.format(
                logical_role_name))

        root_part = root_part[:root_part_len]

        role_name = root_part + '-' + random_part + '-' + logical_role_name

    return role_name
コード例 #6
0
def handler(event, context):
    props = properties.load(
        event,
        {
            'ClientApps':
            properties.StringOrListOfString(),
            'ExplicitAuthFlows':
            properties.StringOrListOfString(default=[]),
            'RefreshTokenValidity':
            properties.String('30'),
            'ConfigurationKey':
            properties.String(
            ),  ##this is only here to force the resource handler to execute on each update to the deployment
            'LambdaConfig':
            properties.Dictionary({}),
            'PoolName':
            properties.String(),
            'Groups':
            properties.ObjectOrListOfObject(
                default=[],
                schema={
                    'Name': properties.String(),
                    'Description': properties.String(''),
                    'Role': properties.String(),
                    'Precedence': properties.String('99')
                }),
            'AllowAdminCreateUserOnly':
            properties.String('')
        })

    #give the identity pool a unique name per stack
    stack_name = aws_utils.get_stack_name_from_stack_arn(event['StackId'])
    stack_name = stack_name.replace(
        '-', ' '
    )  # Prepare stack_name to be used by _associate_user_pool_with_player_access
    pool_name = props.PoolName.replace('-', ' ')
    pool_name = stack_name + pool_name
    cognito_idp_client = user_pool.get_idp_client()
    pool_id = event.get('PhysicalResourceId')
    found_pool = user_pool.get_user_pool(pool_id)

    request_type = event['RequestType']

    if request_type == 'Delete':
        if found_pool != None:
            cognito_idp_client.delete_user_pool(UserPoolId=pool_id)
        data = {}

    else:
        #if the pool exists just update it, otherwise create a new one

        mfaConfig = 'OFF'  # MFA is currently unsupported by Lumberyard
        # Users are automatically prompted to verify these things.
        # At least one auto-verified thing (email or phone) is required to allow password recovery.
        auto_verified_attributes = ['email']

        client_app_data = {}
        lambda_config = props.LambdaConfig

        user_pool.validate_identity_metadata(event['StackId'],
                                             event['LogicalResourceId'],
                                             props.ClientApps)
        admin_create_user_config = __get_admin_create_user_config(
            props.AllowAdminCreateUserOnly)
        print json.dumps(admin_create_user_config)

        if found_pool != None:  # Update
            response = cognito_idp_client.update_user_pool(
                UserPoolId=pool_id,
                MfaConfiguration=mfaConfig,
                AutoVerifiedAttributes=auto_verified_attributes,
                LambdaConfig=lambda_config,
                AdminCreateUserConfig=admin_create_user_config)

            existing_client_apps = user_pool.get_client_apps(pool_id)
            client_app_data = update_client_apps(pool_id, props.ClientApps,
                                                 existing_client_apps, False,
                                                 props.ExplicitAuthFlows,
                                                 props.RefreshTokenValidity)

            response = cognito_idp_client.list_groups(UserPoolId=pool_id)

            found_groups = {}
            for actual_group in response['Groups']:
                group_name = actual_group['GroupName']
                for requested_group in props.Groups:
                    # does the group exist in the resource template
                    if group_name == requested_group.Name:
                        found_groups.update({group_name: True})
                        break

                #delete the group as it is no longer in the resource template
                if group_name not in found_groups:
                    cognito_idp_client.delete_group(
                        GroupName=actual_group['GroupName'],
                        UserPoolId=pool_id)

            print "Found groups=>", json.dumps(found_groups)
            #iterate the groups defined in the user pool resource template
            for group in props.Groups:
                #update the group as it is currently a group in the user pool
                group_definition = __generate_group_defintion(pool_id, group)
                print "Group '{}' is defined by {}".format(
                    group.Name, json.dumps(group_definition))
                if group.Name in found_groups:
                    cognito_idp_client.update_group(**group_definition)
                else:
                    #group is a new group on the user pool
                    cognito_idp_client.create_group(**group_definition)

        else:  # Create
            response = cognito_idp_client.create_user_pool(
                PoolName=pool_name,
                MfaConfiguration=mfaConfig,
                AutoVerifiedAttributes=auto_verified_attributes,
                LambdaConfig=lambda_config,
                AdminCreateUserConfig=admin_create_user_config)
            pool_id = response['UserPool']['Id']
            print 'User pool creation response: ', response
            for group in props.Groups:
                group_definition = __generate_group_defintion(pool_id, group)
                print "Group '{}' is defined by {}".format(
                    group.Name, json.dumps(group_definition))
                cognito_idp_client.create_group(**group_definition)

            client_app_data = update_client_apps(pool_id, props.ClientApps, [],
                                                 False,
                                                 props.ExplicitAuthFlows,
                                                 props.RefreshTokenValidity)

        updated_resources = {
            event['StackId']: {
                event['LogicalResourceId']: {
                    'physical_id': pool_id,
                    'client_apps': {
                        client_app['ClientName']: {
                            'client_id': client_app['ClientId']
                        }
                        for client_app in client_app_data['Created'] +
                        client_app_data['Updated']
                    }
                }
            }
        }

        identity_pool.update_cognito_identity_providers(
            event['StackId'], pool_id, updated_resources)

        data = {
            'UserPoolName': pool_name,
            'UserPoolId': pool_id,
            'ClientApps': client_app_data,
        }

    physical_resource_id = pool_id

    custom_resource_response.succeed(event, context, data,
                                     physical_resource_id)
コード例 #7
0
def handler(event, context):

    props = properties.load(event, {
            'ConfigurationBucket': properties.String(),
            'ConfigurationKey': properties.String(), ##this is only here to force the resource handler to execute on each update to the deployment
            'IdentityPoolName': properties.String(),
            'UseAuthSettingsObject': properties.String(),
            'AllowUnauthenticatedIdentities': properties.String(),
            'DeveloperProviderName': properties.String(default=''),
            'Roles': properties.Object( default={}, 
            schema={
                '*': properties.String()
            }),
            'RoleMappings': properties.Object(default={},
                schema={
                    'Cognito': properties.Object(default={}, schema={
                        'Type': properties.String(''),
                        'AmbiguousRoleResolution': properties.String('')
                    })
                }
            )
        })

    #give the identity pool a unique name per stack
    stack_name = aws_utils.get_stack_name_from_stack_arn(event['StackId'])
    identity_pool_name = stack_name+props.IdentityPoolName
    identity_pool_name = identity_pool_name.replace('-', ' ')
    identity_client = identity_pool.get_identity_client()
    identity_pool_id = event.get('PhysicalResourceId')
    found_pool = identity_pool.get_identity_pool(identity_pool_id)

    request_type = event['RequestType']
    if request_type == 'Delete':
        if found_pool != None:
            identity_client.delete_identity_pool(IdentityPoolId=identity_pool_id) 
        data = {}       

    else:
        use_auth_settings_object = props.UseAuthSettingsObject.lower() == 'true'
        supported_login_providers = {}

        if use_auth_settings_object == True:
            #download the auth settings from s3
            player_access_key = 'player-access/'+constant.AUTH_SETTINGS_FILENAME
            auth_doc = json.loads(_load_doc_from_s3(props.ConfigurationBucket, player_access_key))             

            #if the doc has entries add them to the supported_login_providers dictionary
            if len(auth_doc) > 0:
                for key, value in auth_doc.iteritems():
                    supported_login_providers[value['provider_uri']] = value['app_id']         

        cognito_identity_providers = identity_pool.get_cognito_identity_providers(event['StackId'], event['LogicalResourceId'])

        print 'Identity Providers: ', cognito_identity_providers
        allow_anonymous = props.AllowUnauthenticatedIdentities.lower() == 'true'
        #if the pool exists just update it, otherwise create a new one
        
        args = {
            'IdentityPoolName': identity_pool_name, 
            'AllowUnauthenticatedIdentities': allow_anonymous,
            'SupportedLoginProviders': supported_login_providers, 
            'CognitoIdentityProviders': cognito_identity_providers
        }
        
        if props.DeveloperProviderName:
            args['DeveloperProviderName'] = props.DeveloperProviderName
        
        if found_pool != None:
           identity_client.update_identity_pool(IdentityPoolId=identity_pool_id, **args)    
        else:
           response = identity_client.create_identity_pool(**args) 
           identity_pool_id=response['IdentityPoolId'] 

        #update the roles for the pool
        role_mappings = {}
        if props.RoleMappings.Cognito.Type and len(cognito_identity_providers) > 0:
            print 'Adding role mappings for cognito', props.RoleMappings.Cognito.__dict__
            role_mappings['{}:{}'.format(cognito_identity_providers[0]['ProviderName'],cognito_identity_providers[0]['ClientId'])]=props.RoleMappings.Cognito.__dict__

        print "Role Mappings: ", role_mappings
        identity_client.set_identity_pool_roles(
            IdentityPoolId=identity_pool_id,
            Roles=props.Roles.__dict__,
            RoleMappings=role_mappings)

        data = {
                'IdentityPoolName': identity_pool_name,
                'IdentityPoolId': identity_pool_id       
        }  
    
    physical_resource_id = identity_pool_id

    custom_resource_response.succeed(event, context, data, physical_resource_id)