简体   繁体   English

AWS CDK - 无法通过 Cloudfront 域访问 ALB

[英]AWS CDK - Can't access ALB through Cloudfront domain

I'm trying to deploy a fairly basic Nodejs CRUD API to AWS using AWS-CDK.我正在尝试使用 AWS-CDK 将一个相当基本的 Nodejs CRUD API 部署到 AWS。 The service runs in a docker container and I'm deploying it to an ECS Fargate cluster behind an ALB.该服务在 docker 容器中运行,我将其部署到 ALB 后面的 ECS Fargate 集群。 I also have a domain in Route53 that I'm trying to use.我在 Route53 中也有一个我正在尝试使用的域。

The problem I'm having is I can't seem to access the ALB through the domain.我遇到的问题是我似乎无法通过域访问 ALB。 I can access the ALB directly using its default AWS DNS (XXXXX.us-west-2.elb.amazonaws.com/) over HTTP, but I get 504 timeouts when I attempt to access it through the domain.我可以通过 HTTP 使用其默认 AWS DNS (XXXXX.us-west-2.elb.amazonaws.com/) 直接访问 ALB,但是当我尝试通过域访问它时会出现 504 超时。

I'm pretty new to AWS and CDK, so I'm sure I'm missing something obvious here.我对 AWS 和 CDK 很陌生,所以我确定我在这里遗漏了一些明显的东西。 Any advice or recommended resources/examples would be much appreciated.任何建议或推荐的资源/示例将不胜感激。 Here's my CDK code:这是我的 CDK 代码:

import { Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as Cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as CloudfrontOrigins from "aws-cdk-lib/aws-cloudfront-origins";
import * as Route53 from "aws-cdk-lib/aws-route53";
import * as Route53Targets from "aws-cdk-lib/aws-route53-targets";
import * as ACM from "aws-cdk-lib/aws-certificatemanager";
import * as EC2 from "aws-cdk-lib/aws-ec2";
import * as ECS from "aws-cdk-lib/aws-ecs";
import * as EcsPatterns from "aws-cdk-lib/aws-ecs-patterns";

interface Props extends StackProps {
  domainName: string;
  dockerDir: string;
}

export class AppStack extends Stack {
  constructor(scope: Construct, id: string, { domainName, dockerDir, ...rest }: Props) {
    super(scope, id, rest);

    const hostedZone = Route53.HostedZone.fromLookup(this, `${id}_Zone`, {
      domainName,
    });

    const vpc = new EC2.Vpc(this, `${id}_Vpc`, { maxAzs: 2 });
    const cluster = new ECS.Cluster(this, `${id}_Ec2Cluster`, { vpc });
    cluster.addCapacity(`${id}_DefaultAutoScalingGroup`, {
      instanceType: EC2.InstanceType.of(
        EC2.InstanceClass.T3,
        EC2.InstanceSize.MICRO
      ),
      minCapacity: 1,
      maxCapacity: 3,
    });
    const certificate = new ACM.DnsValidatedCertificate(
      this,
      `${id}_SiteCertificate`,
      {
        domainName,
        hostedZone,
        region: "us-east-1",
      }
    );
  
    const fargateService = new EcsPatterns.ApplicationLoadBalancedFargateService(
      this,
      `${id}_FargateLoadBalancedService`,
      {
        cluster,
        desiredCount: 1,
        publicLoadBalancer: true,
        taskImageOptions: {
          image: ECS.ContainerImage.fromAsset(dockerDir),
          containerPort: 8000,
          environment: {
            PORT: '8000',
          },
        },
      }
    );
  
    const distribution = new Cloudfront.Distribution(
      this,
      `${id}_SiteDistribution`,
      {
        certificate,
        domainNames: [domainName],
        minimumProtocolVersion: Cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
        defaultBehavior: {
          origin: new CloudfrontOrigins.HttpOrigin(
            fargateService.loadBalancer.loadBalancerDnsName
          ),
          compress: false,
          cachePolicy: Cloudfront.CachePolicy.CACHING_DISABLED,
          allowedMethods: Cloudfront.AllowedMethods.ALLOW_ALL,
        },
      }
    );
  
  
    new Route53.ARecord(this, `${id}_SiteAliasRecord`, {
      recordName: domainName,
      target: Route53.RecordTarget.fromAlias(
        new Route53Targets.CloudFrontTarget(distribution)
      ),
      zone: hostedZone,
    });
  }
}

And this class gets created in my bin/infra.ts file:这个类是在我的 bin/infra.ts 文件中创建的:

#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import * as path from "path";
import { AppStack } from "../lib/AppStack";

const appId = `MyApp`;
const app = new cdk.App();

new AppStack(app, `${appId}Stack`, {
  dockerDir: path.resolve(__dirname, "..", "api"), // contains the Dockerfile
  domainName: 'mydomain.com',
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION,
  },
});

And here's the Dockerfile in case it's useful.这是 Dockerfile 以防万一它有用。

FROM node:16-alpine as builder

ENV NODE_ENV build

USER node
WORKDIR /home/node

COPY package*.json ./
RUN npm i

COPY --chown=node:node . .
RUN npm run build \
    && npm prune --production

# ---

FROM node:16-alpine

ENV PORT 8000
ENV NODE_ENV production

# Add curl for healthcheck
RUN apk --no-cache add curl

USER node
WORKDIR /home/node

COPY --from=builder --chown=node:node /home/node/package*.json ./
COPY --from=builder --chown=node:node /home/node/node_modules/ ./node_modules/
COPY --from=builder --chown=node:node /home/node/dist/ ./dist/

EXPOSE 8000
CMD ["node", "dist/main.js"]
HEALTHCHECK CMD curl -f http://localhost:8000/api/healthcheck || exit 1

Why am I getting 504 errors when I access my service through my domain?当我通过我的域访问我的服务时,为什么会收到 504 错误? Or where can I look to get a better idea of what I'm missing?或者我在哪里可以更好地了解我错过了什么?

CloudFront talks HTTPS (port 443) to its origins by default.默认情况下,CloudFront 将 HTTPS(端口 443)与其源通信。 An ALB (regardless of whether created explicitly or implicitly by the ApplicationLoadBalancedFargateService construct) listens on HTTP (port 80) by default unless explicitly set up for HTTPS.默认情况下,ALB(无论是由ApplicationLoadBalancedFargateService构造显式创建还是隐式创建)侦听 HTTP(端口 80),除非显式设置为 HTTPS。 As your ALB is not configured to listen on HTTPS, CloudFront attempts to talk HTTPS to an ALB that only listens on HTTP.由于您的 ALB 未配置为侦听 HTTPS,CloudFront 尝试将 HTTPS 与仅侦听 HTTP 的 ALB 通信。

To fix that, set origin.protocolPolicy to OriginProtocolPolicy.HTTP_ONLY , which instructs CloudFront to talk HTTP to your ALB.要解决此问题,请将origin.protocolPolicy设置为OriginProtocolPolicy.HTTP_ONLY ,这会指示 CloudFront 将 HTTP 与您的 ALB 通信。 Please note that the below code uses CDK v2 and also, I've used LoadBalancerV2Origin over HttpOrigin , although both should work the same.请注意,下面的代码使用 CDK v2,而且我使用LoadBalancerV2Origin而不是HttpOrigin ,尽管两者应该工作相同。

const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
  vpc,
  internetFacing: true,
});
new cloudfront.Distribution(this, 'myDist', {
  defaultBehavior: {
    new origins.LoadBalancerV2Origin(loadBalancer, {
      protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY,
    })
  },
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 AWS CDK 将域别名添加到现有 CloudFront 分配 - How to add domain alias to existing CloudFront distribution using AWS CDK Cloudfront 在没有公共访问的情况下为 S3 存储桶源提供通过 AWS CDK Python 创建的访问被拒绝的响应 - Cloudfront give Access denied response created through AWS CDK Python for S3 bucket origin without public Access 无法通过 S3 访问通过 CloudFront 更新的文件 - Can't access through S3 to files updated through CloudFront AWS Cloudfront 无法访问使用 CodeBuild 部署的 S3 文件 - AWS Cloudfront can't access S3 files deployed with CodeBuild 如何通过CloudFront访问aws websocket - How to access aws websocket through CloudFront AWS Cloudfront(使用WAF)+ API网关:如何通过Cloudfront强制访问? - AWS Cloudfront (with WAF) + API Gateway: how to force access through Cloudfront? S3 和 ALB 前面的 AWS CloudFront - AWS CloudFront in front of S3 and ALB 通过 VPC 端点和 ALB 访问 AWS S3 - AWS S3 access through VPC endpoint and ALB 无法使用 AWS SDK 为 Java 2.x 添加新的备用域名到 CloudFront 资源 - Can't add new alternative domain name to CloudFront resource using AWS SDK for Java 2.x 我没有 API 网关、ALB 或 Cloudfront 我的 AWS 环境中的 WAF 解决方案是什么 - I don't have API Gateway, ALB or Cloudfront what are my solution for the WAF in my AWS environment
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM