BuzzerboyAWSLightsail 0.329.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- BuzzerboyAWSLightsailStack/LightSailPostDeploy.py +113 -0
- BuzzerboyAWSLightsailStack/LightsailAIContainer.py +0 -0
- BuzzerboyAWSLightsailStack/LightsailBase.py +666 -0
- BuzzerboyAWSLightsailStack/LightsailContainer.py +367 -0
- BuzzerboyAWSLightsailStack/LightsailDatabase.py +405 -0
- BuzzerboyAWSLightsailStack/__init__.py +0 -0
- buzzerboyawslightsail-0.329.1.dist-info/METADATA +191 -0
- buzzerboyawslightsail-0.329.1.dist-info/RECORD +10 -0
- buzzerboyawslightsail-0.329.1.dist-info/WHEEL +5 -0
- buzzerboyawslightsail-0.329.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AWS Lightsail Mini Infrastructure Stack
|
|
3
|
+
======================================
|
|
4
|
+
|
|
5
|
+
This module provides a comprehensive AWS Lightsail infrastructure deployment stack
|
|
6
|
+
using CDKTF (Cloud Development Kit for Terraform) with Python.
|
|
7
|
+
|
|
8
|
+
The stack includes:
|
|
9
|
+
* Lightsail Container Service with automatic custom domain attachment
|
|
10
|
+
* PostgreSQL Database (optional)
|
|
11
|
+
* DNS management with CNAME records
|
|
12
|
+
* SSL certificate management with automatic validation
|
|
13
|
+
* IAM resources for service access
|
|
14
|
+
* S3 bucket for application data
|
|
15
|
+
* Secrets Manager for credential storage
|
|
16
|
+
|
|
17
|
+
:author: Generated with GitHub Copilot
|
|
18
|
+
:version: 1.0.0
|
|
19
|
+
:license: MIT
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#region specific imports
|
|
24
|
+
|
|
25
|
+
import os
|
|
26
|
+
import json
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from constructs import Construct
|
|
29
|
+
from cdktf import TerraformOutput
|
|
30
|
+
|
|
31
|
+
# Import the base class
|
|
32
|
+
from .LightsailBase import LightsailBase, BaseLightsailArchitectureFlags
|
|
33
|
+
|
|
34
|
+
#endregion
|
|
35
|
+
|
|
36
|
+
#region AWS Provider and Resources
|
|
37
|
+
from cdktf_cdktf_provider_aws.provider import AwsProvider
|
|
38
|
+
from cdktf_cdktf_provider_aws import (
|
|
39
|
+
lightsail_container_service,
|
|
40
|
+
lightsail_database,
|
|
41
|
+
cloudfront_distribution,
|
|
42
|
+
s3_bucket,
|
|
43
|
+
)
|
|
44
|
+
#endregion
|
|
45
|
+
|
|
46
|
+
#region Random Provider and Resources
|
|
47
|
+
from cdktf_cdktf_provider_random import password
|
|
48
|
+
|
|
49
|
+
# AWS WAF (currently unused but imported for future use)
|
|
50
|
+
from cdktf_cdktf_provider_aws.wafv2_web_acl import (
|
|
51
|
+
Wafv2WebAcl,
|
|
52
|
+
Wafv2WebAclDefaultAction,
|
|
53
|
+
Wafv2WebAclRule,
|
|
54
|
+
Wafv2WebAclVisibilityConfig,
|
|
55
|
+
Wafv2WebAclDefaultActionAllow,
|
|
56
|
+
Wafv2WebAclRuleOverrideAction,
|
|
57
|
+
Wafv2WebAclRuleOverrideActionNone,
|
|
58
|
+
Wafv2WebAclRuleOverrideActionCount,
|
|
59
|
+
Wafv2WebAclRuleVisibilityConfig,
|
|
60
|
+
)
|
|
61
|
+
from cdktf_cdktf_provider_aws.wafv2_web_acl_association import Wafv2WebAclAssociation
|
|
62
|
+
from cdktf_cdktf_provider_aws.wafv2_rule_group import Wafv2RuleGroupRuleVisibilityConfig
|
|
63
|
+
|
|
64
|
+
#endregion
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
#region ArchitectureFlags
|
|
69
|
+
class ArchitectureFlags(BaseLightsailArchitectureFlags):
|
|
70
|
+
"""
|
|
71
|
+
Architecture configuration flags for optional components.
|
|
72
|
+
|
|
73
|
+
Extends BaseLightsailArchitectureFlags with container-specific flags.
|
|
74
|
+
|
|
75
|
+
:param SKIP_DATABASE: Skip database creation
|
|
76
|
+
:param SKIP_DOMAIN: Skip domain and DNS configuration
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
SKIP_DATABASE = "skip_database"
|
|
80
|
+
SKIP_DOMAIN = "skip_domain"
|
|
81
|
+
|
|
82
|
+
#endregion
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class LightsailContainerStack(LightsailBase):
|
|
86
|
+
"""
|
|
87
|
+
AWS Lightsail Mini Infrastructure Stack.
|
|
88
|
+
|
|
89
|
+
A comprehensive infrastructure stack that deploys:
|
|
90
|
+
* Lightsail Container Service with custom domain support
|
|
91
|
+
* PostgreSQL database (optional)
|
|
92
|
+
* IAM resources and S3 storage
|
|
93
|
+
|
|
94
|
+
:param scope: The construct scope
|
|
95
|
+
:param id: The construct ID
|
|
96
|
+
:param kwargs: Configuration parameters including region, domains, flags, etc.
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
>>> stack = LightsailContainerStack(
|
|
100
|
+
... app, "my-stack",
|
|
101
|
+
... region="ca-central-1",
|
|
102
|
+
... domains=["app.example.com"],
|
|
103
|
+
... project_name="my-app",
|
|
104
|
+
... postApplyScripts=[
|
|
105
|
+
... "echo 'Deployment completed'",
|
|
106
|
+
... "curl -X POST https://webhook.example.com/notify"
|
|
107
|
+
... ]
|
|
108
|
+
... )
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def get_architecture_flags():
|
|
113
|
+
"""
|
|
114
|
+
Get the ArchitectureFlags enum for configuration.
|
|
115
|
+
|
|
116
|
+
:returns: ArchitectureFlags enum class
|
|
117
|
+
:rtype: type[ArchitectureFlags]
|
|
118
|
+
"""
|
|
119
|
+
return ArchitectureFlags
|
|
120
|
+
|
|
121
|
+
def __init__(self, scope, id, **kwargs):
|
|
122
|
+
"""
|
|
123
|
+
Initialize the AWS Lightsail Mini Infrastructure Stack.
|
|
124
|
+
|
|
125
|
+
:param scope: The construct scope
|
|
126
|
+
:param id: Unique identifier for this stack
|
|
127
|
+
:param kwargs: Configuration parameters
|
|
128
|
+
|
|
129
|
+
**Configuration Parameters:**
|
|
130
|
+
|
|
131
|
+
:param region: AWS region (default: "us-east-1")
|
|
132
|
+
:param environment: Environment name (default: "dev")
|
|
133
|
+
:param project_name: Project identifier (default: "bb-aws-lightsail-mini-v1a-app")
|
|
134
|
+
:param domain_name: Primary domain name
|
|
135
|
+
:param domains: List of custom domains to configure
|
|
136
|
+
:param flags: List of ArchitectureFlags to modify behavior
|
|
137
|
+
:param profile: AWS profile to use (default: "default")
|
|
138
|
+
:param postApplyScripts: List of shell commands to execute after deployment
|
|
139
|
+
|
|
140
|
+
.. warning::
|
|
141
|
+
Lightsail domain operations must use us-east-1 region regardless of
|
|
142
|
+
the main stack region.
|
|
143
|
+
"""
|
|
144
|
+
# Set container-specific defaults
|
|
145
|
+
if "project_name" not in kwargs:
|
|
146
|
+
kwargs["project_name"] = "bb-aws-lightsail-mini-v1a-app"
|
|
147
|
+
|
|
148
|
+
# Call parent constructor which handles all the base initialization
|
|
149
|
+
super().__init__(scope, id, **kwargs)
|
|
150
|
+
|
|
151
|
+
# ===== Container-Specific Configuration =====
|
|
152
|
+
self.domains = kwargs.get("domains", []) or []
|
|
153
|
+
|
|
154
|
+
# ===== Database Configuration =====
|
|
155
|
+
self.default_db_name = kwargs.get("default_db_name", self.project_name)
|
|
156
|
+
self.default_db_username = kwargs.get("default_db_username", "dbadmin")
|
|
157
|
+
|
|
158
|
+
def _initialize_providers(self):
|
|
159
|
+
"""Initialize all required Terraform providers."""
|
|
160
|
+
# Call parent class to initialize base providers
|
|
161
|
+
super()._initialize_providers()
|
|
162
|
+
|
|
163
|
+
# Add Lightsail-specific provider for domain operations (must be us-east-1)
|
|
164
|
+
self.aws_domain_provider = AwsProvider(
|
|
165
|
+
self, "aws_domain", region="us-east-1", profile=self.profile, alias="domain"
|
|
166
|
+
)
|
|
167
|
+
self.resources["aws_domain"] = self.aws_domain_provider
|
|
168
|
+
|
|
169
|
+
def _set_default_post_apply_scripts(self):
|
|
170
|
+
"""
|
|
171
|
+
Set default post-apply scripts specific to container deployments.
|
|
172
|
+
"""
|
|
173
|
+
# Call parent method for base scripts
|
|
174
|
+
super()._set_default_post_apply_scripts()
|
|
175
|
+
|
|
176
|
+
# Skip if flag is set
|
|
177
|
+
if BaseLightsailArchitectureFlags.SKIP_DEFAULT_POST_APPLY_SCRIPTS.value in self.flags:
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
# Add container-specific scripts
|
|
181
|
+
container_scripts = [
|
|
182
|
+
f"echo '🚀 Container Service URL: https://{self.project_name}.{self.region}.cs.amazonlightsail.com'",
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
# Insert container-specific scripts before the final "execution started" message
|
|
186
|
+
if self.post_apply_scripts:
|
|
187
|
+
# Find the index of the last script and insert before it
|
|
188
|
+
insert_index = len(self.post_apply_scripts) - 1
|
|
189
|
+
for script in reversed(container_scripts):
|
|
190
|
+
self.post_apply_scripts.insert(insert_index, script)
|
|
191
|
+
|
|
192
|
+
def create_lightsail_resources(self):
|
|
193
|
+
"""
|
|
194
|
+
Create core Lightsail resources.
|
|
195
|
+
|
|
196
|
+
Creates:
|
|
197
|
+
* Lightsail Container Service with nano power and scale of 1
|
|
198
|
+
* Random password for database authentication (if database not skipped)
|
|
199
|
+
|
|
200
|
+
.. note::
|
|
201
|
+
Custom domains are configured separately through DNS records and
|
|
202
|
+
post-deployment automation rather than the public_domain_names parameter
|
|
203
|
+
due to CDKTF type complexity.
|
|
204
|
+
"""
|
|
205
|
+
# Lightsail Container Service
|
|
206
|
+
self.container_service = lightsail_container_service.LightsailContainerService(
|
|
207
|
+
self,
|
|
208
|
+
"app_container",
|
|
209
|
+
name=f"{self.project_name}",
|
|
210
|
+
power="nano",
|
|
211
|
+
region=self.region,
|
|
212
|
+
scale=1,
|
|
213
|
+
is_disabled=False,
|
|
214
|
+
# Note: Custom domains are configured separately via DNS records
|
|
215
|
+
# The public_domain_names parameter has complex type requirements
|
|
216
|
+
tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
|
|
217
|
+
)
|
|
218
|
+
self.container_service_url = self.get_lightsail_container_service_domain()
|
|
219
|
+
|
|
220
|
+
# Create Lightsail database if not skipped
|
|
221
|
+
if not self.has_flag(ArchitectureFlags.SKIP_DATABASE.value):
|
|
222
|
+
self.create_lightsail_database()
|
|
223
|
+
|
|
224
|
+
# Create S3 bucket for application data
|
|
225
|
+
self.create_s3_bucket()
|
|
226
|
+
|
|
227
|
+
self.resources["lightsail_container_service"] = self.container_service
|
|
228
|
+
|
|
229
|
+
def create_lightsail_database(self):
|
|
230
|
+
"""
|
|
231
|
+
Create Lightsail PostgreSQL database (optional).
|
|
232
|
+
|
|
233
|
+
Creates a micro PostgreSQL 14 database instance if the SKIP_DATABASE flag
|
|
234
|
+
is not set. Also populates the secrets dictionary with database connection
|
|
235
|
+
information for use in Secrets Manager.
|
|
236
|
+
|
|
237
|
+
Database Configuration:
|
|
238
|
+
* Engine: PostgreSQL 14
|
|
239
|
+
* Size: micro_2_0
|
|
240
|
+
* Final snapshot: Disabled (skip_final_snapshot=True)
|
|
241
|
+
|
|
242
|
+
.. note::
|
|
243
|
+
Database creation can be skipped by including ArchitectureFlags.SKIP_DATABASE
|
|
244
|
+
in the flags parameter during stack initialization.
|
|
245
|
+
"""
|
|
246
|
+
# Database Password Generation
|
|
247
|
+
self.db_password = password.Password(
|
|
248
|
+
self, "db_password", length=16, special=True, override_special="!#$%&*()-_=+[]{}<>:?"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
self.database = lightsail_database.LightsailDatabase(
|
|
252
|
+
self,
|
|
253
|
+
"app_database",
|
|
254
|
+
relational_database_name=f"{self.project_name}-db",
|
|
255
|
+
blueprint_id="postgres_14",
|
|
256
|
+
bundle_id="micro_2_0",
|
|
257
|
+
master_database_name=self.clean_hyphens(f"{self.project_name}"),
|
|
258
|
+
master_username=self.default_db_username,
|
|
259
|
+
master_password=self.db_password.result,
|
|
260
|
+
skip_final_snapshot=True,
|
|
261
|
+
tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Populate secrets for database connection
|
|
265
|
+
self.secrets.update(
|
|
266
|
+
{
|
|
267
|
+
"password": self.db_password.result,
|
|
268
|
+
"username": self.default_db_username,
|
|
269
|
+
"dbname": self.default_db_name,
|
|
270
|
+
"host": self.database.master_endpoint_address,
|
|
271
|
+
"port": self.database.master_endpoint_port,
|
|
272
|
+
}
|
|
273
|
+
def create_s3_bucket(self, bucket_name=None):
|
|
274
|
+
"""
|
|
275
|
+
Create S3 bucket for application data storage.
|
|
276
|
+
|
|
277
|
+
Creates a private S3 bucket with proper tagging for application data storage
|
|
278
|
+
and security configurations:
|
|
279
|
+
- Bucket versioning enabled
|
|
280
|
+
- Server-side encryption with Amazon S3 managed keys (SSE-S3)
|
|
281
|
+
- Bucket key enabled to reduce encryption costs
|
|
282
|
+
- Private ACL
|
|
283
|
+
|
|
284
|
+
The bucket name follows the pattern: {project_name}-s3
|
|
285
|
+
|
|
286
|
+
.. note::
|
|
287
|
+
The ACL parameter is deprecated in favor of aws_s3_bucket_acl resource
|
|
288
|
+
but is retained for backwards compatibility.
|
|
289
|
+
"""
|
|
290
|
+
if bucket_name is None:
|
|
291
|
+
bucket_name = self.properize_s3_bucketname(f"{self.project_name}-s3")
|
|
292
|
+
|
|
293
|
+
self.s3_bucket = s3_bucket.S3Bucket(
|
|
294
|
+
self,
|
|
295
|
+
"app_data_bucket",
|
|
296
|
+
bucket=bucket_name,
|
|
297
|
+
acl="private",
|
|
298
|
+
versioning={"enabled": True},
|
|
299
|
+
server_side_encryption_configuration=({
|
|
300
|
+
"rule": ({
|
|
301
|
+
"apply_server_side_encryption_by_default": {
|
|
302
|
+
"sse_algorithm": "AES256"
|
|
303
|
+
},
|
|
304
|
+
"bucket_key_enabled": True
|
|
305
|
+
})
|
|
306
|
+
}),
|
|
307
|
+
tags={"Environment": self.environment, "Project": self.project_name, "Stack": self.__class__.__name__},
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Store the S3 bucket in resources registry
|
|
311
|
+
self.resources["s3_bucket"] = self.s3_bucket
|
|
312
|
+
self.bucket_name = bucket_name
|
|
313
|
+
|
|
314
|
+
def get_lightsail_container_service_domain(self):
|
|
315
|
+
"""
|
|
316
|
+
Retrieve the actual Lightsail container service domain from AWS.
|
|
317
|
+
|
|
318
|
+
Returns a default format domain since we cannot query AWS at synthesis time.
|
|
319
|
+
|
|
320
|
+
:returns: The public domain URL for the container service
|
|
321
|
+
:rtype: str
|
|
322
|
+
"""
|
|
323
|
+
return f"{self.project_name}.{self.region}.cs.amazonlightsail.com"
|
|
324
|
+
|
|
325
|
+
def create_outputs(self):
|
|
326
|
+
"""
|
|
327
|
+
Create Terraform outputs for important resource information.
|
|
328
|
+
|
|
329
|
+
Generates outputs for:
|
|
330
|
+
* Container service public URL
|
|
331
|
+
* Database endpoint (if database is enabled)
|
|
332
|
+
* Database password (sensitive, if database is enabled)
|
|
333
|
+
* IAM access keys (sensitive)
|
|
334
|
+
|
|
335
|
+
.. note::
|
|
336
|
+
Sensitive outputs are marked as such and will be hidden in
|
|
337
|
+
Terraform output unless explicitly requested.
|
|
338
|
+
"""
|
|
339
|
+
# Container service public URL
|
|
340
|
+
TerraformOutput(
|
|
341
|
+
self,
|
|
342
|
+
"container_service_url",
|
|
343
|
+
value=self.container_service_url,
|
|
344
|
+
description="Public URL of the Lightsail container service",
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# Database outputs (if database is enabled)
|
|
348
|
+
if not self.has_flag(ArchitectureFlags.SKIP_DATABASE.value) and hasattr(self, 'database'):
|
|
349
|
+
TerraformOutput(
|
|
350
|
+
self,
|
|
351
|
+
"database_endpoint",
|
|
352
|
+
value=f"{self.database.master_endpoint_address}:{self.database.master_endpoint_port}",
|
|
353
|
+
description="Database connection endpoint",
|
|
354
|
+
)
|
|
355
|
+
TerraformOutput(
|
|
356
|
+
self,
|
|
357
|
+
"database_password",
|
|
358
|
+
value=self.database.master_password,
|
|
359
|
+
sensitive=True,
|
|
360
|
+
description="Database master password (sensitive)",
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# Use the shared IAM output helper
|
|
364
|
+
self.create_iam_outputs()
|
|
365
|
+
|
|
366
|
+
"""Placeholder for networking resources creation."""
|
|
367
|
+
pass
|