AWS App Runner Private Service with Private Integration

2 min read aws

based on KarlDeux/arps

Demo

export AWS_PROFILE="hub01-admin"
export STACK_NAME=aws-app-runner-private-service-with-private-integration
export REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

sam build --use-container

sam deploy --guided
sam deploy

aws cloudformation describe-stacks \
  --stack-name $STACK_NAME \
  --region $REGION \
  --query 'Stacks[0].Outputs' \
  > stack-outputs.json

# get default vpc id
export DEFAULT_VPC_ID=$(aws ec2 describe-vpcs --region $REGION  --filters "Name=isDefault,Values=true" --query "Vpcs[0].VpcId" --output text)

aws ec2 describe-subnets --filters "Name=vpc-id,Values=${DEFAULT_VPC_ID}" --query "Subnets[].SubnetId" --output text


sam delete --no-prompts

aws cloudformation delete-stack --stack-name $STACK_NAME

# login to ecr from docker
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com

docker build -t hello-world-express .
docker run -p 8000:8000 hello-world-express
docker tag hello-world-express:latest $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$STACK_NAME
docker push $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$STACK_NAME
docker pull "${AWS_ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${STACK_NAME}:latest"


# deployment and event logs
/aws/apprunner/code-based-private-endpoint-1/58b5e70db6aa4481b6cf42ca0c38b5f9/service

# application logs
/aws/apprunner/private-endpoint-1/cc0078056c7d48ab9b434dfcadc796f3/application

# test the enpoint.  this public apig endpoint calls a lambda fn in vpc that calls private app runner services
watch curl https://r4d8inqs3m.execute-api.us-east-1.amazonaws.com/Prod/test

# pause all services
json_data=$(cat aws-app-runner-list-services.json)

# Get the length of the array within the "ServiceSummaryList" property
length=$(echo $json_data | jq '.ServiceSummaryList | length')

# Loop over each element in the array
for (( i=0; i<$length; i++ )); do
  # Extract the object at index $i within the "ServiceSummaryList" array
  object=$(echo $json_data | jq -c ".ServiceSummaryList[$i]")

  # Extract the 'ServiceName' field from the object
  service_name=$(echo $object | jq -r '.ServiceName')
  service_id=$(echo $object | jq -r '.ServiceId')
  service_arn=$(echo $object | jq -r '.ServiceArn')

  # Print out the ServiceName
  echo "Pausing ServiceName: $service_name"
  aws apprunner pause-service --service-arn "${service_arn}"
done
  • log types - event logs (/aws/apprunner/code-based-private-endpoint-1/ba93db338128426481f912edc4d493c1/service/events), deployment logs (/aws/apprunner/code-based-private-endpoint-1/ba93db338128426481f912edc4d493c1/service/deployment/<deployment_id>), application logs

TODO

  • private service only accessible via VPC
  • private integration only accessible via VPC. e.g. RDS DB in private subnet
  • testing - apig -> lambda with VPC access/config to test private app runner service. this is a lot easier than running ec2 in a VPC

screenshots

App Runner Console | Services

App Runner Console | Service Detail View

App Runner Console | Service Detail View | Deployment Logs

CloudWatch Service and Application Log Groups

Resources