Using Existing Role in CloudFormation Template - amazon-web-services

I'm trying to use an existing IAM role in a CFN template that is already being used by other services.
The Resource definition looks like this:
MyInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles: ["Capras999"]
And I'm referencing it like this:
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Role: !Ref MyInstanceProfile
However I get this error:
1 validation error detected: Value 'capras-cluster-Prsr-DL-with-params-MyInstanceProfile-1R68JNUXU0SAA' at 'role' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role/?[a-zA-Z_0-9+=,.#\-_/]+ (Service: AWSLambdaInternal; Status Code: 400; Error Code: ValidationException; Request ID: 5f75a56d-8ce4-473e-924e-626a5d3aab0a)
What am I doing wrong? Please help me.

For lambda function you need role not instance-profile.
The solution was to copy and paste an existing role's ARN into the template. Other possibility is to pass it in using a parameter.
p.s.
Generally, you need to define AWS::IAM::Role with a thrust policy for lambda. For example:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: my-lambda-execution-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: {'Service': ['lambda.amazonaws.com']}
Action: ['sts:AssumeRole']
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSLambdaExecute
Then for your function you would do:
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Role: !GetAtt LambdaExecutionRole.Arn

You are specifying the instance name as the value, this parameter should instead be the Arn of the IAM role in question.
From your question you're trying to attach an instance profile to your Lambda, these are for EC2 instances only. Instead you want the Arn of the role itself.
From the console you can get the Arn for IAM role Capras999.
If you're using an existing role make sure to update your AssumeRolePolicy to also include lambda.amazonaws.com (and lambdaedge.amazonaws.com if using it for Lambda#Edge).

Related

AWS Cloudformation:Template validation error Role and policy

I am new to cloudformation and trying to create a template that can create a execution role and associated policies for my lambda function.
AWSTemplateFormatVersion: 2010-09-09
Description: AWS CloudFormation Template for creating iam role for SSM lambda
Parameters:
rolename:
Type: String
Description: The name of the iam role for SSM Lambda
Default: SSM_lambda_role
policyname:
Type: String
Description: pcluster lambda iam policy for SSM Lambda
Default: SSM_lambda_policy
Resources:
ssmlambdarole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub '${rolename}'
Description: iam role for ssm lambda role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- !Sub 'arn:aws:iam::${AWS::AccountId}:policy/${policyname}'
ssmlambdapolicy:
Type: 'AWS::IAM::ManagedPolicy'
Properties:
ManagedPolicyName: !Sub '${policyname}'
Description: The name of the iam role for SSM Lambda
Path: '/'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- logs:CreateLogGroup
Resource: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*
Effect: Allow
Sid: CloudWatchLogsPolicy
- Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${policyname}:*
Effect: Allow
Sid: CloudWatchLogsPolicy
- Action:
- ssm:Describe*
- ssm:Get*
- ssm:List*
Resource: "*"
Effect: Allow
If I define a role first in the above template, I get an error during stack creation mentioning that the policy is not found and if I create policy first in the above order, I keep getting a validation error. can someone tell me where am I getting wrong.
There is an attribute that can help to achieve that: DependsOn,
but the better way is to use - !Ref ssmlambdapolicy instead of - !Sub 'arn:aws:iam::${AWS::AccountId}:policy/${policyname}'.
In each case, it will establish a dependency between resources. Thanks to that AWS will be able to recognize resource creation orders - you didn't use any of them, so AWS 1stly tries to create a role (or policy, depending on the order in the template), and attach a policy that doesn't exist yet.
The validation error is due to that you missed !sub in the policy statements.
Btw, I strongly recommend looking for help in CFN documentation - sometimes there is a section with use-case examples.

how to get Rolename from existing Lambda function on cloud via its friendly name or arn using cloudformation?

I have created a CFN template for rotating secret of RDS. It consist of a AWS HostedLambda which calls for an autogenerated Role. I want to attach another policy to that role.
rRotationLambdaDecryptPolicy:
Type: AWS::IAM::ManagedPolicy
DependsOn: rSecretRotationScheduleHostedRotationLambda
Properties:
Description: "Providing access to HostedLambda for decrypting KMS"
ManagedPolicyName: CustomedHostedLambdaKmsUserRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowLambdaDecryptKMS
Effect: Allow
Action:
- kms:Decrypt
- kms:CreateGrant
Resource:
- !Sub arn:aws:kms:*:${AWS::AccountId}:key/*
Condition:
ForAnyValue:StringLike:
kms:ResourceAliases: alias/SecretsManager_KMSKey
Roles: <friendly rolename>
Problem is i know the Lambda friendly name and its Arn. Need to find the rolename linked to this lambda so that i can attach the above policy to it(Add its friendly name to Roles).
tried attaching this below
Roles:
Fn::Join:
- ""
- - '"'
- Fn::GetAtt:
- !Sub 'arn:aws:lambda::${AWS::AccountId}:function:SecretsManager-research-creds-rotation-lambda'
- Role
- '"'
P.S.- cant use importvalue here, because the nested stack has been created by AWS and its output doesn't consist of export.
Lambda used:-
rSecretRotationSchedule:
Type: AWS::SecretsManager::RotationSchedule
Properties:
SecretId:<SecretId>
HostedRotationLambda:
KmsKeyArn: <KmsKeyArn>
MasterSecretArn: <MasterSecretArn>
MasterSecretKmsKeyArn: <MasterSecretKmsKeyArn>
RotationType: PostgreSQLMultiUser
RotationLambdaName: SecretsManager-research-creds-rotation-lambda
VpcSecurityGroupIds: <VpcSecurityGroupIds>
VpcSubnetIds: <VpcSubnetIds>
RotationRules:
AutomaticallyAfterDays: 60
Below is the link from which i took reference for template:-
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-rotationschedule.html
Most likely you can't do this with plain CFN. You would have to develop a custom resource. This would be in the form of a new lambda function which would use AWS SDK to query attributes of your primary lambda function. Once the custom resource finds the role name it would return it to your stack for further use.

How to create a condition which allows only resources created in the same CloudFormation stack to assume IAM role?

I'm creating a CloudFormation stack that has a CodeBuild and an IAM role as a resource. I'd like to know if is there a condition that allows only resources created in the same stack to assume the role.
Currently, my stack is defined this way:
CodeBuildProjectIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
CodeBuildProject:
Type: AWS::CodeBuild::Project
The problem is that any CodeBuild project can assume the role above.
When I try to add a condition specifying that only principals with aws:cloudformation:stack-name equal stack name can assume the role:
CodeBuildProjectIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:PrincipalTag/aws:cloudformation:stack-name: !Ref 'AWS::StackName'
, I get this error:
Condition can contain only one colon. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument)
Based on these docs I don't believe what you're trying to do is possible a this time.
Specifically:
You cannot limit permissions to pass a role based on tags attached to that role using the ResourceTag/key-name condition key

AWS Lambda and IAM error on deploy: The role defined for the function cannot be assumed by Lambda

In my AWS project, I use the serverless framework to deploy lambda function and IAM roles.
So I created 6 lambda functions, all using the same IAM Role below:
functions:
auto-delete-identity:
handler: src/auto-delete-identity.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: auto-delete-identity
auto-move-to-user-group:
handler: src/auto-move-to-user-group.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: auto-move-to-user-group
auto-validate-user-creation:
handler: src/auto-validate-user-creation.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: auto-validate-user-creation
auto-validation-user-email-modification:
handler: src/auto-validation-user-email-modification.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: auto-validation-user-email-modification
hello-demo:
handler: src/hello-demo.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: hello-demo
reset-user-password:
handler: src/reset-user-password.handler
role: arn:aws:iam::123456789012:role/lambdaIAMRole
name: reset-user-password
resources:
Resources:
lambdaIAMRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: lambdaIAMRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "sts:AssumeRole"
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Policies:
- PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Effect: "Allow"
Resource:
- !Sub "arn:aws:logs:eu-central-1:123456789012:log-group:/aws/lambda/*:*"
PolicyName: "myLambdaPolicy"
When I deploy using the serverless deploy command, I sometimes got the following error:
An error occurred: HelloDashdemoLambdaFunction - The role defined for the function cannot be assumed by Lambda. (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException; Request ID: 4099072a-809d-4f1c-b83e-7f4f5dd5170b).
It looks like a random bug, since it doesn’t occurs everytime. Also, when it occurs, it doesn’t always occurs on the same function.
Did I do something wrong? How can I fix that?
Thanks for your help.
I think that the problem is that in your Lambda function declarations, you're referring to the IAM role as role: arn:aws:iam::123456789012:role/lambdaIAMRole. This is an absolute ARN and is how you would indicate an IAM role (or other resource) that was created and managed outside of your serverless.yml template.
In your case, the quickest fix is to simply replace role: arn:aws:iam::123456789012:role/lambdaIAMRole with role: lambdaIAMRole. The latter refers to an AWS resource declared inside the template.
An even better fix, assuming that all of your Lambda functions will have the same role, is to remove your lambdaIAMRole declaration entirely and then remove all role: arn:aws:iam::123456789012:role/lambdaIAMRole properties from the Lambda functions. The role declaration adds nothing over the default IAM role that the Serverless Framework will implicitly generate for you and assign to the Lambda functions. This is one of the things that makes the framework valuable - it provides good defaults to save you the time and effort. Examples here.

How do I get the name of a dynamically created lambda role?

I like how a role + inline policy is created when I deploy my template:
Resources:
MyFUnction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
Description: Enter description of what this specific Lambda does
CodeUri: hello_world/build/
Handler: app.lambda_handler
Runtime: python2.7
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
Variables:
PARAM1: VALUE
Policies:
# Using AWSLambdaExecute automatically creates a role named: <StackName>Role-<UUID>
- AWSLambdaExecute
# This policy is assigned as an Inline policy to the role
- Version: '2012-10-17' # Policy Document
Statement:
Effect: Allow
Action: ......
Now can I ref the role that is dynamically created and add an Output: for it in the SAM template?
The resulting role that SAM creates for you is just the name of your function with "Role" added to the end. You can use this information to get the Role or properties of it using normal CloudFormation functions.
For example, if you wanted to access the role ARN of MyFunction, you would use !GetAtt MyFunctionRole.Arn in your SAM YAML template. The same principle should apply for !Ref and other functions.
I was able to test a solution to this, in the SAM template.yaml you can add an Output as you would in CloudFormation for the Logical ID that is created automatically for you as part of the Transform when using Properties such as Policies for AWS::Serverless::Function
The Logical ID of the resulting IAM Role is <Function Logical ID>Role, I used the below:
Outputs:
LambdaRole:
Value:
Fn::GetAtt:
- "LambdaFunctionRole"
- "Arn"
Description: "Lambda IAM Role"