Search code examples
pythonamazon-web-servicesamazon-ec2boto3

Not Authorised Error: AWS lambda ec2.run_instances from launch template with boto3


I am trying to run aws ec2 instances from my lambda. Creating instance from local machine works when I tried this -

import boto3

launchTemplateId = 'lt-000'

ec2 = boto3.client('ec2', region_name='ap-xx-1')

template_specifics = {
    'LaunchTemplateId': launchTemplateId
}

resp = ec2.run_instances(
    MaxCount=1, 
    MinCount=1,
    LaunchTemplate=template_specifics,
    ImageId='ami-00000'
    )

print(resp['ResponseMetadata']['HTTPStatusCode'])

And I am trying this on lambda -

def create_instance(lt_id, img_id, region):
    """ creates instance from launch template. """
    ec2 = boto3.client('ec2', region_name=region)
    resp = ec2.run_instances(
        MaxCount=1, 
        MinCount=1,
        LaunchTemplate={
            'LaunchTemplateId':lt_id
          },
        ImageId=img_id
      )

    return(resp['ResponseMetadata']['HTTPStatusCode'])

with IAM policy -

....
    {
        # "Sid": "PassExecutionRole",
        "Effect": "Allow", 
        "Action": [
            "iam:PassRole",
        ],
        "Resource": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${aws_iam_role.xx_role.name}"
    },
    {
        "Effect": "Allow",
        "Action": [
            "ec2:*"
            # "ec2:StartInstances",
            # "ec2:RunInstances"
        ],
        # "resource": "*"
        "Resource": "arn:aws:ec2:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"
    }
......

Notice I even tried with wildcard * too, even added passRole as a comment suggested but every time it just shows this error -

ClientError: An error occurred (UnauthorizedOperation) when calling the RunInstances operation: You are not authorized to perform this operation. ......

Traceback (most recent call last):
  File "/var/task/xxxx.py", line 153, in xxxx_handler
    instance_create_resp = create_instance(lt_id, img_id, region)
  File "/var/task/xxxx.py", line 79, in create_instance
    resp = ec2.run_instances(
  File "/var/runtime/botocore/client.py", line 391, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 719, in _make_api_call
    raise error_class(parsed_response, operation_name)

What am I doing wrong? Any ideas will be much helpful.

UPDATE I was able to track down the problem and it's 'tags' and 'InstanceProfile' which are causing this error.

TagSpecifications=[{
              'ResourceType': 'instance',
              'Tags': [
                  { 'Key': 'Name',
                    'Value': 'name'
                  }]
}],
IamInstanceProfile={
          'Name': PROFILE
          },

This causes the same error, else it works.


Solution

  • Solution: The lambda did not have permission to Tag resource ec2 while creating. I had to add "ec2:CreateTags" to the policy as the doc suggested, and this solved the issue.

    {
          "Action": [
            "ec2:RunInstances"
          ],
          "Effect": "Allow",
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
             "ec2:CreateTags"
          ],
          "Resource": "arn:aws:ec2:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*/*",
          "Condition": {
             "StringEquals": {
                 "ec2:CreateAction" : "RunInstances"
              }
           }
        }
    

    Note: You will also need to add sts permission for passing role.

    Best wishes.