|
2 | 2 |
|
3 | 3 | import software.amazon.awscdk.Duration; |
4 | 4 | import software.amazon.awscdk.RemovalPolicy; |
5 | | -import software.amazon.awscdk.services.apigateway.*; |
6 | 5 | import software.amazon.awscdk.services.ec2.*; |
7 | 6 | import software.amazon.awscdk.services.eks.v2.alpha.AccessEntry; |
8 | 7 | import software.amazon.awscdk.services.eks.v2.alpha.AccessEntryType; |
|
14 | 13 | import software.amazon.awscdk.services.iam.*; |
15 | 14 | import software.amazon.awscdk.services.lambda.Code; |
16 | 15 | import software.amazon.awscdk.services.lambda.Function; |
| 16 | +import software.amazon.awscdk.services.lambda.FunctionUrl; |
| 17 | +import software.amazon.awscdk.services.lambda.FunctionUrlAuthType; |
| 18 | +import software.amazon.awscdk.services.lambda.FunctionUrlOptions; |
17 | 19 | import software.amazon.awscdk.services.lambda.Runtime; |
18 | 20 | import software.amazon.awscdk.services.logs.LogGroup; |
19 | 21 | import software.amazon.awscdk.services.logs.RetentionDays; |
|
28 | 30 |
|
29 | 31 | /** |
30 | 32 | * ThreadAnalysis construct for thread dump analysis. |
31 | | - * Creates Lambda function and API Gateway for thread dump collection and AI analysis. |
| 33 | + * Creates Lambda function with Function URL for thread dump collection and AI analysis. |
| 34 | + * Uses async self-invocation pattern for fast webhook response. |
32 | 35 | */ |
33 | 36 | public class ThreadAnalysis extends Construct { |
34 | 37 |
|
35 | 38 | private final SecurityGroup lambdaSecurityGroup; |
36 | 39 | private final Function threadDumpLambda; |
37 | | - private final RestApi threadDumpApi; |
| 40 | + private final FunctionUrl functionUrl; |
38 | 41 | private final Role lambdaRole; |
39 | 42 |
|
40 | 43 | public static class ThreadAnalysisProps { |
@@ -130,21 +133,14 @@ public ThreadAnalysis(final Construct scope, final String id, final ThreadAnalys |
130 | 133 | props.getWorkshopBucket().grantReadWrite(lambdaRole); |
131 | 134 | } |
132 | 135 |
|
133 | | - // Create Lambda security group |
| 136 | + // Create Lambda security group for EKS and ECS access |
134 | 137 | this.lambdaSecurityGroup = SecurityGroup.Builder.create(this, "SecurityGroup") |
135 | 138 | .vpc(props.getVpc()) |
136 | 139 | .securityGroupName(prefix + "-thread-dump-lambda-sg") |
137 | 140 | .description("Security group for Thread Dump Lambda function") |
138 | 141 | .allowAllOutbound(true) |
139 | 142 | .build(); |
140 | 143 |
|
141 | | - // Allow inbound from VPC for HTTPS |
142 | | - lambdaSecurityGroup.addIngressRule( |
143 | | - Peer.ipv4(props.getVpc().getVpcCidrBlock()), |
144 | | - Port.tcp(443), |
145 | | - "Allow VPC traffic to Lambda" |
146 | | - ); |
147 | | - |
148 | 144 | // Create CloudWatch Log Group |
149 | 145 | LogGroup.Builder.create(this, "LogGroup") |
150 | 146 | .logGroupName("/aws/lambda/" + prefix + "-thread-dump-lambda") |
@@ -173,56 +169,22 @@ public ThreadAnalysis(final Construct scope, final String id, final ThreadAnalys |
173 | 169 | "S3_BUCKET_NAME", bucketName, |
174 | 170 | "EKS_CLUSTER_NAME", eksClusterName, |
175 | 171 | "S3_THREAD_DUMPS_PREFIX", "thread-dumps/", |
176 | | - "APP_LABEL", "unicorn-store-spring", |
177 | | - "KUBERNETES_AUTH_TYPE", "aws", |
178 | | - "K8S_NAMESPACE", "unicorn-store-spring", |
179 | 172 | "SECRET_NAME", prefix + "-ide-password" |
180 | 173 | )) |
181 | 174 | .build(); |
182 | 175 |
|
183 | | - // Create VPC Endpoint for API Gateway |
184 | | - InterfaceVpcEndpoint apiGatewayEndpoint = InterfaceVpcEndpoint.Builder.create(this, "ApiGatewayVpcEndpoint") |
185 | | - .vpc(props.getVpc()) |
186 | | - .service(InterfaceVpcEndpointAwsService.APIGATEWAY) |
187 | | - .subnets(SubnetSelection.builder() |
188 | | - .subnetType(SubnetType.PRIVATE_WITH_EGRESS) |
189 | | - .build()) |
190 | | - .securityGroups(List.of(lambdaSecurityGroup)) |
191 | | - .privateDnsEnabled(true) |
192 | | - .build(); |
193 | | - |
194 | | - // Create Private REST API Gateway |
195 | | - this.threadDumpApi = RestApi.Builder.create(this, "Api") |
196 | | - .restApiName(prefix + "-thread-dump-api") |
197 | | - .endpointConfiguration(EndpointConfiguration.builder() |
198 | | - .types(List.of(EndpointType.PRIVATE)) |
199 | | - .vpcEndpoints(List.of(apiGatewayEndpoint)) |
200 | | - .build()) |
201 | | - .policy(PolicyDocument.Builder.create() |
202 | | - .statements(List.of( |
203 | | - PolicyStatement.Builder.create() |
204 | | - .effect(Effect.ALLOW) |
205 | | - .principals(List.of(new AnyPrincipal())) |
206 | | - .actions(List.of("execute-api:Invoke")) |
207 | | - .resources(List.of("*")) |
208 | | - .conditions(Map.of( |
209 | | - "StringEquals", Map.of( |
210 | | - "aws:SourceVpce", apiGatewayEndpoint.getVpcEndpointId() |
211 | | - ) |
212 | | - )) |
213 | | - .build() |
214 | | - )) |
215 | | - .build()) |
216 | | - .build(); |
217 | | - |
218 | | - // Remove auto-generated endpoint output |
219 | | - threadDumpApi.getNode().tryRemoveChild("Endpoint"); |
220 | | - |
221 | | - // Add POST method to root |
222 | | - LambdaIntegration lambdaIntegration = LambdaIntegration.Builder.create(threadDumpLambda) |
223 | | - .build(); |
| 176 | + // Add permission for Lambda to invoke itself (async pattern) |
| 177 | + threadDumpLambda.addToRolePolicy(PolicyStatement.Builder.create() |
| 178 | + .effect(Effect.ALLOW) |
| 179 | + .actions(List.of("lambda:InvokeFunction")) |
| 180 | + .resources(List.of(threadDumpLambda.getFunctionArn())) |
| 181 | + .build()); |
224 | 182 |
|
225 | | - threadDumpApi.getRoot().addMethod("POST", lambdaIntegration); |
| 183 | + // Create Function URL (replaces API Gateway + VPC Endpoint) |
| 184 | + // Auth is handled by Lambda code via basic auth against Secrets Manager |
| 185 | + this.functionUrl = threadDumpLambda.addFunctionUrl(FunctionUrlOptions.builder() |
| 186 | + .authType(FunctionUrlAuthType.NONE) |
| 187 | + .build()); |
226 | 188 |
|
227 | 189 | // Create EKS Access Entry for Lambda role (if EKS cluster provided) |
228 | 190 | if (props.getEksCluster() != null) { |
@@ -292,8 +254,8 @@ public Function getThreadDumpLambda() { |
292 | 254 | return threadDumpLambda; |
293 | 255 | } |
294 | 256 |
|
295 | | - public RestApi getThreadDumpApi() { |
296 | | - return threadDumpApi; |
| 257 | + public FunctionUrl getFunctionUrl() { |
| 258 | + return functionUrl; |
297 | 259 | } |
298 | 260 |
|
299 | 261 | public Role getLambdaRole() { |
|
0 commit comments