(Read this article on the blog)

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.

Source: View source