Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to attach an AWS managed policy to a role in cloudformation and troposphere

In my troposphere code i basically want to create an sns topic and a lambda execution role to which i can attach a few managed policy from aws. But the issue is i cannot find a way to just reference the arn name of the managed policy. Below is my code but here i am copying and pasting the managed policy json document.

Is there a better way out ?

from troposphere import FindInMap, GetAtt, Join, Output, Template, Ref, ImportValue
from troposphere.sns import Topic
from troposphere.iam import Role, Policy


t = Template()

t.set_version("2010-09-09")

sns_topic = Topic(TopicName='IngestStateTopic', title='IngestStateTopic')

t.add_resource(sns_topic)

LambdaExecutionRole = t.add_resource(
    Role(
        "LambdaExecutionRole",
        Path="/",
        Policies=[
            Policy(PolicyName="CloudWatchLogsFullAccess",
                   PolicyDocument={
                       "Version":
                       "2012-10-17",
                       "Statement": [{
                           "Action": ["logs:*"],
                           "Effect": "Allow",
                           "Resource": "*"
                       }]
                   }),
            Policy(PolicyName="SnsReadOnlyAccess",
                   PolicyDocument={
                       "Version":
                       "2012-10-17",
                       "Statement": [{
                           "Effect":
                           "Allow",
                           "Action": ["sns:GetTopicAttributes", "sns:List*"],
                           "Resource":
                           "*"
                       }]
                   }),
            Policy(PolicyName="LambdaBasicExecutionRole-Test",
                   PolicyDocument={
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:eu-west-1:498129003450:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:eu-west-1:498129003450:log-group:/aws/lambda/lambda_layers_test:*"
            ]
        }
    ]
})
        ],
        AssumeRolePolicyDocument={
            "Version":
            "2012-10-17",
            "Statement": [{
                "Action": ["sts:AssumeRole"],
                "Effect": "Allow",
                "Principal": {
                    "Service": ["lambda.amazonaws.com"]
                }
            }]
        },
    ))

t.add_output(
    Output(
    "IngestServiceArn",
    Description="ARN of the sns topic",
    Value=Ref(sns_topic),
))

t.add_output(
    Output(
    "LambdaExcecutionRole",
    Description="ARN of the lambda plocy document",
    Value=GetAtt(LambdaExecutionRole, "Arn"),
))

with open('sns_lambda_role.yaml', 'w') as s:
    s.write(t.to_yaml())

And below is my cloud formation yaml file name:

AWSTemplateFormatVersion: '2010-09-09'
Outputs:
  IngestServiceArn:
    Description: ARN of the sns topic
    Value: !Ref 'IngestStateTopic'
  LambdaExcecutionRole:
    Description: ARN of the lambda plocy document
    Value: !GetAtt 'LambdaExecutionRole.Arn'
Resources:
  IngestStateTopic:
    Properties:
      TopicName: IngestStateTopic
    Type: AWS::SNS::Topic
  LambdaExecutionRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - sts:AssumeRole
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
        Version: '2012-10-17'
      Path: /
      Policies:
        - PolicyDocument:
            Statement:
              - Action:
                  - logs:*
                Effect: Allow
                Resource: '*'
            Version: '2012-10-17'
          PolicyName: CloudWatchLogsFullAccess
        - PolicyDocument:
            Statement:
              - Action:
                  - sns:GetTopicAttributes
                  - sns:List*
                Effect: Allow
                Resource: '*'
            Version: '2012-10-17'
          PolicyName: SnsReadOnlyAccess
        - PolicyDocument:
            Statement:
              - Action: logs:CreateLogGroup
                Effect: Allow
                Resource: arn:aws:logs:eu-west-1:498129003450:*
              - Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Effect: Allow
                Resource:
                  - arn:aws:logs:eu-west-1:498129003450:log-group:/aws/lambda/lambda_layers_test:*
            Version: '2012-10-17'
          PolicyName: LambdaBasicExecutionRole-Test
    Type: AWS::IAM::Role
like image 574
Subhayan Bhattacharya Avatar asked Jan 30 '26 06:01

Subhayan Bhattacharya


2 Answers

You can do this by specifying a list of ManagedPolicyArns for Role cloudformation resource, but not the Policies - Documentation:

{
  "Type" : "AWS::IAM::Role",
  "Properties" : {
      "AssumeRolePolicyDocument" : Json,
      "ManagedPolicyArns" : [ String, ... ],
      "MaxSessionDuration" : Integer,
      "Path" : String,
      "PermissionsBoundary" : String,
      "Policies" : [ Policy, ... ],
      "RoleName" : String
    }
}

For ManagedPolicy CloudFormation has separate resource type - AWS::IAM::ManagedPolicy:

SampleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Sid: AllowAllUsersToListAccounts
            Effect: Allow
            Action:
              - iam:ListAccountAliases
              - iam:ListUsers
              - iam:GetAccountSummary
            Resource: "*

Examle:

RootRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - !Ref awsExampleManagedPolicyParameterOne            
        - !Ref awsExampleManagedPolicyParameterTwo

So, if we are talking about the tropopshere - it also has separate class for ManagedPolicy:

class ManagedPolicy(AWSObject):
    resource_type = "AWS::IAM::ManagedPolicy"

    props = {
        'Description': (basestring, False),
        'Groups': ([basestring], False),
        'ManagedPolicyName': (basestring, False),
        'Path': (iam_path, False),
        'PolicyDocument': (policytypes, True),
        'Roles': ([basestring], False),
        'Users': ([basestring], False),
    }

And you refer to it using Ref function.

like image 69
Aleksey Balenko Avatar answered Feb 01 '26 19:02

Aleksey Balenko


You might want to look at the awacs project which allows for policy definition.

Also, likely you need to just Ref() your policy to get the name of it.

like image 22
mark Avatar answered Feb 01 '26 18:02

mark