Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy lambda to VPC. #32

Open
jarrettj opened this issue Aug 27, 2018 · 33 comments
Open

Deploy lambda to VPC. #32

jarrettj opened this issue Aug 27, 2018 · 33 comments
Labels
feature-request Request a new feature functions Issues tied to the functions category p4

Comments

@jarrettj
Copy link

Do you want to request a feature or report a bug?
Feature

What is the current behavior?
There's no option to deploy a lambda into a VPC.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
When using the current function add functionality you are not promoted to place the function into a VPC.

What is the expected behavior?
Would be helpful to deploy to a VPC.

Which versions of Amplify CLI, and which OS are affected by this issue? Did this work in previous versions?
0.1.14

@kaustavghosh06 kaustavghosh06 added the feature-request Request a new feature label Aug 27, 2018
@kaustavghosh06 kaustavghosh06 added the functions Issues tied to the functions category label Jan 7, 2019
@abualsamid
Copy link

abualsamid commented May 31, 2019

any update/timeline on this? and/or is there a workaround, manual or otherwise, to let us deploy our lambda's to a vpc.

@paultipper
Copy link

Any progress on this issue? I've found that if I manually reconfigure the lambda to deploy to my default VPC in the AWS Console, the next time I run the amplify publish command, the VPC setting is reset back to "No VPC". This is a deal killer for me as far as being able to use amplify to build full-stack apps, which is heart-breaking, because otherwise it's awesome.

@BabyDino
Copy link

I was also looking into this. I found a (temp?) solution:

Change your <functionname>-cloudformation-template.json:

Under Resources add:

"VpcConfig": {
   "SecurityGroupIds": [
       "sg-xxx"
   ],
   "SubnetIds": [
       "subnet-xxx",
       "subnet-xxx",
       "subnet-xxx"
   ]
}

and add a statement to your execution role:

{
   "Effect": "Allow",
   "Action": [
       "ec2:CreateNetworkInterface",
       "ec2:DescribeNetworkInterfaces",
       "ec2:DeleteNetworkInterface"
   ],
   "Resource": "*"
}

Refer to: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html

@paultipper
Copy link

@BabyDino Hi Stefan, thanks for the tip. Whereabouts exactly did you add the execution role statement in your -cloudformation-template.json document? I tried adding it to Resources/lambaexecutionpolicy/Properties/PolicyDocument/Statement, but when I tried to deploy using the amplify publish command, I got the following error:

`Following resources failed

Resource Name: cdkamplifyappfe31e78f (AWS::Lambda::Function)
Event Type: update
Reason: The provided execution role does not have permissions to call CreateNetworkInterface on EC2 (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException; Request ID: 0db4f5a3-1fc7-428f-96fd-3d89f464ffa3)
`

I'm guessing I added the execution role statement in the wrong position in the -cloudformation-template.json file.

@BabyDino
Copy link

@paultipper this works for us:

"lambdaexecutionpolicy": {
	"DependsOn": [
		"LambdaExecutionRole"
	],
	"Type": "AWS::IAM::Policy",
	"Properties": {
		"PolicyName": "lambda-execution-policy",
		"Roles": [
			{
				"Ref": "LambdaExecutionRole"
			}
		],
		"PolicyDocument": {
			"Version": "2012-10-17",
			"Statement": [
				{
					"Effect": "Allow",
					"Action": [
						"logs:CreateLogGroup",
						"logs:CreateLogStream",
						"logs:PutLogEvents"
					],
					"Resource": {
						"Fn::Sub": [
							"arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*",
							{
								"region": {
									"Ref": "AWS::Region"
								},
								"account": {
									"Ref": "AWS::AccountId"
								},
								"lambda": {
									"Ref": "LambdaFunction"
								}
							}
						]
					}
				},
				{
					"Effect": "Allow",
					"Action": [
						"ec2:CreateNetworkInterface",
						"ec2:DescribeNetworkInterfaces",
						"ec2:DetachNetworkInterface",
						"ec2:DeleteNetworkInterface"
					],
					"Resource": "*"
				}
			]
		}
	}
}

@paultipper
Copy link

@BabyDino Yeah, that's exactly where I put the new statement, but I'm still getting the error. Stumped. :(

@BabyDino
Copy link

@paultipper I do not have an answer sorry, just figured this out myself. There are some articles about your error though: https://medium.com/@onclouds/aws-codestar-lambda-vpc-706fcf1252d4.

Hope this helps.

@paultipper
Copy link

paultipper commented Jun 28, 2019

@BabyDino Finally cracked it! You have to add and deploy the network interface permissions statement first before you'll be allowed to add the VPC configuration statement. Once the network interface permissions are in place, then you'll be able to add the VPC config, but you can't add the VPC and network interface permissions statements at the same time.

Kudos to gozup for pointing this out - see this thread.

And many thanks, Stefan, for all your help - you got me most of the way there!

@BabyDino
Copy link

BabyDino commented Jun 28, 2019

@paultipper You're welcome, glad it works!

Thank you for the link, I was not aware of that. I'll might consider creating a role in IAM and just use that role instead of creating a role with every function. Most of our functions require the same permissions anyway.

Or something with DependsOn. I'm fairly new to CF.

@regischow
Copy link

@BabyDino another way to do it would be to add arn:aws:iam::aws:policy/service- role/AWSLambdaVPCAccessExecutionRole as ManagedPolicyArns to the LambdaExecutionRole.

@anaji
Copy link

anaji commented Apr 3, 2020

it works after adding the vpc config inside resources properties in -cloudformation-template.jsonc file . i.e:

`"Resources": {
    "LambdaFunction": {
        "Type": "AWS::Lambda::Function",
        "Metadata": {
            "aws:asset:path": "./src",
            "aws:asset:property": "Code"
        },
        "Properties": {
            "Handler": "index.handler",
              ....
            "VpcConfig": {
                "SecurityGroupIds": [
                    "sg-xxx"
                ],
                "SubnetIds": [
                    "subnet-xxx",
                    "subnet-xxx",
                    "subnet-xxx"
                ]
            }
        },
        "LambdaExecutionRole": {
              ....
        `

@batical
Copy link

batical commented Apr 10, 2020

and how to deal with multi env and lambda vpc except doing some manual script to update template json

@alexkates
Copy link

and how to deal with multi env and lambda vpc except doing some manual script to update template json

This is something I'm wrapping my head around also. My current thought is to add a network category via https://aws-amplify.github.io/docs/cli-toolchain/quickstart#custom-cloudformation-stacks, and provision a VPC, Subnets, Security Groups, Route Tables, IGWs, etc. This will give me those resources for each environment, and allow me to link my functions to that VPC via Refs.

I was hoping that someone from the amplify-cli team could offer their thoughts about this as a viable workaround?

@lorengordon
Copy link

Just had to do this ourselves... To deal with the dependency on the IAM role needing the EC2 Network Interface permissions before the role is attached to the lambda, we used a separate inline policy and a DependsOn block... This allowed us to keep the restrictive policy that amplify creates for CloudWatch Logs, rather than use AWSLambdaVPCAccessExecutionRole (which has no resource restriction on which log groups/streams the lambda can write to). Here's a diff:

@@ -23,6 +23,9 @@
        },
        "Resources": {
                "LambdaFunction": {
+                       "DependsOn": [
+                               "LambdaExecutionPolicyCustom"
+                       ],
                        "Type": "AWS::Lambda::Function",
                        "Metadata": {
                                "aws:asset:path": "./src",
@@ -48,6 +51,19 @@
                                                }
                                        ]
                                },
+                               "VpcConfig": {
+                                       "SecurityGroupIds": [
+                                               "sg-xxxxxx"
+                                       ],
+                                       "SubnetIds": [
+                                               "subnet-xxxxxx",
+                                               "subnet-xxxxxx",
+                                               "subnet-xxxxxx",
+                                               "subnet-xxxxxx",
+                                               "subnet-xxxxxx",
+                                               "subnet-xxxxxx"
+                                       ]
+                               },
                                "Environment": {
                                        "Variables": {
                                                "ENV": {
@@ -154,6 +170,104 @@
                                        ]
                                }
                        }
+               },
+               "LambdaExecutionPolicyCustom": {
+                       "Type": "AWS::IAM::Policy",
+                       "Properties": {
+                               "PolicyName": "lambda-execution-policy-custom",
+                               "Roles": [
+                                       {
+                                               "Ref": "LambdaExecutionRole"
+                                       }
+                               ],
+                               "PolicyDocument": {
+                                       "Version": "2012-10-17",
+                                       "Statement": [
+                                               {
+                                                       "Effect": "Allow",
+                                                       "Action": [
+                                                               "ec2:CreateNetworkInterface",
+                                                               "ec2:DescribeNetworkInterfaces",
+                                                               "ec2:DeleteNetworkInterface"
+                                                       ],
+                                                       "Resource": "*"
+                                               }
+                                       ]
+                               }
+                       }

@semirenko
Copy link

here is the way how I did env specific configuration:

  "Conditions": {
.........
    "CurrentEnvIsLive": {
      "Fn::Equals": [
        {
          "Ref": "env"
        },
        "live"
      ]
    }
  },
.......
        "VpcConfig": {
          "Fn::If": [
            "CurrentEnvIsLive",
            {
              "SecurityGroupIds": [
                "sg-xxxxx"
              ],
              "SubnetIds": [
                "subnet-xxxx"
              ]
            },
            {
              "SecurityGroupIds": [
                "sg-yyyyyy"
              ],
              "SubnetIds": [
                "subnet-yyyy"
              ]
            }
          ]
        },

@corydorning53
Copy link

corydorning53 commented Nov 30, 2020

here is the way how I did env specific configuration:

  "Conditions": {
.........
    "CurrentEnvIsLive": {
      "Fn::Equals": [
        {
          "Ref": "env"
        },
        "live"
      ]
    }
  },
.......
        "VpcConfig": {
          "Fn::If": [
            "CurrentEnvIsLive",
            {
              "SecurityGroupIds": [
                "sg-xxxxx"
              ],
              "SubnetIds": [
                "subnet-xxxx"
              ]
            },
            {
              "SecurityGroupIds": [
                "sg-yyyyyy"
              ],
              "SubnetIds": [
                "subnet-yyyy"
              ]
            }
          ]
        },

@semirenko do you mind posting the files your changed and where the changes were made to handle multi-environment? also, where you define the environment...

@semirenko
Copy link

@corydorning53 , env comes as Lambda function parameter in XXXX-cloudformation-template.json file.

  "Parameters": {
    "CHALLENGEANSWER": {
      "Type": "String",
      "Default": ""
    },
    "modules": {
      "Type": "String",
      "Default": "",
      "Description": "Comma-delimmited list of modules to be executed by a lambda trigger. Sent to resource as an env variable."
    },
    "resourceName": {
      "Type": "String",
      "Default": ""
    },
    "trigger": {
      "Type": "String",
      "Default": "true"
    },
    "functionName": {
      "Type": "String",
      "Default": ""
    },
    "roleName": {
      "Type": "String",
      "Default": ""
    },
    "parentResource": {
      "Type": "String",
      "Default": ""
    },
    "parentStack": {
      "Type": "String",
      "Default": ""
    },
    "env": {
      "Type": "String"
    }
  },

It was added by amplify CLI, as part of lambda files generation result.
In my case this is a cognito trigger, part of Auth category. Not sure, if Amplify adds it also in case of regular Lambda function.

I just added CurrentEnvIsLive section into Conditions block of the same file, which is a standard part of any CloudFormation file. Same for VpcConfig. It is also a part of CF file specs, Resources -> LambdaFunction -> Properties -> VpcConfig
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html

@ps2goat
Copy link

ps2goat commented Mar 13, 2021

I was stepping through each of the ec2 permissions to try and limit what the lambda can do, but got stuck on the DeleteNetworkInterfaces permission-- Apparently you can't limit it to a region, it requires *. And if I can't limit that permission, I gave up on the rest. (Permission checks start with CreateNetworkInterfaces -> DescribeNetworkInterfaces -> DeleteNetworkInterface, and I stopped there because of this.)

I'm more concerned with exactly which interfaces it can access and delete more than the logs it can generate. I'm sure Amazon limits this, but it'd be nice to say "create interfaces under some identifier, and you can only attach, detach, create, or delete with those identifers/buckets"

@lorengordon
Copy link

@ps2goat ec2:DeleteNetworkInterface does support tag conditions with ec2:ResourceTag/${TagKey}. So presumably you could tag the network interfaces, and use a condition in the policy to allow deleting network interfaces only if they have a matching tag.

@caiodiletta
Copy link

This works, but how would I do that if I have different vpc for different envs?

@vishalrajole
Copy link

Any update when this will be supported? Thanks

@bothra90
Copy link

@caiodiletta: You can add the env-specific VPC configuration to the team-provider-info.json file as:

{
  "<envName>": {
    ...
    "categories": {
      ...
      "function": {
        "<functionName>": {
          "subnetIds": [
            "subnet-xxxxxxxxxxxxx"
          ],
          "securityGroupIds": [
            "sg-xxxxxxxxxxxxxxxxxxx",
            "sg-xxxxxxxxxxxxxxxxxxx"
          ],
          ...
        }
      }
    }
  }
}

This can then be taken as parameters by the cloud formation template and referred in the function config:

{
  ...
  "Parameters": {
    ...
    "subnetIds": {
      "Type": "CommaDelimitedList"
    },
    "securityGroupIds": {
      "Type": "CommaDelimitedList"
    }
  },
  "Resources": {
    "LambdaFunction": {
      "Properties": {
        "VpcConfig": {
          "SecuritGroupIds": {
            "Ref": "securityGroupIds"
          },
          "SubnetIds": {
            "Ref": "subnetIds"
          }
        }
      }
    },
    ...
  }
}

@koren-tako-storrsoft
Copy link

koren-tako-storrsoft commented Feb 17, 2022

You could perform the VpcConfig configuration by using CloudFormation external values and then:
"VpcConfig": { "SecurityGroupIds": [ { "Fn::ImportValue": { "Fn::Sub": [ "${ENV}-VPCSecurityGroup", { "ENV": { "Ref": "env" } } ] } } ], "SubnetIds": { "Fn::Split": [ ",", { "Fn::ImportValue": { "Fn::Sub": [ "${ENV}-VPCPrivateSubnets", { "ENV": { "Ref": "env" } } ] } } ] } }

@undefobj undefobj added the p4 label Feb 28, 2022
@eettaa
Copy link

eettaa commented May 13, 2022

+1 for official guidance here. In particular, it's my understanding that this is needed in order to have a static outbound IP address for a lambda function (required if your 3p services have ip allowlist ranges). This issue, specifically "I've found that if I manually reconfigure the lambda to deploy to my default VPC in the AWS Console, the next time I run the amplify publish command, the VPC setting is reset back to "No VPC".", seems to directly contradict the official AWS docs on static outbound IP's for lambdas

@CermakM
Copy link

CermakM commented Oct 15, 2022

+1

1 similar comment
@andreav
Copy link

andreav commented Oct 20, 2022

+1

@dan-hook
Copy link

dan-hook commented Dec 19, 2022

@bothra90

"VpcConfig": {
"SecuritGroupIds": {
"Ref": "securityGroupIds"
},

Typo in "SecuritGroupIds"

@boris-lapouga
Copy link

+1

2 similar comments
@liamJunkermann
Copy link

+1

@FelipeRuizGarcia
Copy link

+1

@Thiamath
Copy link

After 5 years since this was reported... can we expect any advancement here? Or we will have to keep doing it manually...

@espetro
Copy link

espetro commented Apr 12, 2024

+1

1 similar comment
@rjmarwil
Copy link

rjmarwil commented May 9, 2024

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request a new feature functions Issues tied to the functions category p4
Projects
None yet
Development

No branches or pull requests