【发布时间】:2021-10-20 19:04:50
【问题描述】:
我正在使用 AWS CDK 为各种其他微服务构建 CloudFront Ingress。它在工作时似乎超级不一致,通常只有第一个请求,然后它完全失败。
我确保在测试任何更改之前使整个发行版无效并确保所有内容都已更新,但我没有运气。
我的目标是:
-
/graphql-> API 网关 -
/app/*-> S3 网站存储桶(应用静态 SPA) -
* (Default)-> S3 网站存储桶(网站静态 SPA)
我正在使用 CloudFront 函数重写对非默认来源的请求以删除前缀:
/* eslint-disable */
function handler(event) {
var request = event.request;
request.uri = request.uri.replace(/^\/[^/]*\//, '/');
return request;
}
当通过控制台进行测试时,它按预期工作(/app/login 变为 /login 等)
然而,似乎发生的情况是,在可能 1 个请求(有时是 0 个请求)之后不尊重起源,并且它默认为 * 行为。
我的主要ingress CDK 堆栈是这样定义的:
import { CloudFrontAllowedMethods, CloudFrontWebDistribution, SSLMethod, ViewerCertificate, SecurityPolicyProtocol, FunctionEventType, Function, FunctionCode, ViewerProtocolPolicy, Behavior, OriginProtocolPolicy, PriceClass } from '@aws-cdk/aws-cloudfront';
import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager';
import { ARecord, HostedZone, RecordTarget } from '@aws-cdk/aws-route53';
import { CloudFrontTarget } from '@aws-cdk/aws-route53-targets';
import { Metric } from '@aws-cdk/aws-cloudwatch';
import { Construct, Duration } from '@aws-cdk/core';
import { Aws, Stack } from '@aws-cdk/core';
import { createGraphQL } from '../graphql';
import { createSite } from '../site';
import { createApp } from '../app';
import type { StackProps } from './types';
export async function createIngress(scope: Construct, id: string, props: StackProps) {
const stack = new Stack(scope, `${id}-${props.environment}`, props);
const serviceProps = {
environment: props.environment,
root: props.root,
core: props.core,
};
// Create the various Services for the Ingress.
const app = await createApp(stack, 'app-resources', serviceProps);
const site = await createSite(stack, 'site-resources', serviceProps);
const graphql = await createGraphQL(stack, 'graphql-resources', serviceProps);
// Fetch the DNS Zone.
const zone = HostedZone.fromLookup(stack, 'ingress-zone', {
domainName: props.domainName,
});
// Ensure there is a Certificate and fetch the ARN.
const { certificateArn } = new DnsValidatedCertificate(stack, 'ingress-cert', {
domainName: props.domainName,
hostedZone: zone,
region: 'us-east-1', // Cloudfront only checks this region for certificates.
});
// Fetch the Viewer Certificate.
const viewerCertificate = ViewerCertificate.fromAcmCertificate({
certificateArn: certificateArn,
env: {
region: Aws.REGION,
account: Aws.ACCOUNT_ID,
},
node: stack.node,
stack,
metricDaysToExpiry: () => new Metric({
namespace: 'TLS Viewer Certificate Validity',
metricName: 'TLS Viewer Certificate Expired',
}),
}, {
sslMethod: SSLMethod.SNI,
securityPolicy: SecurityPolicyProtocol.TLS_V1_2_2021,
aliases: [props.domainName],
});
const rewriteFunction = new Function(stack, 'rewrite-function', {
functionName: 'origin-rewrite',
comment: 'Rewrites Microservice paths for origin',
code: FunctionCode.fromFile({
filePath: './functions/rewrite.js',
}),
});
// Create the CloudFront Ingress.
const distribution = new CloudFrontWebDistribution(stack, 'ingress-distribution', {
comment: 'Ingress',
viewerCertificate,
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
priceClass: PriceClass.PRICE_CLASS_ALL,
defaultRootObject: 'index.html',
originConfigs: [{
/**
* GraphQL
*/
customOriginSource: {
domainName: graphql.url,
originProtocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
},
behaviors: [{
pathPattern: 'graphql',
defaultTtl: Duration.seconds(0),
minTtl: Duration.seconds(0),
maxTtl: Duration.seconds(0),
compress: true,
allowedMethods: CloudFrontAllowedMethods.GET_HEAD,
forwardedValues: {
queryString: true,
cookies: { forward: 'all' },
},
functionAssociations: [{
function: rewriteFunction,
eventType: FunctionEventType.VIEWER_REQUEST,
}],
}],
}, {
/**
* App
*/
customOriginSource: {
domainName: app.staticSite.bucket.bucketWebsiteDomainName,
originProtocolPolicy: OriginProtocolPolicy.HTTP_ONLY,
},
behaviors: [{
pathPattern: 'app/*',
compress: true,
allowedMethods: CloudFrontAllowedMethods.GET_HEAD,
forwardedValues: {
queryString: true,
cookies: { forward: 'all' },
},
functionAssociations: [{
function: rewriteFunction,
eventType: FunctionEventType.VIEWER_REQUEST,
}],
}],
}, {
/**
* Website (Fallback)
*/
customOriginSource: {
domainName: site.staticSite.bucket.bucketWebsiteDomainName,
originProtocolPolicy: OriginProtocolPolicy.HTTP_ONLY,
},
behaviors: [{
isDefaultBehavior: true,
compress: true,
allowedMethods: CloudFrontAllowedMethods.GET_HEAD,
forwardedValues: {
queryString: true,
cookies: { forward: 'all' },
},
}],
}],
});
// Create a DNS Record for the CloudFront Ingress.
new ARecord(stack, 'ingress-record', {
recordName: props.domainName,
target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
zone,
});
return { stack, app, site, graphql };
}
【问题讨论】: