def handler(event, context): 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 'FeatureStack': properties.String(default=''), 'DeploymentStack': properties.String(default='')}) if props.FeatureStack is '' and props.DeploymentStack is '': raise ValidationError('A value for the FeatureStack property or the DeploymentStack property must be provided.') if props.FeatureStack is not '' and props.DeploymentStack is not '': raise ValidationError('A value for only the FeatureStack property or the DeploymentStack property can be provided.') data = {} physical_resource_id = 'CloudCanvas:PlayerAccess:{stack_name}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn(event['StackId'])) if props.FeatureStack is not '': feature_info = discovery_utils.FeatureInfo(props.FeatureStack) # The PlayerAccess resources in feature stacks will be created before # the deployment access stack, and the Player role, is created. In # this case it is OK for us to do nothing and wait for the PlayerAccess # resource defined by the deployment access stack to be created. It # will initialize the role at athat time. role_name = _find_player_role(feature_info.deployment) if role_name is not None: _process_feature_stack(event['RequestType'], feature_info, role_name) else: # DeploymentStack _process_deployment_stack(event['RequestType'], props.DeploymentStack) custom_resource_response.succeed(event, context, data, 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=discovery_utils.get_stack_name_from_stack_arn( event['StackId']), resource_group_name=props.ResourceGroupName) custom_resource_response.succeed(event, context, data, physical_resource_id)
def test_succeed(self): event = { 'StackId': 'test-stack-id', 'RequestId': 'test-request-id', 'LogicalResourceId': 'test-logical-resource-id', 'ResponseURL': 'https://test-host/test-path/test-path?test-arg=test-value' } context = { } data = { 'test-data-key': 'test-data-value' } physical_resource_id = 'test-physical-resoruce-id' with mock.patch('httplib.HTTPSConnection') as mock_HTTPSConnection: mock_connection = mock_HTTPSConnection.return_value mock_getresponse = mock_connection.getresponse mock_response = mock.MagicMock() mock_response.status = httplib.OK mock_getresponse.return_value = mock_response mock_request = mock_connection.request custom_resource_response.succeed(event, context, data, physical_resource_id) mock_HTTPSConnection.assert_called_with('test-host') mock_request.assert_called_with('PUT', '/test-path/test-path?test-arg=test-value', '{"Status": "SUCCESS", "StackId": "test-stack-id", "PhysicalResourceId": "test-physical-resoruce-id", "RequestId": "test-request-id", "Data": {"test-data-key": "test-data-value"}, "LogicalResourceId": "test-logical-resource-id"}')
def handler(event, context): props = properties.load( event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'DeploymentName': properties.String() }) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': '{}/deployment/{}'.format(props.ConfigurationKey, props.DeploymentName), 'DeploymentTemplateURL': 'https://s3.amazonaws.com/{}/{}/deployment/{}/deployment-template.json' .format(props.ConfigurationBucket, props.ConfigurationKey, props.DeploymentName), 'AccessTemplateURL': 'https://s3.amazonaws.com/{}/{}/deployment-access-template-{}.json'. format(props.ConfigurationBucket, props.ConfigurationKey, props.DeploymentName), 'DeploymentName': props.DeploymentName } physical_resource_id = 'CloudCanvas:DeploymentConfiguration:{}:{}'.format( discovery_utils.get_stack_name_from_stack_arn(event['StackId']), props.DeploymentName) custom_resource_response.succeed(event, context, data, physical_resource_id)
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)
def handler(event, context): 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 'RoleLogicalId': properties.String(), 'MetadataKey': properties.String(), 'PhysicalResourceId': properties.String(), 'UsePropagationDelay': properties.String(), 'RequireRoleExists': properties.String(default='true'), 'ResourceGroupStack': properties.String(default=''), 'DeploymentStack': properties.String(default='')}) if props.ResourceGroupStack is '' and props.DeploymentStack is '': raise ValidationError('A value for the ResourceGroupStack property or the DeploymentStack property must be provided.') if props.ResourceGroupStack is not '' and props.DeploymentStack is not '': raise ValidationError('A value for only the ResourceGroupStack property or the DeploymentStack property can be provided.') use_propagation_delay = props.UsePropagationDelay.lower() == 'true' data = {} stack_infos = [] if props.ResourceGroupStack is not '': resource_group_info = stack_info.ResourceGroupInfo(props.ResourceGroupStack) # create a list of stack-infos, starting at the resource group level and working our way upward stack_infos = _build_stack_infos_list(resource_group_info) else: # DeploymentStack deployment_info = stack_info.DeploymentInfo(props.DeploymentStack) # create a list of stack-infos, starting at the deployment level and working our way upward stack_infos = _build_stack_infos_list(deployment_info) # go through each of the stack infos, trying to find the specified role for stack in stack_infos: role = stack.resources.get_by_logical_id(props.RoleLogicalId, expected_type='AWS::IAM::Role', optional=True) if role is not None: break role_physical_id = None if role is not None: role_physical_id = role.physical_id if role_physical_id is None: if props.RequireRoleExists.lower() == 'true': raise ValidationError('Could not find role \'{}\'.'.format(props.RoleLogicalId)) else: if type(stack_infos[0]) is stack_info.ResourceGroupInfo: _process_resource_group_stack(event['RequestType'], stack_infos[0], role_physical_id, props.MetadataKey, use_propagation_delay) else: for resource_group_info in stack_infos[0].resource_groups: _process_resource_group_stack(event['RequestType'], resource_group_info, role_physical_id, props.MetadataKey, use_propagation_delay) custom_resource_response.succeed(event, context, data, props.PhysicalResourceId)
def handler(event, context): props = properties.load(event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'FunctionName': properties.String(), 'Settings': properties.Object( default={}, schema={ '*': properties.String() }), 'Runtime': properties.String() }) request_type = event['RequestType'] if request_type == 'Delete': physical_resource_name = event['PhysicalResourceId'] resource_uuid = physical_resource_name.split(':')[4] _delete_role(resource_uuid) data = {} else: if request_type == 'Create': resource_uuid = uuid4() physical_resource_name = 'CloudCanvas:LambdaConfiguration:{stack_name}:{function_name}:{uuid}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn(event['StackId']), function_name=props.FunctionName, uuid=resource_uuid) role_arn = _create_role(event['StackId'], props.FunctionName, resource_uuid) else: # Update physical_resource_name = event['PhysicalResourceId'] resource_uuid = physical_resource_name.split(':')[4] role_arn = _update_role(event['StackId'], props.FunctionName, resource_uuid) output_key = '{}/feature-code.zip'.format(props.ConfigurationKey) output_key = _inject_settings(props.Settings.__dict__, props.Runtime, props.ConfigurationBucket, output_key, props.FunctionName) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': output_key, 'Runtime': props.Runtime, 'Role': role_arn } custom_resource_response.succeed(event, context, data, physical_resource_name)
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)
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)
def handler(event, context): 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 'FeatureStack': properties.String(default=''), 'DeploymentStack': properties.String(default='') }) if props.FeatureStack is '' and props.DeploymentStack is '': raise ValidationError( 'A value for the FeatureStack property or the DeploymentStack property must be provided.' ) if props.FeatureStack is not '' and props.DeploymentStack is not '': raise ValidationError( 'A value for only the FeatureStack property or the DeploymentStack property can be provided.' ) data = {} physical_resource_id = 'CloudCanvas:PlayerAccess:{stack_name}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn( event['StackId'])) if props.FeatureStack is not '': feature_info = discovery_utils.FeatureInfo(props.FeatureStack) # The PlayerAccess resources in feature stacks will be created before # the deployment access stack, and the Player role, is created. In # this case it is OK for us to do nothing and wait for the PlayerAccess # resource defined by the deployment access stack to be created. It # will initialize the role at athat time. role_name = _find_player_role(feature_info.deployment) if role_name is not None: _process_feature_stack(event['RequestType'], feature_info, role_name) else: # DeploymentStack _process_deployment_stack(event['RequestType'], props.DeploymentStack) custom_resource_response.succeed(event, context, data, physical_resource_id)
def handler(event, context): props = properties.load(event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'FeatureName': properties.String()}) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': '{}/feature/{}'.format(props.ConfigurationKey, props.FeatureName), 'TemplateURL': 'https://s3.amazonaws.com/{}/{}/feature/{}/feature-template.json'.format(props.ConfigurationBucket, props.ConfigurationKey, props.FeatureName) } physical_resource_id = 'CloudCanvas:LambdaConfiguration:{stack_name}:{feature_name}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn(event['StackId']), feature_name=props.FeatureName) custom_resource_response.succeed(event, context, data, physical_resource_id)
def handler(event, context): props = properties.load(event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'DeploymentName': properties.String()}) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': '{}/deployment/{}'.format(props.ConfigurationKey, props.DeploymentName), 'DeploymentTemplateURL': 'https://s3.amazonaws.com/{}/{}/deployment/{}/deployment-template.json'.format(props.ConfigurationBucket, props.ConfigurationKey, props.DeploymentName), 'AccessTemplateURL': 'https://s3.amazonaws.com/{}/{}/deployment-access-template-{}.json'.format(props.ConfigurationBucket, props.ConfigurationKey, props.DeploymentName), 'DeploymentName': props.DeploymentName } physical_resource_id = 'CloudCanvas:DeploymentConfiguration:{}:{}'.format(discovery_utils.get_stack_name_from_stack_arn(event['StackId']), props.DeploymentName) custom_resource_response.succeed(event, context, data, physical_resource_id)
def handler(event, context): props = properties.load(event, {'MainBucket': properties.String()}) s3 = boto3.client('s3') if event['RequestType'] == 'Create': for file_name in bucket_data: s3.put_object(Bucket=props.MainBucket, Key=file_name, Body=bucket_data[file_name]) elif event['RequestType'] == 'Delete': for file_name in bucket_data: s3.delete_object(Bucket=props.MainBucket, Key=file_name) physical_id = 'CloudCanvas:PopulateMainBucket:{stack_name}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn( event['StackId'])) return custom_resource_response.succeed(event, context, {}, physical_id)
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)
def handler(event, context): props = properties.load( event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'FunctionName': properties.String(), 'Settings': properties.Object(default={}, schema={'*': properties.String()}), 'Runtime': properties.String() }) request_type = event['RequestType'] stack_arn = event['StackId'] logical_role_name = props.FunctionName id_data = aws_utils.get_data_from_custom_physical_resource_id( event.get('PhysicalResourceId', None)) if request_type == 'Delete': role_utils.delete_access_control_role(id_data, logical_role_name) response_data = {} else: if request_type == 'Create': project_service_lambda_arn = _get_project_service_lambda_arn( stack_arn) assume_role_service = 'lambda.amazonaws.com' role_arn = role_utils.create_access_control_role( id_data, stack_arn, logical_role_name, assume_role_service, default_policy=get_default_policy(project_service_lambda_arn)) elif request_type == 'Update': role_arn = role_utils.get_access_control_role_arn( id_data, logical_role_name) else: raise RuntimeError( 'Unexpected request type: {}'.format(request_type)) _add_built_in_settings(props.Settings.__dict__, stack_arn) # Check if we have a folder just for this function, if not use the default input_key = _get_input_key(props) output_key = _inject_settings(props.Settings.__dict__, props.Runtime, props.ConfigurationBucket, input_key, props.FunctionName) response_data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': output_key, 'Runtime': props.Runtime, 'Role': role_arn, 'RoleName': role_utils.get_access_control_role_name(stack_arn, logical_role_name) } physical_resource_id = aws_utils.construct_custom_physical_resource_id_with_data( stack_arn, event['LogicalResourceId'], id_data) custom_resource_response.succeed(event, context, response_data, physical_resource_id)
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(), 'Roles': properties.Object(default={}, schema={'*': properties.String()}), }) #give the identity pool a unique name per stack stack_name = discovery_utils.get_stack_name_from_stack_arn( event['StackId']) identity_pool_name = props.IdentityPoolName + stack_name identity_pool_name = identity_pool_name.replace('-', ' ') cognito_client = boto3.client('cognito-identity') found_pool = _find_identity_pool(cognito_client, identity_pool_name) identity_pool_id = None request_type = event['RequestType'] if request_type == 'Delete': if found_pool != None: identity_pool_id = found_pool['IdentityPoolId'] cognito_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/auth-settings.json' 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'] allow_anonymous = props.AllowUnauthenticatedIdentities.lower( ) == 'true' #if the pool exists just update it, otherwise create a new one if found_pool != None: response = cognito_client.update_identity_pool( IdentityPoolId=found_pool['IdentityPoolId'], IdentityPoolName=identity_pool_name, AllowUnauthenticatedIdentities=allow_anonymous, SupportedLoginProviders=supported_login_providers) identity_pool_id = found_pool['IdentityPoolId'] else: response = cognito_client.create_identity_pool( IdentityPoolName=identity_pool_name, AllowUnauthenticatedIdentities=allow_anonymous, SupportedLoginProviders=supported_login_providers) identity_pool_id = response['IdentityPoolId'] #now update the roles for the pool cognito_client.set_identity_pool_roles(IdentityPoolId=identity_pool_id, Roles=props.Roles.__dict__) 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)
def handler(event, context): props = properties.load( event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'FunctionName': properties.String(), 'Settings': properties.Object(default={}, schema={'*': properties.String()}), 'Runtime': properties.String() }) request_type = event['RequestType'] stack_arn = event['StackId'] logical_role_name = event['LogicalResourceId'] physical_resource_name = event.get('PhysicalResourceId', None) # None when create request if request_type == 'Delete': role_utils.delete_role(stack_arn, logical_role_name, POLICY_NAME) data = {} else: policy_metadata_filter = lambda entry: _policy_metadata_filter( entry, props.FunctionName) if request_type == 'Create': physical_resource_name = discovery_utils.get_stack_name_from_stack_arn( stack_arn) + '-' + event['LogicalResourceId'] assume_role_service = 'lambda.amazonaws.com' role_arn = role_utils.create_role(stack_arn, logical_role_name, POLICY_NAME, assume_role_service, DEFAULT_POLICY_STATEMENTS, policy_metadata_filter) elif request_type == 'Update': role_arn = role_utils.update_role(stack_arn, logical_role_name, POLICY_NAME, DEFAULT_POLICY_STATEMENTS, policy_metadata_filter) else: raise ValidationError( 'Unexpected request type: {}'.format(request_type)) input_key = '{}/lambda-function-code.zip'.format( props.ConfigurationKey) output_key = _inject_settings(props.Settings.__dict__, props.Runtime, props.ConfigurationBucket, input_key, props.FunctionName) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': output_key, 'Runtime': props.Runtime, 'Role': role_arn } custom_resource_response.succeed(event, context, data, physical_resource_name)
def handler(event, context): props = properties.load( event, { 'ConfigurationBucket': properties.String(), 'ConfigurationKey': properties.String(), 'FunctionName': properties.String(), 'Settings': properties.Object(default={}, schema={'*': properties.String()}), 'Runtime': properties.String() }) request_type = event['RequestType'] if request_type == 'Delete': physical_resource_name = event['PhysicalResourceId'] resource_uuid = physical_resource_name.split(':')[4] _delete_role(resource_uuid) data = {} else: if request_type == 'Create': resource_uuid = uuid4() physical_resource_name = 'CloudCanvas:LambdaConfiguration:{stack_name}:{function_name}:{uuid}'.format( stack_name=discovery_utils.get_stack_name_from_stack_arn( event['StackId']), function_name=props.FunctionName, uuid=resource_uuid) role_arn = _create_role(event['StackId'], props.FunctionName, resource_uuid) else: # Update physical_resource_name = event['PhysicalResourceId'] resource_uuid = physical_resource_name.split(':')[4] role_arn = _update_role(event['StackId'], props.FunctionName, resource_uuid) output_key = '{}/feature-code.zip'.format(props.ConfigurationKey) output_key = _inject_settings(props.Settings.__dict__, props.Runtime, props.ConfigurationBucket, output_key, props.FunctionName) data = { 'ConfigurationBucket': props.ConfigurationBucket, 'ConfigurationKey': output_key, 'Runtime': props.Runtime, 'Role': role_arn } custom_resource_response.succeed(event, context, data, physical_resource_name)
def handler(event, context): request_type = event['RequestType'] logical_resource_id = event['LogicalResourceId'] logical_role_name = logical_resource_id owning_stack_info = stack_info.get_stack_info(event['StackId']) rest_api_resource_name = owning_stack_info.stack_name + '-' + logical_resource_id id_data = aws_utils.get_data_from_custom_physical_resource_id( event.get('PhysicalResourceId', None)) response_data = {} if request_type == 'Create': props = properties.load(event, PROPERTY_SCHEMA) role_arn = role_utils.create_access_control_role( id_data, owning_stack_info.stack_arn, logical_role_name, API_GATEWAY_SERVICE_NAME) swagger_content = get_configured_swagger_content( owning_stack_info, props, role_arn, rest_api_resource_name) rest_api_id = create_api_gateway(props, swagger_content) response_data['Url'] = get_api_url(rest_api_id, owning_stack_info.region) id_data['RestApiId'] = rest_api_id elif request_type == 'Update': rest_api_id = id_data.get('RestApiId', None) if not rest_api_id: raise RuntimeError( 'No RestApiId found in id_data: {}'.format(id_data)) props = properties.load(event, PROPERTY_SCHEMA) role_arn = role_utils.get_access_control_role_arn( id_data, logical_role_name) swagger_content = get_configured_swagger_content( owning_stack_info, props, role_arn, rest_api_resource_name) update_api_gateway(rest_api_id, props, swagger_content) response_data['Url'] = get_api_url(rest_api_id, owning_stack_info.region) elif request_type == 'Delete': if not id_data: # The will be no data in the id if Cloud Formation cancels a resource creation # (due to a failure in another resource) before it processes the resource create # response. Appearently Cloud Formation has an internal temporary id for the # resource and uses it for the delete request. # # Unfortunalty there isn't a good way to deal with this case. We don't have the # id data, so we can't clean up the things it identifies. At best we can allow the # stack cleanup to continue, leaving the rest API behind and role behind. print 'WARNING: No id_data provided on delete.'.format(id_data) else: rest_api_id = id_data.get('RestApiId', None) if not rest_api_id: raise RuntimeError( 'No RestApiId found in id_data: {}'.format(id_data)) delete_api_gateway(rest_api_id) del id_data['RestApiId'] role_utils.delete_access_control_role(id_data, logical_role_name) else: raise RuntimeError('Invalid RequestType: {}'.format(request_type)) physical_resource_id = aws_utils.construct_custom_physical_resource_id_with_data( event['StackId'], logical_resource_id, id_data) custom_resource_response.succeed(event, context, response_data, physical_resource_id)
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(), 'Roles': properties.Object( default={}, schema={ '*': properties.String() }), }) #give the identity pool a unique name per stack stack_name = discovery_utils.get_stack_name_from_stack_arn(event['StackId']) identity_pool_name = props.IdentityPoolName + stack_name identity_pool_name = identity_pool_name.replace('-', ' ') cognito_client = boto3.client('cognito-identity') found_pool = _find_identity_pool(cognito_client, identity_pool_name) identity_pool_id = None request_type = event['RequestType'] if request_type == 'Delete': if found_pool != None: identity_pool_id = found_pool['IdentityPoolId'] cognito_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/auth-settings.json' 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'] allow_anonymous = props.AllowUnauthenticatedIdentities.lower() == 'true' #if the pool exists just update it, otherwise create a new one if found_pool != None: response = cognito_client.update_identity_pool(IdentityPoolId=found_pool['IdentityPoolId'], IdentityPoolName=identity_pool_name, AllowUnauthenticatedIdentities=allow_anonymous, SupportedLoginProviders=supported_login_providers) identity_pool_id=found_pool['IdentityPoolId'] else: response = cognito_client.create_identity_pool(IdentityPoolName = identity_pool_name, AllowUnauthenticatedIdentities=allow_anonymous, SupportedLoginProviders=supported_login_providers) identity_pool_id=response['IdentityPoolId'] #now update the roles for the pool cognito_client.set_identity_pool_roles(IdentityPoolId=identity_pool_id, Roles=props.Roles.__dict__) 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)
def handler(event, context): if event['RequestType'] != 'Create': return custom_resource_response.succeed(event, context, {}, "PopulateTables") props = properties.load(event, { 'AchievementsTable': properties.String(), 'DailyGiftTable': properties.String(), 'ItemTable': properties.String(), 'MessageOfTheDayTable': properties.String(), 'MissionTable': properties.String(), 'GameDataLUTable' : properties.String() }) achievementsTable = dynamodb.Table(props.AchievementsTable) dailyGiftTable = dynamodb.Table(props.DailyGiftTable) itemTable = dynamodb.Table(props.ItemTable) messageOfTheDayTable = dynamodb.Table(props.MessageOfTheDayTable) missionTable = dynamodb.Table(props.MissionTable) gameDataLUTable = dynamodb.Table(props.GameDataLUTable) achievement = { "CompletionCriteria": "player.LastScore > 300", "Description": "You survived for 300 seconds!", "ItemReward": "FancyShip", "Name": "300SecondSurvival" } achievementsTable.put_item(Item=achievement) dailyGift = { "Date": "12-06-2015", "EndDate": "infinity", "Gifts": [ { "Name": "ShieldMission", "Type": "mission" } ] } dailyGiftTable.put_item(Item=dailyGift) shieldItem = { "Name" : "Shield", "Persist" : False } fancyShipItem = { "Name" : "FancyShip", "Persist" : True } itemTable.put_item(Item=shieldItem) itemTable.put_item(Item=fancyShipItem) messageOfTheDay = { "Date": "12-06-2015", "EndDate": "infinity", "Message": "Message of the Day!" } messageOfTheDayTable.put_item(Item=messageOfTheDay) mission = { "CompletionText": "You completed the Shield Mission!", "Description": "Complete 1 game to get the Shield!", "ItemReward": "Shield", "Name": "ShieldMission", "NumberOfGamesReq": 1 } missionTable.put_item(Item=mission) dailyGiftCached = { "CachedItem": { "Date": "12-06-2015", "EndDate": "infinity", "Gifts": [ { "Name": "ShieldMission", "Type": "mission" } ] }, "CachedItemName": "TodaysGift" } messageOfTheDayCached = { "CachedItem": { "Date": "12-06-2015", "EndDate": "infinity", "Message": "Message of the Day!" }, "CachedItemName": "TodaysMessage" } gameDataLUTable.put_item(Item=dailyGiftCached) gameDataLUTable.put_item(Item=messageOfTheDayCached) custom_resource_response.succeed(event, context, {}, "PopulateTables")
def handler(event, context): custom_resource_response.succeed(event, context, {}, '*')
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)