diff --git a/requirements/dev.txt b/requirements/dev.txt index 0d03166e75..07d399e592 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -2,7 +2,7 @@ coverage>=4.4.0 flake8>=3.3.0 tox>=2.2.1 pytest-cov>=2.4.0 -pylint>=1.7.2 +pylint>=1.7.2,<2.0 pyyaml>=4.2b1 # Test requirements diff --git a/samtranslator/model/iam.py b/samtranslator/model/iam.py index fc9039c28f..fe39be9623 100644 --- a/samtranslator/model/iam.py +++ b/samtranslator/model/iam.py @@ -9,7 +9,8 @@ class IAMRole(Resource): 'AssumeRolePolicyDocument': PropertyType(True, is_type(dict)), 'ManagedPolicyArns': PropertyType(False, is_type(list)), 'Path': PropertyType(False, is_str()), - 'Policies': PropertyType(False, is_type(list)) + 'Policies': PropertyType(False, is_type(list)), + 'PermissionsBoundary': PropertyType(False, is_str()) } runtime_attrs = { diff --git a/samtranslator/model/s3_utils/uri_parser.py b/samtranslator/model/s3_utils/uri_parser.py index b276ad6b6e..371cfb923f 100644 --- a/samtranslator/model/s3_utils/uri_parser.py +++ b/samtranslator/model/s3_utils/uri_parser.py @@ -43,7 +43,7 @@ def to_s3_uri(code_dict): raise TypeError("Code location should be a dictionary") if version: - uri += "?versionId=" + version + uri += "?versionId=" + version return uri diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 35207953cc..c9bdcfcb61 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -42,6 +42,7 @@ class SamFunction(SamResourceMacro): 'VpcConfig': PropertyType(False, is_type(dict)), 'Role': PropertyType(False, is_str()), 'Policies': PropertyType(False, one_of(is_str(), list_of(one_of(is_str(), is_type(dict), is_type(dict))))), + 'PermissionsBoundary': PropertyType(False, is_str()), 'Environment': PropertyType(False, dict_of(is_str(), is_type(dict))), 'Events': PropertyType(False, dict_of(is_str(), is_type(dict))), 'Tags': PropertyType(False, is_type(dict)), @@ -239,6 +240,7 @@ def _construct_role(self, managed_policy_map): execution_role.ManagedPolicyArns = list(managed_policy_arns) execution_role.Policies = policy_documents or None + execution_role.PermissionsBoundary = self.PermissionsBoundary return execution_role diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 7864a2abd8..918f458451 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -29,7 +29,8 @@ class Globals(object): "KmsKeyArn", "AutoPublishAlias", "Layers", - "DeploymentPreference" + "DeploymentPreference", + "PermissionsBoundary" ], # Everything except diff --git a/samtranslator/translator/translator.py b/samtranslator/translator/translator.py index f8b9618a4c..49cf2e7464 100644 --- a/samtranslator/translator/translator.py +++ b/samtranslator/translator/translator.py @@ -110,7 +110,7 @@ def translate(self, sam_template, parameter_values): if 'Transform' in template: del template['Transform'] - if len(document_errors) is 0: + if len(document_errors) == 0: template = intrinsics_resolver.resolve_sam_resource_id_refs(template, changed_logical_ids) template = intrinsics_resolver.resolve_sam_resource_refs(template, supported_resource_refs) return template diff --git a/tests/translator/input/function_with_permissions_boundary.yaml b/tests/translator/input/function_with_permissions_boundary.yaml new file mode 100644 index 0000000000..5cad58b7f9 --- /dev/null +++ b/tests/translator/input/function_with_permissions_boundary.yaml @@ -0,0 +1,9 @@ +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + PermissionsBoundary: arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary + diff --git a/tests/translator/input/globals_for_function.yaml b/tests/translator/input/globals_for_function.yaml index 202c32eac6..97fd5ae30c 100644 --- a/tests/translator/input/globals_for_function.yaml +++ b/tests/translator/input/globals_for_function.yaml @@ -16,6 +16,7 @@ Globals: tag1: value1 Tracing: Active AutoPublishAlias: live + PermissionsBoundary: arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary Layers: - !Sub arn:${AWS:Partition}:lambda:${AWS:Region}:${AWS:AccountId}:layer:MyLayer:1 @@ -41,6 +42,7 @@ Resources: newtag1: newvalue1 Tracing: PassThrough AutoPublishAlias: prod + PermissionsBoundary: arn:aws:1234:iam:boundary/OverridePermissionsBoundary Layers: - !Sub arn:${AWS:Partition}:lambda:${AWS:Region}:${AWS:AccountId}:layer:MyLayer2:2 diff --git a/tests/translator/output/aws-cn/function_with_permissions_boundary.json b/tests/translator/output/aws-cn/function_with_permissions_boundary.json new file mode 100644 index 0000000000..1adb21c16a --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_permissions_boundary.json @@ -0,0 +1,52 @@ +{ + "Resources": { + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} diff --git a/tests/translator/output/aws-cn/globals_for_function.json b/tests/translator/output/aws-cn/globals_for_function.json index 82f9da5a54..e2115176f0 100644 --- a/tests/translator/output/aws-cn/globals_for_function.json +++ b/tests/translator/output/aws-cn/globals_for_function.json @@ -7,6 +7,7 @@ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws-cn:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/OverridePermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -85,6 +86,7 @@ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws-cn:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -198,4 +200,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/function_with_permissions_boundary.json b/tests/translator/output/aws-us-gov/function_with_permissions_boundary.json new file mode 100644 index 0000000000..510988482d --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_permissions_boundary.json @@ -0,0 +1,52 @@ +{ + "Resources": { + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} diff --git a/tests/translator/output/aws-us-gov/globals_for_function.json b/tests/translator/output/aws-us-gov/globals_for_function.json index ad68dde1bb..d001267095 100644 --- a/tests/translator/output/aws-us-gov/globals_for_function.json +++ b/tests/translator/output/aws-us-gov/globals_for_function.json @@ -7,6 +7,7 @@ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws-us-gov:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/OverridePermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -85,6 +86,7 @@ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws-us-gov:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -198,4 +200,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/error_globals_unsupported_property.json b/tests/translator/output/error_globals_unsupported_property.json index 87a48e5174..4805f3f4ee 100644 --- a/tests/translator/output/error_globals_unsupported_property.json +++ b/tests/translator/output/error_globals_unsupported_property.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference']" + "errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary']" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference']" -} \ No newline at end of file + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary']" +} diff --git a/tests/translator/output/function_with_permissions_boundary.json b/tests/translator/output/function_with_permissions_boundary.json new file mode 100644 index 0000000000..ecd3a1e0b8 --- /dev/null +++ b/tests/translator/output/function_with_permissions_boundary.json @@ -0,0 +1,52 @@ +{ + "Resources": { + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/globals_for_function.json b/tests/translator/output/globals_for_function.json index 051c63fbe2..3006cce738 100644 --- a/tests/translator/output/globals_for_function.json +++ b/tests/translator/output/globals_for_function.json @@ -7,6 +7,7 @@ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/OverridePermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -85,6 +86,7 @@ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess" ], + "PermissionsBoundary": "arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -198,4 +200,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index a40b569c70..5f9d371ff0 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -206,6 +206,7 @@ class TestTranslatorEndToEnd(TestCase): 'function_with_global_layers', 'function_with_layers', 'function_with_many_layers', + 'function_with_permissions_boundary', 'function_with_policy_templates', 'function_with_sns_event_source_all_parameters', 'globals_for_function', diff --git a/tests/translator/validator/test_validator.py b/tests/translator/validator/test_validator.py index 34f0fdac4b..ebf1ad6a87 100644 --- a/tests/translator/validator/test_validator.py +++ b/tests/translator/validator/test_validator.py @@ -57,6 +57,7 @@ 'function_with_resource_refs', 'function_with_deployment_and_custom_role', 'function_with_deployment_no_service_role', + 'function_with_permissions_boundary', 'function_with_policy_templates', 'function_with_sns_event_source_all_parameters', 'globals_for_function', diff --git a/versions/2016-10-31.md b/versions/2016-10-31.md index ad6fea0a8e..f3a8b60883 100644 --- a/versions/2016-10-31.md +++ b/versions/2016-10-31.md @@ -113,6 +113,7 @@ MemorySize | `integer` | Size of the memory allocated per invocation of the func Timeout | `integer` | Maximum time that the function can run before it is killed in seconds. Defaults to 3. Role | `string` | ARN of an IAM role to use as this function's execution role. If omitted, a default role is created for this function. Policies | `string` | List of `string` | [IAM policy document object](http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html) | List of [IAM policy document object](http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html) | List of [SAM Policy Templates](../docs/policy_templates.rst) | Names of AWS managed IAM policies or IAM policy documents or SAM Policy Templates that this function needs, which should be appended to the default role for this function. If the Role property is set, this property has no meaning. +PermissionsBoundary | `string` | ARN of a permissions boundary to use for this function's execution role. Environment | [Function environment object](#environment-object) | Configuration for the runtime environment. VpcConfig | [VPC config object](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) | Configuration to enable this function to access private resources within your VPC. Events | Map of `string` to [Event source object](#event-source-object) | A map (string to [Event source object](#event-source-object)) that defines the events that trigger this function. Keys are limited to alphanumeric characters.