def handler(event, context): """Entry point for the Custom::ResourceGroupConfiguration resource handler.""" 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/{}/{}'.format( props.ConfigurationBucket, props.ConfigurationKey, props.ResourceGroupName, constant.RESOURCE_GROUP_TEMPLATE_FILENAME) } 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) return custom_resource_response.success_response(data, physical_resource_id)
def handler(event, context): request_type = event['RequestType'] stack_arn = event['StackId'] physical_resource_id = aws_utils.get_stack_name_from_stack_arn(stack_arn) + '-' + event['LogicalResourceId'] data = {} stack_manager = stack_info.StackInfoManager() stack = stack_manager.get_stack_info(stack_arn) if request_type == 'Delete': _clear_interface_refs(stack) return custom_resource_response.success_response(data, physical_resource_id) if not stack.is_deployment_stack: raise RuntimeError("InterfaceDependecyResolver can only be stood up on a deployment stack") resource_groups = stack.resource_groups configuration_bucket_name = stack.project.configuration_bucket if not configuration_bucket_name: raise RuntimeError('Not adding service settings because there is no project configuration bucket.') service_directory = ServiceDirectory(configuration_bucket_name) interface_deps = event["ResourceProperties"].get("InterfaceDependencies", {}) _clear_interface_refs(stack) for gem, interface_list in interface_deps.iteritems(): for interface in interface_list: print "getting url for interface {} from gem {} to use in {}:{}".format(interface["id"], interface["gem"], gem, interface["function"]) interfaces = service_directory.get_interface_services(stack.deployment_name, interface["id"]) if len(interfaces) > 0: _add_url_to_lambda(interfaces[0], gem, interface["function"], stack) else: print "Failed to lookup interface {}".format(len(interfaces)) return custom_resource_response.success_response(data, physical_resource_id)
def handler(event, context): '''Entry point for the Custom::AccessControl resource 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_manager = stack_info.StackInfoManager() stack = stack_manager.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, event['ResourceProperties']['Gem'], 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. return custom_resource_response.success_response(data, physical_resource_id)
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) return custom_resource_response.success_response(output, physical_resource_id)
def handler(event, context): request_type = event['RequestType'] stack_arn = event['StackId'] physical_resource_id = aws_utils.get_stack_name_from_stack_arn(stack_arn) + '-' + event['LogicalResourceId'] data = {} stack_manager = stack_info.StackInfoManager() stack = stack_manager.get_stack_info(stack_arn) if request_type == 'Delete': _clear_interface_refs(stack) return custom_resource_response.success_response(data, physical_resource_id) if not stack.is_deployment_stack: raise RuntimeError("InterfaceDependencyResolver can only be stood up on a deployment stack") configuration_bucket_name = stack.project.configuration_bucket if not configuration_bucket_name: raise RuntimeError('Not adding service settings because there is no project configuration bucket.') service_directory = ServiceDirectory(configuration_bucket_name) interface_deps = event["ResourceProperties"].get("InterfaceDependencies", {}) # start by clearing the refs this function and role have to make sure no old permissions/interfaces linger _clear_interface_refs(stack) for gem, interface_list in iteritems(interface_deps): gem_function_info = {} for interface in interface_list: if not interface['function'] in gem_function_info: gem_function_info[interface['function']] = {"interfaces": []} interface_function_info = {"id": interface['id'], "gem": interface.get("gem", "CloudGemFramework")} if interface_function_info["gem"] == "CloudGemFramework": interface_function_info["url"] = _get_project_url( service_directory, interface['id']) interface_function_info["permittedArns"] = _get_permitted_arns( _get_resource_group(gem, stack), _get_project_interface_description( service_directory, interface["id"]) ) else: interface_function_info["url"] = _get_url( service_directory, stack, interface['id']) interface_function_info["permittedArns"] = _get_permitted_arns( _get_resource_group(gem, stack), _get_interface_description(service_directory, stack, interface["id"]) ) gem_function_info[interface['function']]["interfaces"].append( interface_function_info) _put_gem_function_info(gem, gem_function_info, stack) return custom_resource_response.success_response(data, physical_resource_id)
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'])) return custom_resource_response.success_response(data, physical_resource_id)
def __init__(self, stack_arn, source_resource_name, resource_type_name, data): self.__stack_arn = stack_arn self.__stack_name = aws_utils.get_stack_name_from_stack_arn(stack_arn) self.__source_resource_name = source_resource_name self.__resource_type_name = resource_type_name self.__permission_metadata = data.get('PermissionMetadata', {}) self.__service_api = data.get('ServiceApi', None) self.__arn_format = data.get('ArnFormat', None) self.__arn_url = data.get('ArnUrl', None) self.__display_info = data.get('DisplayInfo', None) self.__handler_url = data.get('HandlerUrl', None) self.__arn_function = data.get('ArnFunction', None) self.__handler_function = data.get('HandlerFunction', None) self._validate()
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}. # In practice role names are truncated to the max allowable length. stack_name = aws_utils.get_stack_name_from_stack_arn(stack_arn) role_name = sanitize_role_name(stack_name + '-' + logical_role_name) return role_name
def handler(event, context): properties = event["ResourceProperties"] stack_arn = event['StackId'] physical_resource_id = aws_utils.get_stack_name_from_stack_arn( stack_arn) + '-' + event['LogicalResourceId'] buckets = properties.get("Buckets", []) if not buckets: print "There were no buckets in the resource properties, returning early" return custom_resource_response.success_response({}, physical_resource_id) if event["RequestType"] != "Delete": return custom_resource_response.success_response({}, physical_resource_id) for bucket_name in buckets: clear_bucket(bucket_name) return custom_resource_response.success_response({}, physical_resource_id)
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)
def handler(event, context): stack_arn = event['StackId'] stack = stack_info.StackInfoManager().get_stack_info(stack_arn) if not stack.is_project_stack: raise RuntimeError( "Custom::ExternalResourceInstance can only be defined in the project stack." ) request_type = event['RequestType'] if request_type not in ['Create', 'Update', 'Delete']: raise RuntimeError('Unexpected request type: {}'.format(request_type)) if request_type in ['Create', 'Update']: _create_reference_metadata(event, stack) else: _delete_reference_metadata(event['LogicalResourceId'], stack) physical_resource_id = aws_utils.get_stack_name_from_stack_arn( stack_arn) + '-' + event['LogicalResourceId'] return custom_resource_response.success_response({}, physical_resource_id)
def handler(event, context): # Validate RequestType request_type = event['RequestType'] if request_type not in ['Create', 'Update', 'Delete']: raise RuntimeError('Unexpected request type: {}'.format(request_type)) stack_arn = event['StackId'] stack_manager = stack_info.StackInfoManager() stack = stack_manager.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'] if request_type == 'Delete': _delete_iot_policy(physical_resource_id) elif request_type == 'Update': _update_iot_policy(physical_resource_id, stack) elif request_type == 'Create': _create_iot_policy(physical_resource_id, stack) return custom_resource_response.success_response({}, physical_resource_id)
def __init__(self, stack_arn, source_resource_name, resource_type_name, lambda_dictionary, deleted, data): self.__stack_arn = stack_arn self.__stack_name = aws_utils.get_stack_name_from_stack_arn(stack_arn) self.__source_resource_name = source_resource_name self.__resource_type_name = resource_type_name self.__deleted = deleted self.__permission_metadata = data.get('PermissionMetadata', {}) self.__service_api = data.get('ServiceApi', None) self.__arn_format = data.get('ArnFormat', None) self.__arn_url = data.get('ArnUrl', None) self.__display_info = data.get('DisplayInfo', None) self.__handler_url = data.get('HandlerUrl', None) self.__arn_function = data.get('ArnFunction', None) self.__handler_function = data.get('HandlerFunction', None) self.__handler_function_version = None if self.__handler_function: lambda_data = lambda_dictionary.get( self.get_custom_resource_lambda_function_name(), None) self.__handler_function_version = lambda_data[ 'v'] if lambda_data else None # Backwards compatibility self._validate()
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_manager = stack_info.StackInfoManager() 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 = custom_resource_utils.get_embedded_physical_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( stack_manager, 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 return custom_resource_response.success_response(data, physical_resource_id)
def handler(event, context): request_type = event['RequestType'] logical_resource_id = event['LogicalResourceId'] properties = event['ResourceProperties'] physical_resource_id = aws_utils.get_stack_name_from_stack_arn( event['StackId']) + "-" + logical_resource_id domain_name = physical_resource_id + "-domain" workflow_type_name = physical_resource_id + "-workflow-type" if request_type == "Create": swf_client.register_domain(name=domain_name, workflowExecutionRetentionPeriodInDays="15") swf_client.register_workflow_type( domain=domain_name, name=workflow_type_name, version="1.0", defaultTaskStartToCloseTimeout=properties[ 'TaskStartToCloseTimeout'], defaultExecutionStartToCloseTimeout=properties[ 'ExecutionStartToCloseTimeout'], defaultTaskList=properties['TaskList'], defaultChildPolicy=properties['ChildPolicy']) for activity_type in properties['ActivityTypes']: swf_client.register_activity_type(domain=domain_name, name=activity_type, version="1.0") elif request_type == "Update": existing_types = set() params = {'domain': domain_name, 'registrationStatus': "REGISTERED"} while True: response = swf_client.list_activity_types(**params) existing_types.update( set([ item['activityType']['name'] for item in response['typeInfos'] ])) if 'nextPageToken' in response: params['nextPageToken'] = response['nextPageToken'] else: break for activity_type in properties['ActivityTypes']: if activity_type in existing_types: existing_types.discard(activity_type) else: swf_client.register_activity_type(domain=domain_name, name=activity_type, version="1.0") for activity_type in existing_types: swf_client.deprecate_activity_type(domain=domain_name, activityType={ 'name': activity_type, 'version': "1.0" }) elif request_type == "Delete": swf_client.deprecate_domain(name=domain_name) outputs = { 'DomainName': domain_name, 'WorkflowTypeName': workflow_type_name, 'ActivityTypes': properties['ActivityTypes'], 'TaskList': properties['TaskList']['name'] } return custom_resource_response.success_response(outputs, physical_resource_id)
def stack_name(self): return aws_utils.get_stack_name_from_stack_arn(self.stack_arn)
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_manager = stack_info.StackInfoManager() 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(stack_manager, 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(stack_manager, event['StackId'], pool_id, updated_resources) data = { 'UserPoolName': pool_name, 'UserPoolId': pool_id, 'ClientApps': client_app_data, } physical_resource_id = pool_id return custom_resource_response.success_response(data, physical_resource_id)