cloudformation script fails when invoked via lambda

0

i have a cloudformation stack file on s3 which works just fine when I launch it from console. but when I trigger the same script using boto3 from AWS lambda, i get an encoded error message. Decoding it then gives me the following json output. (converted to yaml for readability)

---
allowed: false
explicitDeny: false
matchedStatements:
  items: []
failures:
  items: []
context:
  principal:
    id: AROA3H7OMTCQKOORZGNNY:Spawn-reward-service
    arn: arn:aws:sts::773057xxxxxx:assumed-role/Spawn-reward-service-role-g0vgzj5h/Spawn-reward-service
  action: ec2:RequestSpotFleet
  resource: arn:aws:ec2:us-east-1:773057xxxxxx:subnet/subnet-e18921ca
  conditions:
    items:
    - key: ec2:Vpc
      values:
        items:
        - value: arn:aws:ec2:us-east-1:773057xxxxxx:vpc/vpc-aa2884c1
    - key: aws:Resource
      values:
        items:
        - value: subnet/subnet-e18921ca
    - key: aws:Account
      values:
        items:
        - value: '773057xxxxxx'
    - key: ec2:AvailabilityZone
      values:
        items:
        - value: us-east-1e
    - key: ec2:ResourceTag/Name
      values:
        items:
        - value: 1e subnet
    - key: ec2:SubnetID
      values:
        items:
        - value: subnet-e18921ca
    - key: aws:Region
      values:
        items:
        - value: us-east-1
    - key: aws:Service
      values:
        items:
        - value: ec2
    - key: aws:Type
      values:
        items:
        - value: subnet
    - key: 773057xxxxxx:Name
      values:
        items:
        - value: 1e subnet
    - key: ec2:Region
      values:
        items:
        - value: us-east-1
    - key: aws:ARN
      values:
        items:
        - value: arn:aws:ec2:us-east-1:773057xxxxxx:subnet/subnet-e18921ca

The Lambda role has AmazonEC2SpotFleetTaggingRole, NetworkAdministrator and AWSCloudFormationFullAccess policies attached. So not sure where the hangup is. Any help appreciated.

Here is the lambda function in full for reference.

import json, boto3

def lambda_handler(event, context):
    cloudformation = boto3.client('cloudformation')
    response = cloudformation.create_stack(
        StackName='yj',
        TemplateURL='https://s3.amazonaws.com/cf-templates-xxxxxxxxxxxx-us-east-1/reward-service-01-spot.yaml',
        Parameters=[
            {
                'ParameterKey': 'InstanceType',
                'ParameterValue': 't2.large'
            }
        ]
    )
    return response
2 Answers
1

Are you providing CloudFormation with a different role to use for execution of the Stack? If not it will use the credentials you've used to invoke CloudFormation. In this case that's the role with NetworkAdministrator and AWSCloudFormationFullAccess policies which wouldn't contain anything to allow ec2:RequestSpotFleet.

EXPERT
answered a year ago
  • I am specifying the role in my template - Do you mean to say, it inherits the lambda role and overrides the role in my script? In any case, i added the AmazonEC2SpotFleetTaggingRole which allows request spot instances, but with no luck. I realized my json was truncated. updating my question and posting it as yaml in case it is hiding any clues.

  • I am not sure it has anything to do with VPCs though. I did try to move the lambda into a VPC, but that just causes the lambda to timeout and never trigger the stack even after a minute.

  • The "different role" I was talking about is passing the following to create_stack():

    RoleARN (string) -- The Amazon Resource Name (ARN) of an Identity and Access Management (IAM) role that CloudFormation assumes to create the stack. CloudFormation uses the role's credentials to make calls on your behalf. CloudFormation always uses this role for all future operations on the stack. Provided that users have permission to operate on the stack, CloudFormation uses this role even if the users don't have permission to pass it. Ensure that the role grants least privilege. If you don't specify a value, CloudFormation uses the role that was previously associated with the stack. If no role is available, CloudFormation uses a temporary session that's generated from your user credentials.

    As it looks like you're not providing a RoleARN, your Lambda's role will be used to execute all of CloudFormation's AWS API calls while creating the Stack.

  • i did try passing the role ARN using

            RoleARN='arn:aws:iam::773057xxxxxx:role/aws-ec2-spot-fleet-tagging-role', 
    

    unfortunately I get Role arn:aws:iam::773057xxxxxx:role/aws-ec2-spot-fleet-tagging-role is invalid or cannot be assumed". Since this is an AWS managed role, i cannot edit it, but it is setup to be assumed based on my reading of the policy.

0
Accepted Answer

The whole request spotfleet approach seems to be deprecated. The recommended approach after further research seems to be to use the create_fleet api which moves a bunch of config to launch templates from the cloudformation scripts to launch templates.

I got onboard this train and have just a lambda function with launch template and no cloudformation stuff.

answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions