npm package: @infraless-cdk-constructs/aurora-cluster
Description: AWS CDK L3 construct for Aurora RDS clusters with production-ready defaults
Latest version: 1.0.2

# Aurora Cluster CDK Construct

An AWS CDK L3 construct for creating production-ready Aurora RDS clusters with sensible defaults and comprehensive configuration options.

## Features

- ✅ **Dual Engine Support**: Both Aurora PostgreSQL and MySQL
- ✅ **Automatic VPC Integration**: Smart subnet selection and security group management
- ✅ **Secure by Default**: KMS encryption, Secrets Manager integration, deletion protection
- ✅ **High Availability**: Multi-AZ with configurable reader instances
- ✅ **Snapshot Restoration**: Create clusters from existing snapshots
- ✅ **IAM Authentication**: Built-in support for IAM database authentication
- ✅ **SSM Parameter Store**: Automatic export of cluster outputs for cross-stack references
- ✅ **CloudWatch Integration**: Optional log exports with configurable retention
- ✅ **Performance Insights**: Optional performance monitoring
- ✅ **Extensible**: Override any resource creation via protected hook methods
- ✅ **Production-Ready Defaults**: 30-day backups, encryption enabled, secure passwords

## Installation

```bash
npm install @cdk-constructs/aurora-cluster
```

Or with yarn:

```bash
yarn add @cdk-constructs/aurora-cluster
```

## Basic Usage

### PostgreSQL Cluster

```typescript
import { AuroraCluster } from '@cdk-constructs/aurora-cluster';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

const cluster = new AuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'production-postgres-cluster'
});

// Access cluster properties
console.log('Cluster ID:', cluster.clusterIdentifier);
console.log('Endpoint:', cluster.clusterEndpoint.hostname);
console.log('Secret ARN:', cluster.secret.secretArn);
```

### MySQL Cluster

```typescript
const mysqlCluster = new AuroraCluster(this, 'MysqlDatabase', {
  vpc: myVpc,
  engineVersion: rds.AuroraMysqlEngineVersion.VER_3_03_0,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'production-mysql-cluster'
});
```

## Advanced Examples

### High Availability with Multiple Readers

```typescript
const haCluster = new AuroraCluster(this, 'HADatabase', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'ha-cluster',
  instanceCount: 3, // 1 writer + 2 readers
  instanceClass: 'MEMORY4',
  instanceSize: 'LARGE'
});
```

### Snapshot Restoration

```typescript
const restoredCluster = new AuroraCluster(this, 'RestoredDatabase', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'restored',
  username: 'admin',
  clusterName: 'restored-from-snapshot',
  snapshotId: 'rds:my-cluster-2024-01-15-final-snapshot'
});
```

### Custom Security Groups

```typescript
const customSg = new ec2.SecurityGroup(this, 'CustomSG', {
  vpc: myVpc,
  description: 'Custom security group for database'
});

customSg.addIngressRule(
  ec2.Peer.ipv4('10.0.0.0/16'),
  ec2.Port.tcp(5432),
  'Allow from application subnets'
);

const cluster = new AuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'custom-sg-cluster',
  securityGroups: [customSg]
});
```

### CloudWatch Logs Integration

```typescript
import { Duration } from 'aws-cdk-lib';
import * as logs from 'aws-cdk-lib/aws-logs';

// PostgreSQL with logs
const pgCluster = new AuroraCluster(this, 'PostgresDB', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'postgres-with-logs',
  cloudwatchLogsExports: ['postgresql'],
  cloudwatchLogsRetention: logs.RetentionDays.ONE_MONTH
});

// MySQL with logs
const mysqlCluster = new AuroraCluster(this, 'MysqlDB', {
  vpc: myVpc,
  engineVersion: rds.AuroraMysqlEngineVersion.VER_3_03_0,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'mysql-with-logs',
  cloudwatchLogsExports: ['error', 'general', 'slowquery'],
  cloudwatchLogsRetention: logs.RetentionDays.TWO_WEEKS
});
```

### IAM Database Authentication

```typescript
import * as iam from 'aws-cdk-lib/aws-iam';

const cluster = new AuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'iam-auth-cluster'
});

// Grant a Lambda function permission to connect as 'app_user'
const lambdaRole = iam.Role.fromRoleArn(
  this,
  'LambdaRole',
  'arn:aws:iam::123456789012:role/my-lambda-role'
);

cluster.grantConnect(lambdaRole, 'app_user');

// Don't forget to create the database user with rds_iam role:
// CREATE USER app_user;
// GRANT rds_iam TO app_user;
```

### SSM Parameter Store Integration

The construct automatically stores cluster connection details in AWS Systems Manager Parameter Store for easy cross-stack references and external access without CloudFormation exports.

#### Default Behavior (Enabled)

By default, the construct creates four SSM parameters:

```typescript
const cluster = new AuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'production-cluster'
  // SSM parameters automatically created at:
  // /cdk/Database/cluster-identifier
  // /cdk/Database/endpoint-hostname
  // /cdk/Database/endpoint-port
  // /cdk/Database/secret-arn
});
```

#### Parameters Created

| Parameter Name | Value | Description |
|----------------|-------|-------------|
| `${prefix}/cluster-identifier` | Cluster ID | RDS Aurora cluster identifier |
| `${prefix}/endpoint-hostname` | Hostname | Cluster endpoint hostname |
| `${prefix}/endpoint-port` | Port | Cluster endpoint port (5432 or 3306) |
| `${prefix}/secret-arn` | ARN | Secrets Manager secret ARN |

#### Custom Prefix

Organize parameters with a custom prefix:

```typescript
const cluster = new AuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'production-cluster',
  ssmParameterPrefix: '/myorg/databases/production'
  // Parameters created at:
  // /myorg/databases/production/cluster-identifier
  // /myorg/databases/production/endpoint-hostname
  // /myorg/databases/production/endpoint-port
  // /myorg/databases/production/secret-arn
});
```

#### Disable SSM Parameters

For development environments or when parameters aren't needed:

```typescript
const devCluster = new AuroraCluster(this, 'DevDatabase', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'dev',
  username: 'admin',
  clusterName: 'dev-cluster',
  enableSsmParameters: false // No SSM parameters created
});
```

#### Retrieving Parameters

Access parameters from other CDK stacks:

```typescript
import * as ssm from 'aws-cdk-lib/aws-ssm';

// In a different stack
const clusterEndpoint = ssm.StringParameter.valueForStringParameter(
  this,
  '/cdk/Database/endpoint-hostname'
);

const secretArn = ssm.StringParameter.valueForStringParameter(
  this,
  '/cdk/Database/secret-arn'
);

// Use in Lambda environment variables
new lambda.Function(this, 'MyFunction', {
  environment: {
    DB_HOST: clusterEndpoint,
    DB_SECRET_ARN: secretArn
  }
});
```

Using AWS CLI:

```bash
# Get cluster endpoint
aws ssm get-parameter --name "/cdk/Database/endpoint-hostname" --query "Parameter.Value" --output text

# Get all cluster parameters
aws ssm get-parameters-by-path --path "/cdk/Database" --recursive

# Get secret ARN for credentials retrieval
aws ssm get-parameter --name "/cdk/Database/secret-arn" --query "Parameter.Value" --output text
```

#### Parameter Tags

All SSM parameters are tagged for management:

- `ManagedBy`: `CDK`
- `ConstructType`: `AuroraCluster`
- `ConstructId`: The construct's node ID

### Performance Insights and Custom Parameters

```typescript
const optimizedCluster = new AuroraCluster(this, 'OptimizedDB', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'optimized-cluster',
  enablePerformanceInsights: true,
  parameters: {
    'max_connections': '200',
    'shared_buffers': '256MB',
    'effective_cache_size': '1GB'
  }
});
```

### Development Environment (Reduced Costs)

```typescript
import { Duration } from 'aws-cdk-lib';

const devCluster = new AuroraCluster(this, 'DevDatabase', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'dev',
  username: 'admin',
  clusterName: 'dev-cluster',
  instanceCount: 1, // Single instance
  instanceClass: 'BURSTABLE3', // Cost-effective
  instanceSize: 'MEDIUM',
  deletionProtection: false, // Allow easy teardown
  backupRetention: Duration.days(7) // Shorter retention
});
```

## Extending the Construct

The `AuroraCluster` construct supports customization through protected hook methods. This allows you to override specific resource creation without modifying the base module.

### Why Extend?

- **Cross-client reuse**: Use the same base module across multiple projects with client-specific customizations
- **No module forking**: Customize behavior without maintaining a fork
- **Type-safe**: Full TypeScript support for all hook methods
- **Selective overrides**: Override only what you need, keep defaults for the rest

### Available Hook Methods

| Hook Method | Returns | Purpose |
|-------------|---------|---------|
| `resolveVpc(props)` | `IVpc` | Custom VPC resolution |
| `createSecret(props)` | `ISecret` | Custom secret management |
| `createCredentials(props)` | `Credentials` | Custom credential configuration |
| `createEncryptionKey(props)` | `IKey` | Custom KMS key (or use existing) |
| `createSecurityGroup(vpc, port, props)` | `ISecurityGroup` | Custom security rules |
| `createParameterGroup(engine, props)` | `IParameterGroup` | Custom database parameters |
| `createClusterInstances(props)` | `ClusterInstanceConfig` | Custom instance configuration |
| `createCluster(config, props)` | `IDatabaseCluster` | Full cluster customization |
| `onClusterCreated(cluster)` | `void` | Post-creation hooks (tags, alarms) |
| `onConstructComplete()` | `void` | Final customization |

### Protected Properties

All intermediate resources are available as protected properties in your subclass:

| Property | Type | Description |
|----------|------|-------------|
| `_props` | `AuroraClusterProps` | Original constructor props |
| `_vpc` | `IVpc` | Resolved VPC |
| `_kmsKey` | `IKey` | Encryption key |
| `_securityGroups` | `ISecurityGroup[]` | Security groups |
| `_parameterGroup` | `IParameterGroup` | Parameter group |
| `_credentials` | `Credentials` | Database credentials |
| `_engine` | `IClusterEngine` | Database engine |

### Example: Custom Security Group

```typescript
import { AuroraCluster, AuroraClusterProps } from '@cdk-constructs/aurora-cluster';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

class MyAuroraCluster extends AuroraCluster {
  protected createSecurityGroup(
    vpc: ec2.IVpc,
    port: number,
    props: AuroraClusterProps
  ): ec2.ISecurityGroup {
    const sg = new ec2.SecurityGroup(this, 'CustomSG', {
      vpc,
      description: 'Custom security group with specific CIDR rules'
    });

    // Allow from specific CIDR ranges
    sg.addIngressRule(ec2.Peer.ipv4('10.0.0.0/8'), ec2.Port.tcp(port), 'Corporate network');
    sg.addIngressRule(ec2.Peer.ipv4('172.16.0.0/12'), ec2.Port.tcp(port), 'VPN network');

    return sg;
  }
}
```

### Example: Use Existing KMS Key

```typescript
import * as kms from 'aws-cdk-lib/aws-kms';

class MyAuroraCluster extends AuroraCluster {
  protected createEncryptionKey(props: AuroraClusterProps): kms.IKey {
    // Use an existing KMS key from your organization
    return kms.Key.fromKeyArn(this, 'ExistingKey',
      'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
    );
  }
}
```

### Example: Custom Parameter Group

```typescript
import * as rds from 'aws-cdk-lib/aws-rds';

class MyAuroraCluster extends AuroraCluster {
  protected createParameterGroup(
    engine: rds.IClusterEngine,
    props: AuroraClusterProps
  ): rds.IParameterGroup {
    return new rds.ParameterGroup(this, 'CustomParams', {
      engine,
      parameters: {
        'shared_preload_libraries': 'pg_stat_statements,auto_explain',
        'log_min_duration_statement': '1000',
        'auto_explain.log_min_duration': '1000',
        ...props.parameters
      }
    });
  }
}
```

### Example: Post-Creation Tagging and Alarms

```typescript
import { Tags } from 'aws-cdk-lib';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import * as rds from 'aws-cdk-lib/aws-rds';

class MyAuroraCluster extends AuroraCluster {
  protected onClusterCreated(cluster: rds.IDatabaseCluster): void {
    // Add organization-specific tags
    Tags.of(cluster).add('CostCenter', 'engineering');
    Tags.of(cluster).add('Environment', 'production');
    Tags.of(cluster).add('Team', 'platform');

    // Add CloudWatch alarm for CPU utilization
    new cloudwatch.Alarm(this, 'CPUAlarm', {
      metric: cluster.metricCPUUtilization(),
      threshold: 80,
      evaluationPeriods: 3,
      alarmDescription: 'Database CPU utilization is high'
    });

    // Add alarm for freeable memory
    new cloudwatch.Alarm(this, 'MemoryAlarm', {
      metric: cluster.metricFreeableMemory(),
      threshold: 100 * 1024 * 1024, // 100MB
      evaluationPeriods: 3,
      comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD,
      alarmDescription: 'Database freeable memory is low'
    });
  }
}
```

### Example: Complete Client Extension

```typescript
import { AuroraCluster, AuroraClusterProps, ClusterInstanceConfig } from '@cdk-constructs/aurora-cluster';
import { Construct } from 'constructs';
import { Tags } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as kms from 'aws-cdk-lib/aws-kms';
import * as rds from 'aws-cdk-lib/aws-rds';

/**
 * ACME Corporation's customized Aurora cluster with:
 * - Organization KMS key
 * - Corporate network security rules
 * - Standard tagging
 * - Monitoring alarms
 */
class AcmeAuroraCluster extends AuroraCluster {
  constructor(scope: Construct, id: string, props: AuroraClusterProps) {
    super(scope, id, props);
  }

  // Use organization's shared KMS key
  protected createEncryptionKey(props: AuroraClusterProps): kms.IKey {
    return kms.Key.fromKeyArn(this, 'AcmeKey',
      `arn:aws:kms:${process.env.AWS_REGION}:${process.env.AWS_ACCOUNT}:alias/acme-rds-key`
    );
  }

  // Apply corporate security rules
  protected createSecurityGroup(
    vpc: ec2.IVpc,
    port: number,
    props: AuroraClusterProps
  ): ec2.ISecurityGroup {
    const sg = new ec2.SecurityGroup(this, 'AcmeSG', {
      vpc,
      description: 'ACME standard database security group'
    });

    // Corporate networks only
    sg.addIngressRule(ec2.Peer.ipv4('10.0.0.0/8'), ec2.Port.tcp(port));
    sg.addIngressRule(ec2.Peer.ipv4('192.168.0.0/16'), ec2.Port.tcp(port));

    return sg;
  }

  // Add standard ACME tags
  protected onClusterCreated(cluster: rds.IDatabaseCluster): void {
    Tags.of(cluster).add('Organization', 'ACME');
    Tags.of(cluster).add('ManagedBy', 'Platform-Team');
    Tags.of(cluster).add('CostAllocation', this._props.clusterName);
  }
}

// Usage
const cluster = new AcmeAuroraCluster(this, 'Database', {
  vpc: myVpc,
  engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3,
  databaseName: 'myapp',
  username: 'admin',
  clusterName: 'acme-production-db'
});
```

## API Reference

### AuroraClusterProps

| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| `vpc` | `IVpc` | Either vpc or vpcId | - | The VPC to deploy the cluster in |
| `vpcId` | `string` | Either vpc or vpcId | - | The VPC ID for lookup |
| `engineVersion` | `AuroraPostgresEngineVersion \| AuroraMysqlEngineVersion` | ✅ Yes | - | The Aurora engine version |
| `databaseName` | `string` | ✅ Yes | - | The name of the default database |
| `username` | `string` | ✅ Yes | - | The master username |
| `clusterName` | `string` | ✅ Yes | - | The cluster identifier (must be unique) |
| `instanceCount` | `number` | No | `1` | Total instances (1 writer + N-1 readers) |
| `instanceClass` | `string` | No | `'BURSTABLE3'` | Instance class (e.g., 'MEMORY4', 'BURSTABLE3') |
| `instanceSize` | `string` | No | `'MEDIUM'` | Instance size (e.g., 'SMALL', 'MEDIUM', 'LARGE') |
| `snapshotId` | `string` | No | - | Snapshot ID to restore from |
| `parameterGroupName` | `string` | No | Auto-created | Custom parameter group name |
| `parameters` | `{ [key: string]: string }` | No | `{}` | Custom database parameters |
| `securityGroups` | `ISecurityGroup[]` | No | Auto-created | Custom security groups |
| `deletionProtection` | `boolean` | No | `true` | Enable deletion protection |
| `cloudwatchLogsExports` | `string[]` | No | `[]` | Log types to export to CloudWatch |
| `cloudwatchLogsRetention` | `RetentionDays` | No | `ONE_WEEK` | CloudWatch log retention period |
| `enablePerformanceInsights` | `boolean` | No | `false` | Enable Performance Insights |
| `backupRetention` | `Duration` | No | `Duration.days(30)` | Backup retention period |
| `enableSsmParameters` | `boolean` | No | `true` | Create SSM parameters for cluster outputs |
| `ssmParameterPrefix` | `string` | No | `/cdk/${constructId}` | Custom prefix for SSM parameter paths |

### AuroraCluster Properties

| Property | Type | Description |
|----------|------|-------------|
| `databaseCluster` | `IDatabaseCluster` | The underlying RDS cluster instance |
| `secret` | `ISecret` | The Secrets Manager secret with credentials |
| `clusterIdentifier` | `string` | The cluster identifier |
| `clusterEndpoint` | `Endpoint` | The cluster endpoint (hostname and port) |

### AuroraCluster Methods

#### `grantConnect(role: IRole, databaseUser: string): void`

Grants an IAM role permission to connect to the database as a specific user using IAM authentication.

**Parameters:**
- `role`: The IAM role to grant access to
- `databaseUser`: The database username that the role will connect as

**Example:**
```typescript
const lambdaRole = iam.Role.fromRoleArn(this, 'Role', roleArn);
cluster.grantConnect(lambdaRole, 'app_user');
```

**Note:** You must create the database user separately with the `rds_iam` role:
```sql
CREATE USER app_user;
GRANT rds_iam TO app_user;
```

## Engine Versions

### PostgreSQL

```typescript
import * as rds from 'aws-cdk-lib/aws-rds';

engineVersion: rds.AuroraPostgresEngineVersion.VER_15_3  // PostgreSQL 15.3
engineVersion: rds.AuroraPostgresEngineVersion.VER_14_6  // PostgreSQL 14.6
engineVersion: rds.AuroraPostgresEngineVersion.VER_13_9  // PostgreSQL 13.9
```

### MySQL

```typescript
engineVersion: rds.AuroraMysqlEngineVersion.VER_3_03_0  // MySQL 8.0.28
engineVersion: rds.AuroraMysqlEngineVersion.VER_3_02_0  // MySQL 8.0.23
engineVersion: rds.AuroraMysqlEngineVersion.VER_2_11_0  // MySQL 5.7.40
```

## Instance Classes and Sizes

### Available Classes

- `BURSTABLE3` (db.t3) - Cost-effective for development/testing
- `BURSTABLE4` (db.t4g) - ARM-based, cost-effective
- `MEMORY4` (db.r4) - Memory-optimized
- `MEMORY5` (db.r5) - Latest memory-optimized
- `MEMORY6G` (db.r6g) - ARM-based memory-optimized

### Available Sizes

- `SMALL`, `MEDIUM`, `LARGE`
- `XLARGE`, `XLARGE2`, `XLARGE4`, `XLARGE8`, etc.

### Example Combinations

```typescript
// Development
instanceClass: 'BURSTABLE3', instanceSize: 'SMALL'   // db.t3.small

// Production - Balanced
instanceClass: 'BURSTABLE3', instanceSize: 'LARGE'   // db.t3.large

// Production - Memory-intensive
instanceClass: 'MEMORY5', instanceSize: 'XLARGE2'    // db.r5.2xlarge
```

## Troubleshooting

### Issue: VPC not found

**Error:** `Cannot find VPC with ID: vpc-xxxxx`

**Solution:** Ensure the VPC exists in the target region and account. Use `ec2.Vpc.fromLookup()` or pass the VPC object directly.

### Issue: Insufficient subnet coverage

**Error:** `DBSubnetGroup requires subnets in at least 2 availability zones`

**Solution:** Ensure your VPC has private subnets in at least 2 availability zones. Aurora requires multi-AZ subnet groups.

```typescript
const vpc = new ec2.Vpc(this, 'Vpc', {
  maxAzs: 2, // Minimum for Aurora
  natGateways: 1
});
```

### Issue: Deployment timeout

**Problem:** Stack deployment times out waiting for cluster creation.

**Solution:** Aurora cluster creation typically takes 10-15 minutes. Increase CloudFormation timeout or wait patiently. Check RDS console for actual cluster status.

### Issue: IAM authentication not working

**Error:** Database user cannot authenticate with IAM

**Solution:**
1. Ensure the database user exists and has `rds_iam` role:
   ```sql
   CREATE USER app_user;
   GRANT rds_iam TO app_user;
   ```
2. Verify the IAM role has the correct permissions (use `grantConnect()`)
3. Use the correct connection method with IAM token generation

### Issue: Parameter group errors

**Error:** `Invalid parameter group family`

**Solution:** Ensure custom parameters are compatible with your engine version. Check AWS documentation for valid parameters for your Aurora version.

### Issue: Snapshot not found

**Error:** `DBSnapshotNotFound: Snapshot not found`

**Solution:** Verify the snapshot ID exists and is in the same region. Snapshot IDs use format: `rds:cluster-name-YYYY-MM-DD-HH-MM`.

### Issue: SSM parameter conflicts

**Error:** `Parameter /cdk/Database/cluster-identifier already exists`

**Solution:**
1. SSM parameter names must be unique. If redeploying, either:
   - Use a different construct ID
   - Use a different `ssmParameterPrefix`
   - Set `enableSsmParameters: false`
2. Delete old parameters manually:
   ```bash
   aws ssm delete-parameter --name "/cdk/Database/cluster-identifier"
   ```
3. Or delete all parameters for a prefix:
   ```bash
   aws ssm delete-parameters --names $(aws ssm get-parameters-by-path --path "/cdk/Database" --query "Parameters[].Name" --output text)
   ```

### Issue: Cannot retrieve SSM parameters from another stack

**Error:** `ParameterNotFound: Parameter not found`

**Solution:**
1. Verify the parameter was created. Check CloudFormation outputs or AWS Console.
2. Ensure the parameter name matches exactly (case-sensitive).
3. Verify the IAM role/user has `ssm:GetParameter` permission.
4. Parameters are region-specific - ensure you're querying the correct region.
5. If the cluster stack was deleted, parameters are deleted too.

## Security Best Practices

1. **Encryption**: Always enabled by default with KMS key rotation
2. **Secrets**: Credentials stored in Secrets Manager, never hardcoded
3. **Network**: Deploy in private subnets with controlled security groups
4. **Deletion Protection**: Enabled by default for production
5. **Backups**: 30-day retention by default
6. **IAM Authentication**: Use instead of password-based auth when possible
7. **Least Privilege**: Grant only necessary database permissions

## Cost Optimization

1. **Instance Sizing**: Start with `BURSTABLE3.SMALL` and scale up as needed
2. **Instance Count**: Use single instance for dev, 3+ for production
3. **Backup Retention**: Adjust based on compliance requirements
4. **Performance Insights**: Enable only when actively debugging
5. **CloudWatch Logs**: Export only necessary log types
6. **Deletion Protection**: Disable for temporary/dev environments

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Related Resources

- [AWS Aurora Documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/)
- [AWS CDK Documentation](https://docs.aws.amazon.com/cdk/v2/guide/home.html)
- [Aurora Best Practices](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.BestPractices.html)
- [IAM Database Authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html)

## Support

For issues and questions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review AWS Aurora troubleshooting guides