私有子网中CodeBuild连接S3遇TCP 443超时问题求助
我把CodeBuild部署在VPC的私有子网中,目的是访问子网内的RDS集群,但CodeBuild抛出以下超时错误:
CLIENT_ERROR: RequestError: send request failed caused by: Get "https://abcdatabase-schema-abcdatabaseschemap-jatjfe01aqps.s3.amazonaws.com/abcDatabase-Sc/Artifact_S/LrJBqSR.zip": dial tcp 52.217.128.121:443: i/o timeout for primary source and source version arn:aws:s3:::abcdatabase-schema-abcdatabaseschemap-jatjfe01aqps/abcDatabase-Sc/Artifact_S/LrJBqSR.zip
这是TCP 443超时错误,说明CodeBuild从S3下载构件时网络不通。我已配置S3 VPC网关终端节点,按逻辑应该能建立连接且无需NAT网关,以下是我的CDK配置代码:
VPC栈代码
private readonly coreVpc: EC2.Vpc; constructor(scope: CDK.App, id: string, props?: VpcStackStackProps) { super(scope, id, props); const vpcName: string = "CoreVpc"; // Create VPC this.coreVpc = new EC2.Vpc(this, "CoreVpc", { vpcName: vpcName, cidr: "10.0.0.0/16", enableDnsHostnames: true, enableDnsSupport: true, maxAzs: 3, // 3 availability zones // Each zone will have one public subnet and one private subnet. subnetConfiguration: [ { cidrMask: 19, name: "PublicSubnet", subnetType: EC2.SubnetType.PUBLIC, }, { cidrMask: 19, name: "PrivateSubnet", subnetType: EC2.SubnetType.PRIVATE_ISOLATED, }, ], }); // Create security group for the VPC const vpcEndpointSecurityGroup = new EC2.SecurityGroup( this, `${vpcName}-VPCEndpointSecurityGroup`, { securityGroupName: `${vpcName}-VPCEndpointSecurityGroup`, vpc: this.coreVpc, description: "Security group for granting AWS services access to the CoreVpc", allowAllOutbound: false, } ); vpcEndpointSecurityGroup.addIngressRule( EC2.Peer.ipv4(this.coreVpc.vpcCidrBlock), EC2.Port.tcp(443), "Allow HTTPS ingress traffic" ); vpcEndpointSecurityGroup.addEgressRule( EC2.Peer.ipv4(this.coreVpc.vpcCidrBlock), EC2.Port.tcp(443), "Allow HTTPS egress traffic" ); const privateSubnets = this.coreVpc.selectSubnets( { subnetType: EC2.SubnetType.PRIVATE_ISOLATED } ); // Grant AWS CodeBuild service access to the VPC's private subnets. new EC2.InterfaceVpcEndpoint( this, 'CodeBuildInterfaceVpcEndpoint', { service: EC2.InterfaceVpcEndpointAwsService.CODEBUILD, vpc: this.coreVpc, privateDnsEnabled: true, securityGroups: [vpcEndpointSecurityGroup], subnets: privateSubnets } ); // Grant VPC access to S3 service. new EC2.GatewayVpcEndpoint( this, 'S3InterfaceVpcEndpoint', { service: EC2.GatewayVpcEndpointAwsService.S3, vpc: this.coreVpc, } ); } }
CodeBuild栈代码
export class CodeBuildStack extends CDK.Stack { constructor(scope: Construct, id: string, props: CodeBuildStackProps) { super(scope, id, props); const buildspecFile = FS.readFileSync("./config/buildspec.yml", "utf-8"); const buildspecFileYaml = YAML.parse(buildspecFile, { prettyErrors: true, }); // Grant write permissions to the DeploymentRole to the artifact S3 bucket. const deploymentRoleArn: string = `arn:aws:iam::${props.env?.account}:role/${props.pipelineName}-DeploymentRole`; const deploymentRole = IAM.Role.fromRoleArn( this, `CodeBuild${props.pipelineStageInfo.stageName}DeploymentRoleConstructID`, deploymentRoleArn, { mutable: false, // Causes CDK to update the resource policy where required, instead of the Role addGrantsToResources: true, } ); const coreVpc: EC2.IVpc = EC2.Vpc.fromLookup( this, `${props.pipelineStageInfo.stageName}VpcLookupId`, { vpcName: "CoreVpc", } ); const securityGroupForVpc: EC2.ISecurityGroup = EC2.SecurityGroup.fromLookupByName( this, "SecurityGroupLookupForVpcEndpoint", "CoreVpc-VPCEndpointSecurityGroup", coreVpc ); new CodeBuild.Project( this, `${props.pipelineName}-${props.pipelineStageInfo.stageName}-ColdBuild`, { projectName: `${props.pipelineName}-${props.pipelineStageInfo.stageName}-ColdBuild`, environment: { buildImage: CodeBuild.LinuxBuildImage.STANDARD_5_0, }, buildSpec: CodeBuild.BuildSpec.fromObjectToYaml(buildspecFileYaml), vpc: coreVpc, securityGroups: [securityGroupForVpc], role: deploymentRole, } ); } }
1. S3网关终端节点路由表关联缺失
S3网关终端节点需要关联私有子网的路由表,否则私有子网内的流量不会走终端节点访问S3。你的代码创建S3网关终端节点时未指定routeTables参数,CDK默认只会将终端节点关联到公有子网的路由表,私有子网路由表没有添加指向S3网关的路由,导致CodeBuild流量尝试走公网(私有子网无NAT网关,因此超时)。
解决方法:创建S3网关终端节点时,明确关联私有子网的路由表:
new EC2.GatewayVpcEndpoint( this, 'S3GatewayVpcEndpoint', { service: EC2.GatewayVpcEndpointAwsService.S3, vpc: this.coreVpc, routeTables: this.coreVpc.selectSubnets({subnetType: EC2.SubnetType.PRIVATE_ISOLATED}).routeTables } );
2. CodeBuild安全组出站规则限制
你给CodeBuild使用的CoreVpc-VPCEndpointSecurityGroup安全组,出站规则仅允许访问VPC CIDR的443端口。虽然S3网关终端节点的流量在VPC内流转,但安全组需要允许HTTPS流量到S3服务范围。
解决方法:修改安全组出站规则,允许HTTPS(443)出站到任意地址(路由会自动将S3流量导向网关):
vpcEndpointSecurityGroup.addEgressRule( EC2.Peer.anyIpv4(), EC2.Port.tcp(443), "Allow HTTPS egress to S3 and other AWS services" );
3. S3存储桶访问策略限制
检查S3存储桶的桶策略,确保允许CodeBuild角色访问该桶,并且允许通过VPC终端节点访问。可添加条件限制仅允许VPC内访问:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:role/CODEBUILD_ROLE_ARN" }, "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:::abcdatabase-schema-abcdatabaseschemap-jatjfe01aqps", "arn:aws:s3:::abcdatabase-schema-abcdatabaseschemap-jatjfe01aqps/*" ], "Condition": { "StringEquals": { "aws:sourceVpc": "VPC_ID" } } } ] }
4. 确认私有子网DNS配置
虽然你已开启enableDnsHostnames和enableDnsSupport,需确保私有子网的DNS服务器为VPC默认DNS(VPC CIDR+2),这样S3域名才能正确解析到VPC终端节点地址,而非公网IP。
内容的提问来源于stack exchange,提问作者Yang Liu

