Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix references to AWS managed policies in SAM templates #6148

Merged
merged 1 commit into from May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 1 addition & 21 deletions localstack/services/iam/provider.py
Expand Up @@ -5,11 +5,7 @@

from moto.iam.models import AWSManagedPolicy, IAMNotFoundException, InlinePolicy, Policy
from moto.iam.models import Role as MotoRole
from moto.iam.models import (
aws_managed_policies,
aws_managed_policies_data_parsed,
filter_items_with_path_prefix,
)
from moto.iam.models import aws_managed_policies, filter_items_with_path_prefix
from moto.iam.models import iam_backend as moto_iam_backend
from moto.iam.policy_validation import VALID_STATEMENT_ELEMENTS, IAMPolicyDocumentValidator
from moto.iam.responses import IamResponse
Expand Down Expand Up @@ -336,15 +332,6 @@ def get_service_linked_role_deletion_status(
# return GetUserResponse(User=response_user)


class AWSManagedPolicyUSGov(AWSManagedPolicy):
# Fix missing regions in managed policies (e.g., aws-us-gov). Note: make sure to keep at global scope here
# TODO: possibly find a more efficient way for this - e.g., lazy loading of policies in special regions

@property
def arn(self):
return "arn:aws-us-gov:iam::aws:policy{0}{1}".format(self.path, self.name)


def apply_patches():
# support service linked roles

Expand Down Expand Up @@ -421,10 +408,3 @@ def inline_policy_unapply_policy(fn, self, backend):
except Exception:
# Actually role can be deleted before policy being deleted in cloudformation
pass

managed_policies = moto_iam_backend.managed_policies
if "arn:aws-us-gov:iam::aws:policy/AmazonRDSFullAccess" not in managed_policies:
for name, data in aws_managed_policies_data_parsed.items():
policy = AWSManagedPolicyUSGov.from_data(name, data)
if policy.arn not in moto_iam_backend.managed_policies:
moto_iam_backend.managed_policies[policy.arn] = policy
23 changes: 13 additions & 10 deletions localstack/utils/cloudformation/template_preparer.py
Expand Up @@ -9,6 +9,7 @@
import moto.cloudformation.utils
import yaml
from requests.structures import CaseInsensitiveDict
from samtranslator.translator.managed_policy_translator import ManagedPolicyLoader
from samtranslator.translator.transform import transform as transform_sam

from localstack import config, constants
Expand All @@ -28,28 +29,30 @@
for k, v in NoDatesSafeLoader.yaml_implicit_resolvers.items()
}

policy_loader = None


def _create_loader():
global policy_loader
if not policy_loader:
iam_client = aws_stack.connect_to_service("iam")
policy_loader = ManagedPolicyLoader(iam_client=iam_client)
return policy_loader


def transform_template(req_data) -> Optional[str]:
"""only returns string when parsing SAM template, otherwise None"""
template_body = get_template_body(req_data)
parsed = parse_template(template_body)
if parsed.get("Transform") == "AWS::Serverless-2016-10-31":
policy_map = {
# SAM Transformer expects this map to be non-empty, but apparently the content doesn't matter (?)
"dummy": "entry"
# 'AWSLambdaBasicExecutionRole': 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole',
}

class MockPolicyLoader:
def load(self):
return policy_map

# Note: we need to fix boto3 region, otherwise AWS SAM transformer fails
region_before = os.environ.get("AWS_DEFAULT_REGION")
if boto3.session.Session().region_name is None:
os.environ["AWS_DEFAULT_REGION"] = aws_stack.get_region()
loader = _create_loader()
try:
transformed = transform_sam(parsed, {}, MockPolicyLoader())
transformed = transform_sam(parsed, {}, loader)
return json.dumps(transformed)
finally:
os.environ.pop("AWS_DEFAULT_REGION", None)
Expand Down
16 changes: 16 additions & 0 deletions tests/integration/cloudformation/test_cloudformation_sam.py
@@ -0,0 +1,16 @@
import os.path

import pytest


@pytest.mark.aws_validated
def test_sam_policies(deploy_cfn_template, cfn_client, iam_client):
stack = deploy_cfn_template(
template_path=os.path.join(
os.path.dirname(__file__), "../templates/sam_function-policies.yaml"
)
)
role_name = stack.outputs["HelloWorldFunctionIamRoleName"]

roles = iam_client.list_attached_role_policies(RoleName=role_name)
assert "AmazonSNSFullAccess" in [p["PolicyName"] for p in roles["AttachedPolicies"]]
35 changes: 35 additions & 0 deletions tests/integration/templates/sam_function-policies.yaml
@@ -0,0 +1,35 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
InlineCode: |+
import json

def handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world",
}),
}

Runtime: python3.9
Handler: index.handler
Architectures:
- x86_64
Policies:
- AmazonSNSFullAccess
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
Outputs:
HelloWorldFunctionIamRoleArn:
Value: !GetAtt HelloWorldFunctionRole.Arn
HelloWorldFunctionIamRoleName:
Value: !Ref HelloWorldFunctionRole