Deployment circle with CloudFront and Terraform
The aws_cloudfront_distribution
resource has a very concise config: its origins and cache behaviors are arguments instead of separate resources.
This helps with deployment time as that required only one 4-minute waiting.
But it also makes it easier to end up with a dependency circle. This is the most recent one I encountered:
There is a NodeJS app that verifies the JWT passed by the user:
const jwtVerifier = CognitoJwtVerifier.create({
userPoolId: process.env.COGNITO_USER_POOL_ID,
tokenUse: "access",
clientId: process.env.COGNITO_CLIENT_ID,
});
This creates a circle:
The distribution uses a VPC origin that is an EC2 instance:
resource "aws_cloudfront_distribution" "distribution" {
origin {
origin_id = "backend"
vpc_origin_config {
vpc_origin_id = aws_cloudfront_vpc_origin.backend.id
}
}
}
The vpc origin depends on the instance:
resource "aws_cloudfront_vpc_origin" "backend" {
vpc_origin_endpoint_config {
arn = aws_instance.backend.arn
}
}
That instance has a setup script:
resource "aws_instance" "backend" {
user_data = local.user_data
}
That user data starts the NodeJS server that sets the Cognito User Pool client id:
locals {
user_data = <<-EOF
#!/bin/bash
...
export COGNITO_USER_POOL_ID="${aws_cognito_user_pool.pool.id}"
export COGNITO_CLIENT_ID="${aws_cognito_user_pool_client.client.id}"
export PORT="8080"
EOF
}
But then the User Pool client needs the CloudFront distibution:
resource "aws_cognito_user_pool_client" "client" {
callback_urls = ["https://${aws_cloudfront_distribution.distribution.domain_name}"]
}
If there was a way to separate the origins config from the CloudFront distribution resource this would be easy to configure: the Cognito client could be created after the distribution then the origins could be configured after.