Execution Role

An IAM Execution Role Scoped to BookNest's Table

The function's role, assumable only by Lambda 24 , grants exactly what the handler does: two reads on one table, writes to its log group (declared above it, 14 days' retention) and the calls that attach it to the VPC:

infra/booknest-app.yaml: a least-privilege execution roleYAML
  ApiRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: booknest-api
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal: {Service: lambda.amazonaws.com}
            Action: sts:AssumeRole
      Policies:
        - PolicyName: read-catalog-and-log
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: [dynamodb:GetItem, dynamodb:Scan]
                Resource: !GetAtt BooksTable.Arn
              - Effect: Allow
                Action: [logs:CreateLogStream, logs:PutLogEvents]
                Resource: !GetAtt ApiLogGroup.Arn
              - Effect: Allow
                Action: [ec2:CreateNetworkInterface, ec2:DescribeNetworkInterfaces,
                  ec2:DescribeSubnets, ec2:DeleteNetworkInterface,
                  ec2:AssignPrivateIpAddresses, ec2:UnassignPrivateIpAddresses]
                Resource: "*"

Shortcuts such as AmazonDynamoDBReadOnlyAccess read every table in the account; this role has no write, no other table and no logs:CreateLogGroup. AWS 24 documents the EC2 24 list for VPC-attached functions and requires it on "*"; a deny keyed on lambda:SourceFunctionArn stops the function's own code from using it. The named role needs CAPABILITY_NAMED_IAM (IAM for CloudFormation).