Skip to content

Commit 0bc55ca

Browse files
authored
fix(deployment): add missing policy (#36)
1 parent dc0abe3 commit 0bc55ca

6 files changed

Lines changed: 23 additions & 15 deletions

File tree

‎infra/template.yml‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,7 @@ Resources:
368368
]
369369
}
370370
371-
# Execution role assigned to every user-deployed Lambda (app-*). The function-deployer
372-
# hardcodes this exact role name (LambdaDeploymentRepository.java: role/UserFunctionRole).
371+
# Execution role assigned to every user-deployed Lambda (app-*).
373372
# Intentionally minimal: untrusted user code only gets CloudWatch Logs access.
374373
#
375374
# Log retention/cleanup for these functions is handled by the function-deployer at runtime
@@ -379,7 +378,6 @@ Resources:
379378
UserFunctionRole:
380379
Type: AWS::IAM::Role
381380
Properties:
382-
RoleName: UserFunctionRole # name is hardcoded in LambdaDeploymentRepository.java
383381
AssumeRolePolicyDocument:
384382
Version: '2012-10-17'
385383
Statement:
@@ -417,6 +415,7 @@ Resources:
417415
LAMBDA_ENVIRONMENT: "FUNCTION_DEPLOYER_LAMBDA"
418416
ECR_REPOSITORY_URI: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepositoryName}"
419417
DEPLOYMENTS_METADATA_TABLE: !Ref DeploymentsMetadataTable
418+
FUNCTION_URL_USER_ROLE_ARN: !GetAtt UserFunctionRole.Arn
420419
Policies:
421420
# create the user's Lambda from the ECR image and expose it via a public Function URL
422421
- Statement:

‎lambda/common-utils/src/main/java/com/hosting/common/aws/repositories/LambdaDeploymentRepository.java‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ private String getLogGroupName(String functionName) {
3939
return "/aws/lambda/" + functionName;
4040
}
4141

42-
public void createFunction(String deploymentId, String imageUri, String accountId) {
43-
// role name must match the one in template.yml
44-
String roleArn = String.format("arn:aws:iam::%s:role/UserFunctionRole", accountId);
42+
public void createFunction(String deploymentId, String imageUri) {
43+
String roleArn = UserLambdaConfig.FUNCTION_URL_ROLE_ARN;
4544
String functionName = getFunctionName(deploymentId);
4645

4746
// Pre-create the log group. Otherwise Lambda auto-creates it on first
@@ -81,6 +80,7 @@ public String setupFunctionUrl(String deploymentId) {
8180

8281
LOGGER.info("Created new Function URL: {}", url);
8382

83+
// see https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html; both permissions required
8484
lambdaClient.addPermission(
8585
AddPermissionRequest.builder()
8686
.functionName(functionName)
@@ -90,6 +90,15 @@ public String setupFunctionUrl(String deploymentId) {
9090
.functionUrlAuthType(FunctionUrlAuthType.NONE)
9191
.build());
9292
LOGGER.info("Added public access permission to Function URL for {}", functionName);
93+
lambdaClient.addPermission(
94+
AddPermissionRequest.builder()
95+
.functionName(functionName)
96+
.statementId("PublicFunctionInvokeAccess")
97+
.action("lambda:InvokeFunction")
98+
.principal("*")
99+
.functionUrlAuthType(FunctionUrlAuthType.NONE)
100+
.build());
101+
LOGGER.info("Added public invoke permission to Function for {}", functionName);
93102

94103
return url;
95104
} catch (Exception e) {

‎lambda/common-utils/src/main/java/com/hosting/common/config/UserLambdaConfig.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import software.amazon.awssdk.services.lambda.model.Architecture;
44
import software.amazon.awssdk.services.lambda.model.PackageType;
55

6-
public final class UserLambdaConfig {
6+
public final class UserLambdaConfig extends BaseConfig {
77

88
private UserLambdaConfig() {
99
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
@@ -12,6 +12,7 @@ private UserLambdaConfig() {
1212
public static final PackageType PACKAGE_TYPE = PackageType.IMAGE;
1313
// architecture should match the codebuild architecture in the template.yml
1414
public static final Architecture ARCHITECTURE = Architecture.ARM64;
15-
public static final int TIMEOUT_SECONDS = 30;
15+
public static final int TIMEOUT_SECONDS = 5; // short for user code
1616
public static final int MEMORY_SIZE_MB = 128;
17+
public static final String FUNCTION_URL_ROLE_ARN = getOrThrow("FUNCTION_URL_USER_ROLE_ARN");
1718
}

‎lambda/function-deployer-lambda/src/main/java/com/hosting/deployer/handler/FunctionDeployerHandler.java‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public Void handleRequest(Map<String, Object> event, Context context) {
5757

5858
LOGGER.info("Processing CodeBuild SUCCEEDED event");
5959

60-
String accountId = context.getInvokedFunctionArn().split(":")[4];
61-
deploymentManagerService.deploy(userId, deploymentId, imageTag, accountId);
60+
deploymentManagerService.deploy(userId, deploymentId, imageTag);
6261

6362
} catch (Exception e) {
6463
LOGGER.error("Failed to process deployment event", e);

‎lambda/function-deployer-lambda/src/main/java/com/hosting/deployer/service/DeploymentManagerService.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ public DeploymentManagerService(
1818
this.deploymentService = deploymentService;
1919
}
2020

21-
public void deploy(String userId, String deploymentId, String imageTag, String accountId) {
21+
public void deploy(String userId, String deploymentId, String imageTag) {
2222
LOGGER.info("Starting API deployment");
2323

2424
String repositoryUri = EcrConfig.REPOSITORY_URI;
2525
String imageUri = repositoryUri + ":" + imageTag;
2626

27-
lambdaRepository.createFunction(deploymentId, imageUri, accountId);
27+
lambdaRepository.createFunction(deploymentId, imageUri);
2828
String functionUrl = lambdaRepository.setupFunctionUrl(deploymentId);
2929

3030
deploymentService.setApiUri(userId, deploymentId, functionUrl);

‎web/src/docs/documentation.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ app.listen(port, () => console.log(`Server running on port ${port}`));
4343

4444
### Python Setup
4545

46-
1. Your dependency file (**`requirements.txt`** or **`pyproject.toml`**) must be in the **root directory**.
46+
1. Your dependency file (**`requirements.txt`** or **`pyproject.toml`**) must be in the **root directory**. Note that `uvicorn` as an ASGI server is a required dependency.
4747
2. Your main application file must be named **`main.py`** and located in the root directory.
4848
3. Inside `main.py`, your FastAPI instance variable must be named **`app`**.
4949

@@ -65,7 +65,7 @@ def read_root():
6565

6666
You can define custom environment variables directly in your project's deployment settings on the APIForge dashboard.
6767

68-
* All variables are encrypted at rest and injected into your runtime environment automatically.
68+
* Secret variables are encrypted at rest and injected into your runtime environment automatically. Note that they will not be rotated
6969
* **Never** commit secrets, passwords, or `.env` files to your repository.
7070
* **Note for Node.js:** The `PORT` variable is reserved by the platform and automatically managed for you.
7171

@@ -75,6 +75,6 @@ You can define custom environment variables directly in your project's deploymen
7575

7676
| Resource | Limit | Description |
7777
| --- | --- | --- |
78-
| Request Timeout | 30 seconds | Maximum time your API has to respond to an incoming request. |
78+
| Request Timeout | 5 seconds | Maximum time your API has to respond to an incoming request. |
7979
| Payload Size | 6 MB | Maximum size for incoming HTTP request bodies and responses. |
8080
| Concurrency | 1,000 | Maximum number of simultaneous requests handled before throttling. |

0 commit comments

Comments
 (0)