diff --git a/api/README.md b/api/README.md new file mode 100644 index 0000000..4d19351 --- /dev/null +++ b/api/README.md @@ -0,0 +1,5 @@ +# API Server for Pare Cloud + +Responsible for managing the lifecycle of a Pare endpoint. + +Handles user authentication, routing based on the git hash, and deploying/updating Lambdas. diff --git a/api/src/deploy/lambda_deploy.py b/api/src/deploy/lambda_deploy.py index bbc347d..fd7a02e 100644 --- a/api/src/deploy/lambda_deploy.py +++ b/api/src/deploy/lambda_deploy.py @@ -2,7 +2,7 @@ import asyncio import json -from typing import Callable, TypeVar +from typing import Any, Callable, TypeVar import boto3 from botocore.exceptions import ClientError @@ -11,7 +11,26 @@ from src import settings -def create_ecr_repository(repository_name: str) -> bool: +def generate_ecr_repo_policy(function_name: str) -> dict[str, Any]: + return { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "LambdaECRImageRetrievalPolicy", + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": ["ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer"], + "Condition": { + "StringLike": { + "aws:sourceArn": f"arn:aws:lambda:{settings.AWS_DEFAULT_REGION}:{settings.AWS_ACCOUNT_ID}:function:{function_name}" + } + }, + } + ], + } + + +def create_ecr_repository(repository_name: str, function_name: str) -> bool: ecr_client = boto3.client("ecr", region_name=settings.AWS_DEFAULT_REGION) # type: ignore try: @@ -30,7 +49,7 @@ def create_ecr_repository(repository_name: str) -> bool: ecr_client.set_repository_policy( # type: ignore repositoryName=repository_name, - policyText=json.dumps(settings.ECR_REPO_POLICY), + policyText=json.dumps(generate_ecr_repo_policy(function_name)), ) print(f"Repository policy set for '{repository_name}'") return True diff --git a/api/src/deploy/routes.py b/api/src/deploy/routes.py index 04dd964..0caaf8a 100644 --- a/api/src/deploy/routes.py +++ b/api/src/deploy/routes.py @@ -45,7 +45,8 @@ async def deploy_image( ) -> bool: repo_name = build_ecr_repo_name(user, service_config.name) tag = deploy_config.git_hash - repo_created = create_ecr_repository(repo_name) + function_name = build_lambda_function_name(repo_name, tag) + repo_created = create_ecr_repository(repo_name, function_name=function_name) if not repo_created: print(f"Failed to create ECR repository for {repo_name}") return False @@ -61,7 +62,7 @@ async def deploy_image( return False return await deploy_python_lambda_function_from_ecr( - function_name=build_lambda_function_name(repo_name, tag), + function_name=function_name, image_name=build_result.image_name, environment_variables=deploy_config.environment_variables, ) diff --git a/api/src/settings.py b/api/src/settings.py index 6389970..53900fc 100644 --- a/api/src/settings.py +++ b/api/src/settings.py @@ -2,7 +2,6 @@ from __future__ import annotations from pathlib import Path -from typing import Any from environs import Env @@ -36,23 +35,6 @@ AWS_LAMBDA_UPDATE_INITIAL_BACKOFF: int = env.int("AWS_LAMBDA_UPDATE_INITIAL_BACKOFF", 1) AWS_LAMBDA_UPDATE_MAX_RETRIES: int = env.int("AWS_LAMBDA_UPDATE_MAX_RETRIES", 8) -ECR_REPO_POLICY: dict[str, Any] = { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "LambdaECRImageRetrievalPolicy", - "Effect": "Allow", - "Principal": {"Service": "lambda.amazonaws.com"}, - "Action": ["ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer"], - "Condition": { - "StringLike": { - "aws:sourceArn": f"arn:aws:lambda:{AWS_DEFAULT_REGION}:{AWS_ACCOUNT_ID}:function:*" - } - }, - } - ], -} - PARE_ATOMIC_DEPLOYMENT_HEADER: str = env.str( "PARE_ATOMIC_DEPLOYMENT_HEADER", "X-Pare-Atomic-Deployment" )