# Solving the AWS CloudFront Cross-Region Certificate Puzzle with CDK

## The Problem That Makes Developers Pull Their Hair Out

When you design infrastructure across multiple AWS regions, you expect each region to be self-contained — its own EKS clusters, databases, Lambdas, and certificates — all neatly separated by region.

That’s how my CDK setup was built: a clean, modular design that could deploy the same infrastructure stack in any region (ap-southeast-2, ap-south-1, etc.) just by switching configuration.

Everything worked perfectly… until CloudFront entered the picture.

The moment I added CloudFront for my frontend, deployments started failing with confusing certificate errors like:

```plaintext
Error: Certificate for alternate domain name is not issued by AWS Certificate Manager
```

Or worse:

```plaintext
The certificate that is attached to your distribution doesn't cover the alternate domain name
```

After debugging, I realized the issue wasn’t with my setup at all — it was an AWS constraint hiding in plain sight:

**CloudFront requires SSL certificates to be created in us-east-1, no matter where your infrastructure lives.**

That single requirement completely broke my otherwise predictable, region-specific deployment model. This post walks through how I solved it — a clean, battle-tested pattern to handle CloudFront’s cross-region certificate constraint using AWS CDK, without messy hacks or manual intervention.

## Problem 1: The Hidden us-east-1 Certificate Requirement

### The Problem

AWS CloudFront is a global service, but it has a peculiar requirement: SSL/TLS certificates used with CloudFront distributions **must** be created in the `us-east-1` region. This isn't clearly stated in error messages, and developers often waste hours trying to debug certificate validation issues.

**Common symptoms:**

* Certificate validation succeeds in your primary region but CloudFront still fails
    
* "Certificate not found" errors despite the certificate existing
    
* CloudFormation rollbacks with cryptic certificate-related errors
    

### The Solution

Create a dedicated stack for us-east-1 resources that extends your domain stack:

```typescript
// src/stacks/domain/us-east1-domain.stack.ts
export class USEast1DomainStack extends DomainStack {
  constructor(scope: Construct, id: string, props: IStackProps) {
    super(scope, id, {
      ...props,
      description: 'Stack to create domain resources in us-east-1',
    }, true);

    // Enforce us-east-1 deployment
    if (props.env?.region !== 'us-east-1' ||
        props.config.region !== 'us-east-1') {
      throw new Error('This stack must be deployed in us-east-1 region');
    }

    // Create wildcard certificate for CloudFront
    this.createWildcardCertificate();
    this.createWebAppReviewCertificates();
  }
}
```

**Why this works:** By explicitly creating a separate stack for us-east-1 resources, you maintain clean separation of concerns while ensuring certificates are in the correct region.

## Problem 2: Cross-Region Reference Failures

### The Problem

When your main infrastructure is in `ap-southeast-2` but certificates are in `us-east-1`, CDK throws errors:

```plaintext
Error: Stack "FrontendStack" cannot reference "USEast1DomainStack" across regions without crossRegionReferences enabled
```

Even worse, CloudFormation exports don't automatically work across regions, leading to deployment failures.

### The Solution

Enable cross-region references when creating the us-east-1 stack:

```typescript
// src/stages/microservices-platform.stage.ts
const usEast1DomainStack = new USEast1DomainStack(
  this,
  'USEast1DomainStack',
  {
    ...props,
    env: {
      ...props.env,
      region: 'us-east-1',  // Override region
    },
    config: {
      ...props.config,
      region: 'us-east-1',  // Update config region too
    },
    crossRegionReferences: true,  // Critical!
  },
);

// Frontend stack can now reference us-east-1 certificates
const frontendStack = new FrontendStack(this, 'FrontendStack', {
  ...props,
  domainStack: usEast1DomainStack,  // Pass the us-east-1 stack
  crossRegionReferences: true,
});
```

**Why this works:** The `crossRegionReferences` flag tells CDK to use AWS Systems Manager Parameter Store to share values between regions, working around CloudFormation's regional limitations.

## Problem 3: Stack Dependency and Deployment Order

### The Problem

Complex dependency chains emerge when you have:

* A domain stack in your primary region (for Route53)
    
* A us-east-1 domain stack (for certificates)
    
* Frontend stacks that need both
    

Incorrect dependency setup leads to:

* Circular dependency errors
    
* Resources created in wrong order
    
* "Export already exists" conflicts
    

### The Solution

Implement intelligent dependency management:

```typescript
// Conditional domain stack creation based on region
let domainStack: DomainStack | undefined = undefined;

if (this.config.region !== 'us-east-1') {
  domainStack = new DomainStack(this, 'DomainStack', props, true);
}

const usEast1DomainStack = new USEast1DomainStack(
  this,
  'USEast1DomainStack',
  { /* ... */ }
);

// Set up dependency chain
if (domainStack) {
  usEast1DomainStack.addDependency(domainStack);
} else {
  domainStack = usEast1DomainStack;  // us-east-1 IS the domain stack
}

// Frontend depends on us-east-1 stack for certificates
const frontendStack = new FrontendStack(this, 'FrontendStack', {
  ...props,
  domainStack: usEast1DomainStack,
  crossRegionReferences: true,
});

frontendStack.addDependency(usEast1DomainStack);
```

**Why this works:** This pattern ensures:

1. Route53 hosted zone is created first (if needed)
    
2. Certificates are created in us-east-1 with DNS validation
    
3. Frontend resources wait for certificates to be ready
    

## Problem 4: Managing Multiple Apps and Review Deployments

### The Problem

Modern development workflows require:

* Multiple frontend applications (admin portal, customer app, etc.)
    
* Review/preview deployments for pull requests
    
* Wildcard certificates for dynamic subdomains
    

Managing certificates for all these scenarios becomes complex.

### The Solution

Use a combination of wildcard certificates and app-specific certificates:

```typescript
// Base wildcard certificate for all standard subdomains
private createWildcardCertificate(): void {
  this._wildcardCertificate = new acm.Certificate(
    this,
    'WildcardCertificate',
    {
      domainName: `*.${this.domainName}`,
      validation: acm.CertificateValidation.fromDns(this.hostedZone),
    }
  );
}

// App-specific wildcard certificates for review deployments
private createWebAppReviewCertificates(): void {
  for (const frontEndAppName in this.config.domainConfig.frontendApp) {
    const enableReviews = this.config.frontendApps?.find(
      (app) => app.name === frontEndAppName,
    )?.enableReviews;

    if (!enableReviews) continue;

    const frontEndDomain =
      this.config.domainConfig.frontendApp[frontEndAppName]?.subDomainName;

    // Create wildcard for review apps: *.app.domain.com
    const certificate = new acm.Certificate(
      this,
      `${frontEndDomain}-certificate`,
      {
        domainName: `${frontEndDomain}.${this.domainName}`,
        subjectAlternativeNames: [`*.${frontEndDomain}.${this.domainName}`],
        validation: acm.CertificateValidation.fromDns(this.hostedZone),
      }
    );

    this.webappReviewCertificates.set(frontEndAppName, certificate);
  }
}
```

**Why this works:** This approach provides flexibility for both stable deployments and dynamic review environments without certificate proliferation.

## Problem 5: Bootstrap and Environment Configuration

### The Problem

Cross-region deployments require:

* Both regions to be bootstrapped
    
* Environment-specific configurations
    
* Proper IAM trust relationships
    

Missing any of these causes deployment failures that are hard to debug.

### The Solution

1. **Bootstrap both regions before deployment:**
    

```bash
# Bootstrap primary region
cdk bootstrap aws://ACCOUNT_ID/ap-southeast-2

# Bootstrap us-east-1 for certificates
cdk bootstrap aws://ACCOUNT_ID/us-east-1
```

2. **Use environment-specific configuration:**
    

```typescript
// src/config/environments/dev/config.dev.ts
export const AUDevConfig: IConfig = {
  accountID: DEV_ACCOUNT_ID,
  region: 'ap-southeast-2',
  env: 'DEV',
  iluminrPrimaryRegion: 'ap-southeast-2',
  domainConfig: devDomainConfig,
  frontendApps: devFrontendConfig,
  // ... other config
};
```

3. **Consume configuration in your CDK app:**
    

```typescript
// Frontend stack integration
const frontendStack = new FrontendStack(this, 'FrontendStack', {
  ...props,
  domainStack: usEast1DomainStack,
  crossRegionReferences: true,
});

// Angular deployment using the cross-region certificate
new AngularAppDeployment(this, app.name, {
  appName: app.name,
  subDomainName: props.config.domainConfig.frontendApp[app.name]?.subDomainName,
  rootDomain: props.config.domainConfig.domainName,
  certificate: props.domainStack.wildcardCertificate,  // From us-east-1
  hostedZone: props.domainStack.hostedZone,
  env: props.config.env,
});
```

**Why this works:** Proper bootstrapping ensures CDK has the necessary resources in both regions, while configuration management keeps your infrastructure DRY and maintainable.

## Best Practices

1. **Always validate certificates using DNS validation** - It works across regions without manual intervention
    
2. **Use wildcard certificates strategically** - Reduces certificate count and management overhead
    
3. **Tag your resources consistently** - Makes debugging and cost allocation easier
    
4. **Export critical values** - Certificate ARNs, distribution IDs for use by CI/CD pipelines
    
5. **Document region requirements** - Add error checks that explicitly state region requirements
    

## Common Pitfalls to Avoid

### ❌ Don't Forget to Bootstrap us-east-1

Even if your infrastructure is elsewhere, us-east-1 needs bootstrapping for certificate creation.

### ❌ Don't Mix Regional and Global Resources

Keep clear separation between regional stacks and us-east-1 stacks.

### ❌ Don't Ignore Deletion Order

When destroying stacks, delete in reverse dependency order:

```bash
# Delete frontend first
cdk destroy FrontendStack
# Then us-east-1 resources
cdk destroy USEast1DomainStack
# Finally, primary region resources
cdk destroy DomainStack
```

### ❌ Don't Hardcode Region Values

Always use configuration to manage regions:

```typescript
// Bad
const stack = new Stack(this, 'Stack', { env: { region: 'us-east-1' } });

// Good
const stack = new Stack(this, 'Stack', {
  env: { region: config.certificateRegion }
});
```

## Conclusion

The CloudFront cross-region certificate requirement is a classic AWS gotcha that has frustrated countless developers. By understanding the underlying constraints and implementing a clean separation between regional and us-east-1 resources, you can build robust, multi-region CDK applications without the headache.

Key takeaways:

* **Always create CloudFront certificates in us-east-1**
    
* **Use** `crossRegionReferences: true` for cross-region stack dependencies
    
* **Implement proper dependency chains between stacks**
    
* **Bootstrap all regions before deployment**
    
* **Use configuration-driven infrastructure for flexibility**
    

This pattern has been battle-tested in production environments serving millions of requests. It provides a solid foundation for building globally distributed applications with AWS CDK while maintaining clean, maintainable infrastructure code.

Remember: The complexity is in understanding the problem. Once you know the constraints, the solution is straightforward.

---

*Have you encountered other cross-region challenges with AWS CDK? What patterns have worked for you? Share your experiences and let's build better infrastructure together.*
