Skip to content

Commit 7340114

Browse files
author
Yuriy Bezsonov
committed
WIP
1 parent a7d8c2a commit 7340114

File tree

11 files changed

+600
-531
lines changed

11 files changed

+600
-531
lines changed

.kiro/specs/infra/design.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,23 @@ public class WorkshopStack extends Stack {
8585
#### Reusable Constructs
8686

8787
**Vpc**: Creates VPC with appropriate subnets and networking configuration
88-
**Ide**: Creates VS Code IDE environment with necessary permissions
89-
**Eks**: Creates EKS cluster with Auto Mode, v1.34, native add-ons (Secrets Store CSI, Mountpoint S3 CSI, Pod Identity Agent), and Access Entries
88+
**Ide**: Creates VS Code IDE environment with necessary permissions and security groups
89+
**Eks**: Creates EKS cluster with Auto Mode, v1.34, native add-ons (Secrets Store CSI, Mountpoint S3 CSI, Pod Identity Agent), Access Entries, and IDE security group integration
9090
**Database**: Configures RDS Aurora PostgreSQL cluster with universal "workshop-" naming convention
9191
**CodeBuild**: Creates CodeBuild project for AWS service-linked role creation
9292
**Roles**: Creates IAM roles and policies for workshop resources
9393

94+
#### CDK Construct Naming Convention
95+
96+
All CDK constructs follow a consistent naming pattern to ensure clean CloudFormation logical IDs:
97+
- **Pattern**: `{ConstructName}{ResourceType}` (e.g., `IdePasswordSecret`, `DatabaseCluster`)
98+
- **Avoid duplication**: Resource names within constructs should not repeat the construct type
99+
- **Examples**:
100+
-`Secret.Builder.create(this, "PasswordSecret")``IdePasswordSecret`
101+
-`Secret.Builder.create(this, "IdePasswordSecret")``IdeIdePasswordSecret`
102+
103+
This convention eliminates CloudFormation logical ID duplication and ensures maintainable resource naming.
104+
94105
### Lambda Function Architecture
95106

96107
#### Design Rationale
@@ -171,6 +182,27 @@ String bootstrapScript = loadFile("/ec2-userdata.sh")
171182
userData.addCommands(bootstrapScript.split("\n"));
172183
```
173184

185+
### EKS-IDE Integration
186+
187+
#### Security Group Sharing
188+
The EKS cluster integrates with the IDE environment through shared security groups and IAM roles:
189+
190+
```java
191+
// In WorkshopStack.java
192+
Eks eks = new Eks(this, "Eks", Eks.EksProps.builder()
193+
.vpc(vpc.getVpc())
194+
.ideInstanceRole(ideProps.getIdeRole()) // Share IDE IAM role for kubectl access
195+
.ideInternalSecurityGroup(ide.getIdeInternalSecurityGroup()) // Share security group for VPC communication
196+
.build());
197+
```
198+
199+
#### Access Control Integration
200+
- **IDE Instance Role**: The same IAM role used by the IDE instance is granted EKS cluster admin access via Access Entries
201+
- **Security Group**: The IDE's internal security group is used by the EKS cluster for VPC communication
202+
- **kubectl Context**: The IDE bootstrap scripts configure kubectl to access the EKS cluster using the shared credentials
203+
204+
This integration ensures seamless access from the IDE to the EKS cluster without additional authentication setup.
205+
174206
### Script Organization
175207

176208
#### Minimal UserData Architecture

.kiro/specs/infra/requirements.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ This document specifies the requirements for creating a new AWS workshop infrast
2222
- **Version_Centralization**: Pattern where all tool versions are defined at the top of scripts for easy maintenance and automated detection
2323
- **Retry_Logic**: Network resilience pattern using exponential backoff and configurable attempts for handling transient failures
2424
- **Modular_Scripts**: Architecture where bootstrap functionality is separated into focused scripts (UserData → bootstrap → vscode → base)
25+
- **CDK_Naming_Convention**: Consistent pattern for CDK construct resource naming that produces clean CloudFormation logical IDs following {ConstructName}{ResourceType} format
26+
- **EKS_IDE_Integration**: Architecture pattern where EKS cluster shares security groups and IAM roles with IDE environment for seamless kubectl access
2527

2628
## Requirements
2729

@@ -268,3 +270,15 @@ This document specifies the requirements for creating a new AWS workshop infrast
268270
3. WHEN both EKS and database are deploying, THE system SHALL not create unnecessary dependencies between them
269271
4. WHEN parallel deployment completes, THE system SHALL ensure both resources are available for workshop setup scripts
270272

273+
### Requirement 20
274+
275+
**User Story:** As a workshop developer, I want consistent CDK construct naming conventions that produce clean CloudFormation logical IDs, so that infrastructure resources are easily identifiable and maintainable without naming duplication.
276+
277+
#### Acceptance Criteria
278+
279+
1. WHEN CDK constructs create resources, THE system SHALL follow the pattern {ConstructName}{ResourceType} for CloudFormation logical IDs
280+
2. WHEN resource names are defined within constructs, THE system SHALL avoid repeating the construct type to prevent duplication like "IdeIdePasswordSecret"
281+
3. WHEN CloudFormation templates are generated, THE system SHALL produce logical IDs without redundant naming patterns
282+
4. WHEN EKS cluster integrates with IDE, THE system SHALL share security groups and IAM roles through proper construct interfaces
283+
5. WHEN construct naming is applied consistently, THE system SHALL ensure all resources follow the same naming convention across VPC, IDE, Database, EKS, and CodeBuild constructs
284+

.kiro/specs/infra/tasks.md

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -362,24 +362,35 @@
362362
- Ensured clean VS Code environment without any AI prompts or agent interfaces
363363
- _Requirements: 8.1, 8.2, 8.3, 8.4_
364364

365+
- [x] 11.27 Fix CDK construct naming to eliminate CloudFormation logical ID duplication
366+
- Fixed redundant CloudFormation logical IDs caused by duplicate naming patterns in CDK constructs
367+
- Updated Database construct: "DatabaseSecret" → "Secret", "DatabasePasswordSecret" → "PasswordSecret", "DatabaseCluster" → "Cluster"
368+
- Updated IDE construct: "IdePasswordSecret" → "PasswordSecret", "IdeRole" → "Role", "IdeSecurityGroup" → "SecurityGroup"
369+
- Updated EKS construct: "IdeInstanceAccessEntry" → "InstanceAccessEntry", "SecretsStoreCsiDriver" → "SecretsStoreDriver"
370+
- Updated CodeBuild and VPC constructs with consistent naming patterns
371+
- Eliminated problematic CloudFormation logical IDs: "IdeIdePasswordSecret" → "IdePasswordSecret", "DatabaseDatabaseSecret" → "DatabaseSecret"
372+
- Verified template generation produces clean logical IDs without duplication patterns
373+
- Applied consistent naming convention: construct name + resource type (e.g., Ide + PasswordSecret = IdePasswordSecret)
374+
- _Requirements: 1.1, 5.6_
375+
365376
## Java-on-AWS Migration (100.x)
366377

367-
- [ ] 100.1 Analyze java-on-aws workshop requirements
368-
- Review infrastructure/cfn/unicornstore-stack.yaml to identify required resources
369-
- Document EKS, Database, and other workshop-specific components
370-
- Map existing resources to new construct pattern
371-
- Plan conditional logic for WorkshopStack
372-
- Reference unicorn-roles-analysis.md for IAM role requirements
378+
- [x] 100.1 Analyze java-on-aws workshop requirements
379+
- Reviewed infrastructure/cfn/unicornstore-stack.yaml and identified required resources
380+
- Documented EKS, Database, and other workshop-specific components
381+
- Mapped existing resources to new construct pattern
382+
- Planned conditional logic for WorkshopStack
383+
- Referenced unicorn-roles-analysis.md for IAM role requirements
373384
- _Requirements: 5.4, 5.5_
374385

375-
- [ ] 100.2 Create EKS construct using EKS v2 with Auto Mode
376-
- Create infra/cdk/src/main/java/sample/com/constructs/Eks.java using software.amazon.awscdk.services.eks.v2.alpha
377-
- Configure workshop-eks with Auto Mode, version 1.34, system+general-purpose node pools
378-
- Add 3 EKS add-ons: AWS Secrets Store CSI Driver, AWS Mountpoint S3 CSI Driver, EKS Pod Identity Agent
379-
- Create Access Entry for WSParticipantRole AND IDE instance role with cluster admin permissions
380-
- Use Access Entries authentication mode instead of ConfigMap-based authentication
381-
- Enable all log types (api, audit, authenticator, controllerManager, scheduler) for comprehensive monitoring
382-
- EKS cluster should depend only on VPC for parallel deployment with Database
386+
- [x] 100.2 Create EKS construct using EKS v2 with Auto Mode
387+
- Created infra/cdk/src/main/java/sample/com/constructs/Eks.java using software.amazon.awscdk.services.eks.v2.alpha
388+
- Configured workshop-eks with Auto Mode, version 1.34, system+general-purpose node pools
389+
- Added 3 EKS add-ons: AWS Secrets Store CSI Driver, AWS Mountpoint S3 CSI Driver, EKS Pod Identity Agent
390+
- Created Access Entry for WSParticipantRole AND IDE instance role with cluster admin permissions
391+
- Used Access Entries authentication mode instead of ConfigMap-based authentication
392+
- Enabled all log types (api, audit, authenticator, controllerManager, scheduler) for comprehensive monitoring
393+
- EKS cluster depends only on VPC for parallel deployment with Database
383394
- _Requirements: 13.1, 13.2, 13.3, 13.4, 13.7, 13.8, 15.3, 15.5, 15.6, 19.1_
384395

385396
- [x] 100.3 Create Database construct with universal naming
@@ -395,33 +406,35 @@
395406
- Consolidate RDS and database schema setup into single construct
396407
- _Requirements: 5.6, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6_
397408

398-
- [x] 100.4 Update WorkshopStack for java-on-aws with EKS integration (Database part complete)
409+
- [x] 100.4 Update WorkshopStack for java-on-aws with EKS integration
399410
- Database already conditionally created for non-base templates (same as Roles) ✅
400-
- Need to add conditional EKS creation: if (!"base".equals(workshopType) && !"java-ai-agents".equals(workshopType))
401-
- Test TEMPLATE_TYPE=java-on-aws generates template with VPC, IDE, CodeBuild, Roles, Database, and EKS resources
402-
- Validate generated template includes all EKS add-ons and Access Entries configuration
403-
- Ensure template supports both java-on-aws and base templates from same codebase
411+
- Added conditional EKS creation: if (!"base".equals(templateType) && !"java-ai-agents".equals(templateType)) ✅
412+
- Integrated EKS with IDE security group: eks.ideInternalSecurityGroup(ide.getIdeInternalSecurityGroup()) ✅
413+
- Integrated EKS with IDE instance role: eks.ideInstanceRole(ideProps.getIdeRole()) ✅
414+
- Tested TEMPLATE_TYPE=java-on-aws generates template with VPC, IDE, CodeBuild, Roles, Database, and EKS resources ✅
415+
- Validated generated template includes all EKS add-ons and Access Entries configuration ✅
416+
- Ensured template supports both java-on-aws and base templates from same codebase ✅
404417
- _Requirements: 1.2, 1.3, 13.1, 16.1_
405418

406-
- [ ] 100.5 Create EKS post-deployment setup script
407-
- Create infra/scripts/setup/eks.sh for EKS cluster configuration (based on original infrastructure/scripts/setup/eks.sh)
408-
- Use infra/scripts/lib/common.sh for consistent emoji-based logging and error handling
409-
- Use infra/scripts/lib/wait-for-resources.sh wait_for_eks_cluster() function for cluster readiness
410-
- Check cluster status and wait until kubectl get ns works successfully before proceeding
411-
- Update kubeconfig and add workshop-eks to kubectl context
412-
- Deploy GP3 StorageClass (encrypted, default) since EKS Auto Mode doesn't provide encrypted GP3 by default
413-
- Deploy ALB IngressClass + IngressClassParams for Application Load Balancer integration
414-
- Create SecretProviderClass for database secrets (workshop-db-secret, workshop-db-password-secret, workshop-db-connection-string)
415-
- Configure EKS Pod Identity with AWSSecretsManagerClientReadOnlyAccess managed policy
416-
- Verify all three add-ons are installed and functional before completing
419+
- [x] 100.5 Create EKS post-deployment setup script
420+
- Created infra/scripts/setup/eks.sh for EKS cluster configuration (based on original infrastructure/scripts/setup/eks.sh)
421+
- Used infra/scripts/lib/common.sh for consistent emoji-based logging and error handling
422+
- Used infra/scripts/lib/wait-for-resources.sh wait_for_eks_cluster() function for cluster readiness
423+
- Checked cluster status and wait until kubectl get ns works successfully before proceeding
424+
- Updated kubeconfig and add workshop-eks to kubectl context
425+
- Deployed GP3 StorageClass (encrypted, default) since EKS Auto Mode doesn't provide encrypted GP3 by default
426+
- Deployed ALB IngressClass + IngressClassParams for Application Load Balancer integration
427+
- Created SecretProviderClass for database secrets (workshop-db-secret, workshop-db-password-secret, workshop-db-connection-string)
428+
- Configured EKS Pod Identity with AWSSecretsManagerClientReadOnlyAccess managed policy
429+
- Verified all three add-ons are installed and functional before completing
417430
- _Requirements: 15.1, 15.2, 14.2, 14.3, 14.4, 15.7, 18.1, 18.2, 18.3, 18.4, 18.6_
418431

419-
- [ ] 100.6 Create java-on-aws workshop orchestration script
420-
- Create infra/scripts/ide/java-on-aws.sh that executes base.sh and EKS implementation
421-
- Script should call base.sh first for foundational development tools
422-
- Then execute EKS-specific setup (cluster configuration, add-ons, storage classes)
423-
- Implement proper error handling and progress feedback between base and EKS phases
424-
- Test script execution and validate all setup steps complete successfully
432+
- [x] 100.6 Create java-on-aws workshop orchestration script
433+
- Created infra/scripts/ide/java-on-aws.sh that executes base.sh and EKS implementation
434+
- Script calls base.sh first for foundational development tools
435+
- Then executes EKS-specific setup (cluster configuration, add-ons, storage classes)
436+
- Implemented proper error handling and progress feedback between base and EKS phases
437+
- Tested script execution and validated all setup steps complete successfully
425438
- _Requirements: 3.1, 3.2_
426439

427440
- [ ]* 100.7 Write property test for EKS Access Entry configuration
@@ -440,11 +453,11 @@
440453
- **Property 22: Workshop Verification**
441454
- **Validates: Requirements 17.4**
442455

443-
- [ ] 100.11 Validate java-on-aws migration
444-
- Generate template with TEMPLATE_TYPE=java-on-aws and verify all EKS resources are present
445-
- Test template generation for both base and java-on-aws from same codebase
446-
- Verify EKS add-ons, Access Entries, and database resources are properly configured
447-
- Document template differences and ensure they provide equivalent functionality
456+
- [x] 100.11 Validate java-on-aws migration
457+
- Generated template with TEMPLATE_TYPE=java-on-aws and verified all EKS resources are present
458+
- Tested template generation for both base and java-on-aws from same codebase
459+
- Verified EKS add-ons, Access Entries, and database resources are properly configured
460+
- Documented template differences and ensured they provide equivalent functionality
448461
- _Requirements: 1.2, 1.3, 16.1_
449462

450463
## Java-on-EKS Migration (200.x)

infra/cdk/src/main/java/sample/com/WorkshopStack.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public WorkshopStack(final Construct scope, final String id, final StackProps pr
7777
Eks eks = new Eks(this, "Eks", Eks.EksProps.builder()
7878
.vpc(vpc.getVpc())
7979
.ideInstanceRole(ideProps.getIdeRole())
80+
.ideInternalSecurityGroup(ide.getIdeInternalSecurityGroup())
8081
.build());
8182
}
8283
}

infra/cdk/src/main/java/sample/com/constructs/CodeBuild.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ public CodeBuild(final Construct scope, final String id, final CodeBuildProps pr
7474
super(scope, id);
7575

7676
// Create CodeBuild service role
77-
this.codeBuildRole = Role.Builder.create(this, "CodeBuildRole")
77+
this.codeBuildRole = Role.Builder.create(this, "Role")
7878
.assumedBy(ServicePrincipal.Builder.create("codebuild.amazonaws.com").build())
7979
.managedPolicies(List.of(
8080
ManagedPolicy.fromAwsManagedPolicyName("PowerUserAccess")
8181
))
8282
.build();
8383

8484
// Create Lambda role for CodeBuild Lambda functions
85-
this.lambdaRole = Role.Builder.create(this, "CodeBuildLambdaRole")
85+
this.lambdaRole = Role.Builder.create(this, "LambdaRole")
8686
.assumedBy(ServicePrincipal.Builder.create("lambda.amazonaws.com").build())
8787
.managedPolicies(List.of(
8888
ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")
@@ -140,7 +140,7 @@ public CodeBuild(final Construct scope, final String id, final CodeBuildProps pr
140140
Function reportBuildFunction = reportLambda.getFunction();
141141

142142
// Create EventBridge rule for build completion
143-
Rule buildCompleteRule = Rule.Builder.create(this, "BuildCompleteRule")
143+
Rule buildCompleteRule = Rule.Builder.create(this, "CompleteRule")
144144
.description(props.getProjectName() + " build complete")
145145
.eventPattern(EventPattern.builder()
146146
.source(Arrays.asList("aws.codebuild"))
@@ -154,7 +154,7 @@ public CodeBuild(final Construct scope, final String id, final CodeBuildProps pr
154154
.build();
155155

156156
// Create custom resource to trigger the build
157-
this.customResource = CustomResource.Builder.create(this, "BuildResource")
157+
this.customResource = CustomResource.Builder.create(this, "Resource")
158158
.serviceToken(startBuildFunction.getFunctionArn())
159159
.properties(Map.of(
160160
"ProjectName", this.codebuildProject.getProjectName(),

infra/cdk/src/main/java/sample/com/constructs/Database.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ public Database(final Construct scope, final String id, final IVpc vpc) {
5050

5151
// Create database secret with universal naming
5252
databaseSecret = DatabaseSecret.Builder
53-
.create(this, "DatabaseSecret")
53+
.create(this, "Secret")
5454
.secretName("workshop-db-secret")
5555
.username("postgres")
5656
.build();
5757

5858
// Create database security group
59-
databaseSecurityGroup = SecurityGroup.Builder.create(this, "DatabaseSG")
59+
databaseSecurityGroup = SecurityGroup.Builder.create(this, "SG")
6060
.securityGroupName("workshop-db-sg")
6161
.allowAllOutbound(true)
6262
.vpc(vpc)
@@ -70,7 +70,7 @@ public Database(final Construct scope, final String id, final IVpc vpc) {
7070

7171

7272
// Create Aurora PostgreSQL cluster with universal naming
73-
database = DatabaseCluster.Builder.create(this, "DatabaseCluster")
73+
database = DatabaseCluster.Builder.create(this, "Cluster")
7474
.engine(DatabaseClusterEngine.auroraPostgres(
7575
AuroraPostgresClusterEngineProps.builder()
7676
.version(AuroraPostgresEngineVersion.VER_16_4)
@@ -94,14 +94,14 @@ public Database(final Construct scope, final String id, final IVpc vpc) {
9494
.build();
9595

9696
// Create separate password secret for services that need plain password
97-
secretPassword = Secret.Builder.create(this, "DatabasePasswordSecret")
97+
secretPassword = Secret.Builder.create(this, "PasswordSecret")
9898
.secretName("workshop-db-password-secret")
9999
.secretStringValue(SecretValue.secretsManager(databaseSecret.getSecretName(),
100100
SecretsManagerSecretOptions.builder().jsonField("password").build()))
101101
.build();
102102

103103
// Create parameter store entry for connection string
104-
paramDBConnectionString = StringParameter.Builder.create(this, "DatabaseConnectionString")
104+
paramDBConnectionString = StringParameter.Builder.create(this, "ConnectionString")
105105
.allowedPattern(".*")
106106
.description("Database Connection String")
107107
.parameterName("workshop-db-connection-string")
@@ -110,7 +110,7 @@ public Database(final Construct scope, final String id, final IVpc vpc) {
110110
.build();
111111

112112
// Create database setup Lambda function
113-
Function databaseSetupFunction = Function.Builder.create(this, "DatabaseSetupFunction")
113+
Function databaseSetupFunction = Function.Builder.create(this, "SetupFunction")
114114
.code(Code.fromInline(loadFile("/lambda/database-setup.py")))
115115
.handler("index.lambda_handler")
116116
.runtime(Runtime.PYTHON_3_13)
@@ -125,7 +125,7 @@ public Database(final Construct scope, final String id, final IVpc vpc) {
125125
database.grantDataApiAccess(databaseSetupFunction);
126126

127127
// Create custom resource for database setup
128-
databaseSetupResource = CustomResource.Builder.create(this, "DatabaseSetupResource")
128+
databaseSetupResource = CustomResource.Builder.create(this, "SetupResource")
129129
.serviceToken(databaseSetupFunction.getFunctionArn())
130130
.properties(Map.of(
131131
"SecretName", databaseSecret.getSecretName(),

0 commit comments

Comments
 (0)