dbt-platform-helper 11.3.0__py3-none-any.whl → 12.0.0__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.
Potentially problematic release.
This version of dbt-platform-helper might be problematic. Click here for more details.
- dbt_platform_helper/COMMANDS.md +3 -252
- dbt_platform_helper/addons-template-map.yml +7 -33
- dbt_platform_helper/commands/application.py +8 -7
- dbt_platform_helper/commands/conduit.py +1 -4
- dbt_platform_helper/commands/copilot.py +14 -110
- dbt_platform_helper/commands/environment.py +0 -5
- dbt_platform_helper/commands/pipeline.py +1 -13
- dbt_platform_helper/domain/database_copy.py +2 -2
- dbt_platform_helper/domain/maintenance_page.py +0 -3
- dbt_platform_helper/templates/addon-instructions.txt +1 -1
- dbt_platform_helper/templates/addons/svc/s3-policy.yml +0 -8
- dbt_platform_helper/utils/aws.py +3 -1
- dbt_platform_helper/utils/platform_config.py +2 -7
- dbt_platform_helper/utils/validation.py +3 -78
- {dbt_platform_helper-11.3.0.dist-info → dbt_platform_helper-12.0.0.dist-info}/METADATA +1 -1
- {dbt_platform_helper-11.3.0.dist-info → dbt_platform_helper-12.0.0.dist-info}/RECORD +20 -33
- platform_helper.py +0 -8
- dbt_platform_helper/commands/check_cloudformation.py +0 -87
- dbt_platform_helper/commands/dns.py +0 -952
- dbt_platform_helper/custom_resources/__init__.py +0 -0
- dbt_platform_helper/custom_resources/s3_object.py +0 -85
- dbt_platform_helper/templates/addons/env/addons.parameters.yml +0 -19
- dbt_platform_helper/templates/addons/env/aurora-postgres.yml +0 -604
- dbt_platform_helper/templates/addons/env/monitoring.yml +0 -121
- dbt_platform_helper/templates/addons/env/opensearch.yml +0 -257
- dbt_platform_helper/templates/addons/env/rds-postgres.yml +0 -603
- dbt_platform_helper/templates/addons/env/redis-cluster.yml +0 -171
- dbt_platform_helper/templates/addons/env/s3.yml +0 -219
- dbt_platform_helper/templates/addons/env/vpc.yml +0 -120
- dbt_platform_helper/utils/cloudformation.py +0 -34
- {dbt_platform_helper-11.3.0.dist-info → dbt_platform_helper-12.0.0.dist-info}/LICENSE +0 -0
- {dbt_platform_helper-11.3.0.dist-info → dbt_platform_helper-12.0.0.dist-info}/WHEEL +0 -0
- {dbt_platform_helper-11.3.0.dist-info → dbt_platform_helper-12.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,603 +0,0 @@
|
|
|
1
|
-
# {% extra_header %}
|
|
2
|
-
# {% version_info %}
|
|
3
|
-
|
|
4
|
-
Parameters:
|
|
5
|
-
# Copilot required Parameters...
|
|
6
|
-
App:
|
|
7
|
-
Type: String
|
|
8
|
-
Description: Your application's name.
|
|
9
|
-
Env:
|
|
10
|
-
Type: String
|
|
11
|
-
Description: The environment name your service, job, or workflow is being deployed to.
|
|
12
|
-
|
|
13
|
-
# Parameters from the parent stack brought in via addons.parameters.yml...
|
|
14
|
-
EnvironmentSecurityGroup:
|
|
15
|
-
Type: String
|
|
16
|
-
DefaultPublicRoute:
|
|
17
|
-
Type: String
|
|
18
|
-
InternetGateway:
|
|
19
|
-
Type: String
|
|
20
|
-
InternetGatewayAttachment:
|
|
21
|
-
Type: String
|
|
22
|
-
PrivateSubnets:
|
|
23
|
-
Type: String
|
|
24
|
-
PublicRouteTable:
|
|
25
|
-
Type: String
|
|
26
|
-
PublicSubnet1RouteTableAssociation:
|
|
27
|
-
Type: String
|
|
28
|
-
PublicSubnet2RouteTableAssociation:
|
|
29
|
-
Type: String
|
|
30
|
-
VpcId:
|
|
31
|
-
Type: String
|
|
32
|
-
|
|
33
|
-
# Other parameters...
|
|
34
|
-
# Customize your RDS Postgres cluster by setting the default value of the following parameters.
|
|
35
|
-
{{ addon_config.prefix }}DBName:
|
|
36
|
-
Type: String
|
|
37
|
-
Description: The name of the initial database to be created.
|
|
38
|
-
Default: main
|
|
39
|
-
# Cannot have special characters
|
|
40
|
-
# Naming constraints: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints
|
|
41
|
-
|
|
42
|
-
Mappings:
|
|
43
|
-
{{ addon_config.prefix }}EnvironmentConfigMap:
|
|
44
|
-
{%- for env_name, config in addon_config.environments.items() %}
|
|
45
|
-
{{ env_name }}:
|
|
46
|
-
DBInstanceClass: '{{ config.instance }}'
|
|
47
|
-
MultiAZ: {{ config.multi_az }}
|
|
48
|
-
AllocatedStorage: {{ config.volume_size }}
|
|
49
|
-
MaxAllocatedStorage: {{ (config.volume_size * 1.26)|round|int }}
|
|
50
|
-
StorageType: {% if env_name == "prod" or env_name == "production" %}io1{% else %}gp3{% endif %}
|
|
51
|
-
Iops: {{ config.iops if env_name == "prod" or env_name == "production" else '""' }}
|
|
52
|
-
DeletionPolicy: {{ config.deletion_policy }}
|
|
53
|
-
DeletionProtection: {{ config.deletion_protection if config.deletion_protection else false }}
|
|
54
|
-
SnapshotIdentifier: {{ config.snapshot_id if config.snapshot_id else '""' }}
|
|
55
|
-
{%- endfor %}
|
|
56
|
-
|
|
57
|
-
Conditions:
|
|
58
|
-
{{ addon_config.prefix }}CreateProdSubFilter: !Or [!Equals [!Ref Env, prod], !Equals [!Ref Env, production], !Equals [!Ref Env, PROD], !Equals [!Ref Env, PRODUCTION]]
|
|
59
|
-
{{ addon_config.prefix }}UseSnapshot: !Not [!Equals [!FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, SnapshotIdentifier], ""]]
|
|
60
|
-
{{ addon_config.prefix }}UseIops: !Not [!Equals [!FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, Iops], ""]]
|
|
61
|
-
|
|
62
|
-
Resources:
|
|
63
|
-
# Subnet group to control where the DB gets placed
|
|
64
|
-
{{ addon_config.prefix }}DBSubnetGroup:
|
|
65
|
-
Type: AWS::RDS::DBSubnetGroup
|
|
66
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
67
|
-
UpdateReplacePolicy: Retain
|
|
68
|
-
Properties:
|
|
69
|
-
DBSubnetGroupDescription: Group of subnets to place DB into
|
|
70
|
-
SubnetIds: !Split [ ",", !Ref PrivateSubnets ]
|
|
71
|
-
|
|
72
|
-
# Security group to add the DB to the VPC,
|
|
73
|
-
# and to allow the Fargate containers to talk to DB
|
|
74
|
-
{{ addon_config.prefix }}SecurityGroup:
|
|
75
|
-
Metadata:
|
|
76
|
-
'aws:copilot:description': 'A security group to access the DB cluster'
|
|
77
|
-
Type: AWS::EC2::SecurityGroup
|
|
78
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
79
|
-
UpdateReplacePolicy: Retain
|
|
80
|
-
Properties:
|
|
81
|
-
GroupDescription: "DB Security Group"
|
|
82
|
-
VpcId: !Ref VpcId
|
|
83
|
-
Tags:
|
|
84
|
-
- Key: Name
|
|
85
|
-
Value: !Sub 'copilot-${App}-${Env}-{{ addon_config.name }}-RDS-Postgres-SecurityGroup'
|
|
86
|
-
|
|
87
|
-
# Enable ingress from other ECS services created within the environment.
|
|
88
|
-
{{ addon_config.prefix }}DBIngress:
|
|
89
|
-
Metadata:
|
|
90
|
-
'aws:copilot:description': 'Allow ingress from containers in my application to the DB cluster'
|
|
91
|
-
Type: AWS::EC2::SecurityGroupIngress
|
|
92
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
93
|
-
UpdateReplacePolicy: Retain
|
|
94
|
-
Properties:
|
|
95
|
-
Description: Ingress from Fargate containers
|
|
96
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
97
|
-
IpProtocol: tcp
|
|
98
|
-
FromPort: 5432
|
|
99
|
-
ToPort: 5432
|
|
100
|
-
SourceSecurityGroupId: !Ref EnvironmentSecurityGroup
|
|
101
|
-
|
|
102
|
-
{{ addon_config.prefix }}LambdaIngress:
|
|
103
|
-
Metadata:
|
|
104
|
-
'aws:copilot:description': 'Allow ingress from Lambda Functions in my application to the DB'
|
|
105
|
-
Type: AWS::EC2::SecurityGroupIngress
|
|
106
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
107
|
-
UpdateReplacePolicy: Retain
|
|
108
|
-
Properties:
|
|
109
|
-
Description: Ingress from Lambda Functions to DB
|
|
110
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
111
|
-
IpProtocol: tcp
|
|
112
|
-
FromPort: 5432
|
|
113
|
-
ToPort: 5432
|
|
114
|
-
SourceSecurityGroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
115
|
-
|
|
116
|
-
{{ addon_config.prefix }}SecretsManagerIngress:
|
|
117
|
-
Metadata:
|
|
118
|
-
'aws:copilot:description': 'Allow ingress from Lambda Functions in my application to the Secrets Manager'
|
|
119
|
-
Type: AWS::EC2::SecurityGroupIngress
|
|
120
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
121
|
-
UpdateReplacePolicy: Retain
|
|
122
|
-
Properties:
|
|
123
|
-
Description: Ingress from Lambda Functions to Secrets Manager
|
|
124
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
125
|
-
IpProtocol: tcp
|
|
126
|
-
FromPort: 443
|
|
127
|
-
ToPort: 443
|
|
128
|
-
SourceSecurityGroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
129
|
-
|
|
130
|
-
{{ addon_config.prefix }}LambdaEgress:
|
|
131
|
-
Metadata:
|
|
132
|
-
'aws:copilot:description': 'Allow egress from DB in my application to the Lambda Function'
|
|
133
|
-
Type: AWS::EC2::SecurityGroupEgress
|
|
134
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
135
|
-
UpdateReplacePolicy: Retain
|
|
136
|
-
Properties:
|
|
137
|
-
Description: Egress from DB to Lambda Functions
|
|
138
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
139
|
-
IpProtocol: tcp
|
|
140
|
-
FromPort: 5432
|
|
141
|
-
ToPort: 5432
|
|
142
|
-
DestinationSecurityGroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
143
|
-
|
|
144
|
-
{{ addon_config.prefix }}SecretsManagerEgress:
|
|
145
|
-
Metadata:
|
|
146
|
-
'aws:copilot:description': 'Allow egress from Secrets Manager in my application to the Lambda Function'
|
|
147
|
-
Type: AWS::EC2::SecurityGroupEgress
|
|
148
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
149
|
-
UpdateReplacePolicy: Retain
|
|
150
|
-
Properties:
|
|
151
|
-
Description: Egress from Secrets Manager to Lambda Functions
|
|
152
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
153
|
-
IpProtocol: tcp
|
|
154
|
-
FromPort: 443
|
|
155
|
-
ToPort: 443
|
|
156
|
-
DestinationSecurityGroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
157
|
-
|
|
158
|
-
{{ addon_config.prefix }}HTTPSEgress:
|
|
159
|
-
Metadata:
|
|
160
|
-
'aws:copilot:description': 'Allow egress for HTTPS (so the Lambda Function can post a success response back to the Custom Resource)'
|
|
161
|
-
Type: AWS::EC2::SecurityGroupEgress
|
|
162
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
163
|
-
UpdateReplacePolicy: Retain
|
|
164
|
-
Properties:
|
|
165
|
-
CidrIp: 0.0.0.0/0
|
|
166
|
-
Description: Egress for HTTPS
|
|
167
|
-
GroupId: !Ref '{{ addon_config.prefix }}SecurityGroup'
|
|
168
|
-
IpProtocol: tcp
|
|
169
|
-
FromPort: 443
|
|
170
|
-
ToPort: 443
|
|
171
|
-
|
|
172
|
-
{{ addon_config.prefix }}RDSDBParameterGroup:
|
|
173
|
-
Metadata:
|
|
174
|
-
'aws:copilot:description': 'A DB parameter group for engine configuration values'
|
|
175
|
-
Type: 'AWS::RDS::DBParameterGroup'
|
|
176
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
177
|
-
UpdateReplacePolicy: Retain
|
|
178
|
-
Properties:
|
|
179
|
-
Description: !Ref 'AWS::StackName'
|
|
180
|
-
Family: 'postgres{{ addon_config.version | int }}'
|
|
181
|
-
Parameters:
|
|
182
|
-
client_encoding: 'UTF8'
|
|
183
|
-
log_statement: ddl
|
|
184
|
-
log_statement_sample_rate: '1.0'
|
|
185
|
-
|
|
186
|
-
{{ addon_config.prefix }}KMSKey:
|
|
187
|
-
Type: "AWS::KMS::Key"
|
|
188
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
189
|
-
UpdateReplacePolicy: Retain
|
|
190
|
-
Properties:
|
|
191
|
-
Description: "KMS Key for RDS encryption"
|
|
192
|
-
KeyPolicy:
|
|
193
|
-
Version: '2012-10-17'
|
|
194
|
-
Id: !Sub '${App}-${Env}-{{ addon_config.prefix }}-key'
|
|
195
|
-
Statement:
|
|
196
|
-
- Sid: Enable IAM User Permissions
|
|
197
|
-
Effect: Allow
|
|
198
|
-
Principal:
|
|
199
|
-
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
|
|
200
|
-
Action: kms:*
|
|
201
|
-
Resource: '*'
|
|
202
|
-
|
|
203
|
-
{{ addon_config.prefix }}KeyAlias:
|
|
204
|
-
Type: 'AWS::KMS::Alias'
|
|
205
|
-
Properties:
|
|
206
|
-
AliasName: !Sub 'alias/${App}-${Env}-{{ addon_config.prefix }}-key'
|
|
207
|
-
TargetKeyId: !Ref {{ addon_config.prefix }}KMSKey
|
|
208
|
-
|
|
209
|
-
# The cluster itself.
|
|
210
|
-
{{ addon_config.prefix }}DBInstance:
|
|
211
|
-
Metadata:
|
|
212
|
-
'aws:copilot:description': 'DB cluster'
|
|
213
|
-
Type: AWS::RDS::DBInstance
|
|
214
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
215
|
-
UpdateReplacePolicy: Retain
|
|
216
|
-
Properties:
|
|
217
|
-
AllowMajorVersionUpgrade: false
|
|
218
|
-
AutoMinorVersionUpgrade: true
|
|
219
|
-
BackupRetentionPeriod: 8
|
|
220
|
-
EnablePerformanceInsights:
|
|
221
|
-
!If [
|
|
222
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
223
|
-
!Ref AWS::NoValue,
|
|
224
|
-
true
|
|
225
|
-
]
|
|
226
|
-
EnableCloudwatchLogsExports:
|
|
227
|
-
- postgresql
|
|
228
|
-
- upgrade
|
|
229
|
-
Engine: postgres
|
|
230
|
-
EngineVersion: '{{ addon_config.version }}'
|
|
231
|
-
DBInstanceClass: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DBInstanceClass]
|
|
232
|
-
DBSnapshotIdentifier: !If [{{ addon_config.prefix }}UseSnapshot, !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, SnapshotIdentifier], !Ref AWS::NoValue]
|
|
233
|
-
AllocatedStorage: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, AllocatedStorage]
|
|
234
|
-
MaxAllocatedStorage: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, MaxAllocatedStorage]
|
|
235
|
-
StorageType: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, StorageType]
|
|
236
|
-
Iops: !If [{{ addon_config.prefix }}UseIops, !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, Iops], !Ref AWS::NoValue]
|
|
237
|
-
MultiAZ: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, MultiAZ]
|
|
238
|
-
DBParameterGroupName: !Ref {{ addon_config.prefix }}RDSDBParameterGroup
|
|
239
|
-
DBName:
|
|
240
|
-
!If [
|
|
241
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
242
|
-
!Ref AWS::NoValue,
|
|
243
|
-
!Ref {{ addon_config.prefix }}DBName
|
|
244
|
-
]
|
|
245
|
-
KmsKeyId:
|
|
246
|
-
!If [
|
|
247
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
248
|
-
!Ref AWS::NoValue,
|
|
249
|
-
!Ref {{ addon_config.prefix }}KMSKey
|
|
250
|
-
]
|
|
251
|
-
MasterUsername:
|
|
252
|
-
!If [
|
|
253
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
254
|
-
!Ref AWS::NoValue,
|
|
255
|
-
!Join [ "", [ '{% raw %}{{{% endraw %}resolve:secretsmanager:', !Ref {{ addon_config.prefix }}RDSSecret, ":SecretString:username{% raw %}}}{% endraw %}" ]]
|
|
256
|
-
]
|
|
257
|
-
MasterUserPassword:
|
|
258
|
-
!If [
|
|
259
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
260
|
-
!Ref AWS::NoValue,
|
|
261
|
-
!Join [ "", [ '{% raw %}{{{% endraw %}resolve:secretsmanager:', !Ref {{ addon_config.prefix }}RDSSecret, ":SecretString:password{% raw %}}}{% endraw %}" ]]
|
|
262
|
-
]
|
|
263
|
-
DBSubnetGroupName: !Ref '{{ addon_config.prefix }}DBSubnetGroup'
|
|
264
|
-
VPCSecurityGroups:
|
|
265
|
-
- !Ref {{ addon_config.prefix }}SecurityGroup
|
|
266
|
-
StorageEncrypted:
|
|
267
|
-
!If [
|
|
268
|
-
{{ addon_config.prefix }}UseSnapshot,
|
|
269
|
-
!Ref AWS::NoValue,
|
|
270
|
-
true
|
|
271
|
-
]
|
|
272
|
-
DeletionProtection: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionProtection]
|
|
273
|
-
|
|
274
|
-
{{ addon_config.prefix }}RDSSecret:
|
|
275
|
-
Metadata:
|
|
276
|
-
'aws:copilot:description': 'A Secrets Manager secret to store your DB credentials'
|
|
277
|
-
Type: AWS::SecretsManager::Secret
|
|
278
|
-
Properties:
|
|
279
|
-
Name: !Sub '/copilot/${App}/${Env}/secrets/{{ addon_config.name|upper|replace("-", "_") }}'
|
|
280
|
-
Description: !Sub RDS main user secret for ${AWS::StackName}
|
|
281
|
-
GenerateSecretString:
|
|
282
|
-
SecretStringTemplate: '{"username": "postgres"}'
|
|
283
|
-
GenerateStringKey: "password"
|
|
284
|
-
ExcludePunctuation: true
|
|
285
|
-
IncludeSpace: false
|
|
286
|
-
PasswordLength: 16
|
|
287
|
-
ExcludeCharacters: '[]{}()"@/\;=?&`><:|#'
|
|
288
|
-
|
|
289
|
-
{{ addon_config.prefix }}SecretRDSAttachment:
|
|
290
|
-
Type: AWS::SecretsManager::SecretTargetAttachment
|
|
291
|
-
Properties:
|
|
292
|
-
SecretId: !Ref {{ addon_config.prefix }}RDSSecret
|
|
293
|
-
TargetId: !Ref {{ addon_config.prefix }}DBInstance
|
|
294
|
-
TargetType: AWS::RDS::DBInstance
|
|
295
|
-
|
|
296
|
-
{{ addon_config.prefix }}LambdaFunction:
|
|
297
|
-
Type: AWS::Lambda::Function
|
|
298
|
-
Properties:
|
|
299
|
-
FunctionName: !Sub "${App}-${Env}-{{ addon_config.prefix }}-rds-create-user"
|
|
300
|
-
Handler: index.handler
|
|
301
|
-
Runtime: python3.11
|
|
302
|
-
Layers:
|
|
303
|
-
- arn:aws:lambda:eu-west-2:763451185160:layer:python-postgres:1
|
|
304
|
-
MemorySize: 128
|
|
305
|
-
Timeout: 10
|
|
306
|
-
Role: !GetAtt {{ addon_config.prefix }}LambdaFunctionExecutionRole.Arn
|
|
307
|
-
VpcConfig:
|
|
308
|
-
SecurityGroupIds:
|
|
309
|
-
- !Ref {{ addon_config.prefix }}SecurityGroup
|
|
310
|
-
SubnetIds: !Split [ ",", !Ref PrivateSubnets ]
|
|
311
|
-
Code:
|
|
312
|
-
ZipFile: |
|
|
313
|
-
import json
|
|
314
|
-
import boto3
|
|
315
|
-
import cfnresponse
|
|
316
|
-
import psycopg2
|
|
317
|
-
from botocore.exceptions import ClientError
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
def drop_user(cursor, username):
|
|
321
|
-
cursor.execute(f"SELECT * FROM pg_catalog.pg_user WHERE usename = '{username}'")
|
|
322
|
-
|
|
323
|
-
if cursor.fetchone() is not None:
|
|
324
|
-
cursor.execute(f"GRANT {username} TO postgres")
|
|
325
|
-
cursor.execute(f"DROP OWNED BY {username}")
|
|
326
|
-
cursor.execute(f"DROP USER {username}")
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
def create_db_user(conn, cursor, username, password, permissions):
|
|
330
|
-
drop_user(cursor, username)
|
|
331
|
-
|
|
332
|
-
cursor.execute(f"CREATE USER {username} WITH ENCRYPTED PASSWORD '%s'" % password)
|
|
333
|
-
cursor.execute(f"GRANT {username} to postgres;")
|
|
334
|
-
cursor.execute(f"GRANT {', '.join(permissions)} ON ALL TABLES IN SCHEMA public TO {username};")
|
|
335
|
-
cursor.execute(f"ALTER DEFAULT PRIVILEGES FOR USER {username} IN SCHEMA public GRANT {', '.join(permissions)} ON TABLES TO {username};")
|
|
336
|
-
conn.commit()
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def create_or_update_user_secret(ssm, user_secret_name, user_secret_string, event):
|
|
340
|
-
user_secret_description = event['ResourceProperties']['SecretDescription']
|
|
341
|
-
copilot_application = event['ResourceProperties']['CopilotApplication']
|
|
342
|
-
copilot_environment = event['ResourceProperties']['CopilotEnvironment']
|
|
343
|
-
|
|
344
|
-
user_secret = None
|
|
345
|
-
|
|
346
|
-
try:
|
|
347
|
-
user_secret = ssm.put_parameter(
|
|
348
|
-
Name=user_secret_name,
|
|
349
|
-
Description=user_secret_description,
|
|
350
|
-
Value=json.dumps(user_secret_string),
|
|
351
|
-
Tags=[
|
|
352
|
-
{'Key': 'custom:cloudformation:stack-name', 'Value': event["StackId"].split('/')[1]},
|
|
353
|
-
{'Key': 'custom:cloudformation:logical-id', 'Value': event["LogicalResourceId"]},
|
|
354
|
-
{'Key': 'custom:cloudformation:stack-id', 'Value': event["StackId"]},
|
|
355
|
-
{'Key': 'copilot-application', 'Value': copilot_application},
|
|
356
|
-
{'Key': 'copilot-environment', 'Value': copilot_environment},
|
|
357
|
-
],
|
|
358
|
-
Type="String",
|
|
359
|
-
)
|
|
360
|
-
except ClientError as error:
|
|
361
|
-
if error.response["Error"]["Code"] == "ParameterAlreadyExists":
|
|
362
|
-
user_secret = ssm.put_parameter(
|
|
363
|
-
Name=user_secret_name,
|
|
364
|
-
Description=user_secret_description,
|
|
365
|
-
Value=json.dumps(user_secret_string),
|
|
366
|
-
Overwrite=True,
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
return user_secret
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
def handler(event, context):
|
|
373
|
-
print("REQUEST RECEIVED:\n" + json.dumps(event))
|
|
374
|
-
|
|
375
|
-
db_master_user_secret = event['ResourceProperties']['MasterUserSecret']
|
|
376
|
-
user_secret_name = event['ResourceProperties']['SecretName']
|
|
377
|
-
username = event['ResourceProperties']['Username']
|
|
378
|
-
user_permissions = event['ResourceProperties']['Permissions']
|
|
379
|
-
|
|
380
|
-
secrets_manager = boto3.client("secretsmanager")
|
|
381
|
-
ssm = boto3.client("ssm")
|
|
382
|
-
|
|
383
|
-
master_user = json.loads(secrets_manager.get_secret_value(SecretId=db_master_user_secret)["SecretString"])
|
|
384
|
-
|
|
385
|
-
user_password = secrets_manager.get_random_password(
|
|
386
|
-
PasswordLength=16,
|
|
387
|
-
ExcludeCharacters='[]{}()"@/\;=?&`><:|#',
|
|
388
|
-
ExcludePunctuation=True,
|
|
389
|
-
IncludeSpace=False,
|
|
390
|
-
)["RandomPassword"]
|
|
391
|
-
|
|
392
|
-
user_secret_string = {
|
|
393
|
-
"username": username,
|
|
394
|
-
"password": user_password,
|
|
395
|
-
"engine": master_user["engine"],
|
|
396
|
-
"port": master_user["port"],
|
|
397
|
-
"dbname": master_user["dbname"],
|
|
398
|
-
"host": master_user["host"],
|
|
399
|
-
"dbInstanceIdentifier": master_user["dbInstanceIdentifier"]
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
conn = psycopg2.connect(
|
|
403
|
-
dbname=master_user["dbname"],
|
|
404
|
-
user=master_user["username"],
|
|
405
|
-
password=master_user["password"],
|
|
406
|
-
host=master_user["host"],
|
|
407
|
-
port=master_user["port"]
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
cursor = conn.cursor()
|
|
411
|
-
|
|
412
|
-
response = {"Status": "SUCCESS"}
|
|
413
|
-
|
|
414
|
-
try:
|
|
415
|
-
match event["RequestType"]:
|
|
416
|
-
case "Create":
|
|
417
|
-
create_db_user(conn, cursor, username, user_password, user_permissions)
|
|
418
|
-
|
|
419
|
-
response = {
|
|
420
|
-
**response,
|
|
421
|
-
"Data": create_or_update_user_secret(ssm, user_secret_name, user_secret_string, event)
|
|
422
|
-
}
|
|
423
|
-
case "Update":
|
|
424
|
-
create_db_user(conn, cursor, username, user_password, user_permissions)
|
|
425
|
-
|
|
426
|
-
response = {
|
|
427
|
-
**response,
|
|
428
|
-
"Data": create_or_update_user_secret(ssm, user_secret_name, user_secret_string, event)
|
|
429
|
-
}
|
|
430
|
-
case "Delete":
|
|
431
|
-
drop_user(cursor, username)
|
|
432
|
-
|
|
433
|
-
response = {
|
|
434
|
-
**response,
|
|
435
|
-
"Data": ssm.delete_parameter(Name=user_secret_name)
|
|
436
|
-
}
|
|
437
|
-
case _:
|
|
438
|
-
response = {"Status": "FAILED",
|
|
439
|
-
"Data": {"Error": f"""Invalid requestType of '${event["RequestType"]}'"""}}
|
|
440
|
-
except Exception as e:
|
|
441
|
-
response = {"Status": "FAILED", "Data": {"Error": str(e)}}
|
|
442
|
-
|
|
443
|
-
cursor.close()
|
|
444
|
-
conn.close()
|
|
445
|
-
|
|
446
|
-
print(json.dumps(response, default=str))
|
|
447
|
-
cfnresponse.send(event, context, response["Status"], response["Data"], event["LogicalResourceId"])
|
|
448
|
-
|
|
449
|
-
{{ addon_config.prefix }}ApplicationUser:
|
|
450
|
-
Type: 'Custom::{{ addon_config.prefix }}ApplicationUser'
|
|
451
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
452
|
-
UpdateReplacePolicy: Retain
|
|
453
|
-
Properties:
|
|
454
|
-
ServiceToken: !GetAtt '{{ addon_config.prefix }}LambdaFunction.Arn'
|
|
455
|
-
CopilotApplication: !Sub "${App}"
|
|
456
|
-
CopilotEnvironment: !Sub "${Env}"
|
|
457
|
-
MasterUserSecret: !Ref {{ addon_config.prefix }}RDSSecret
|
|
458
|
-
SecretDescription: !Sub RDS application user secret for ${AWS::StackName}
|
|
459
|
-
SecretName: !Sub '/copilot/${App}/${Env}/secrets/{{ addon_config.name|upper|replace("-", "_") }}_APPLICATION_USER'
|
|
460
|
-
DefaultPublicRoute: !Ref DefaultPublicRoute
|
|
461
|
-
InternetGateway: !Ref InternetGateway
|
|
462
|
-
InternetGatewayAttachment: !Ref InternetGatewayAttachment
|
|
463
|
-
PublicRouteTable: !Ref PublicRouteTable
|
|
464
|
-
PublicSubnet1RouteTableAssociation: !Ref PublicSubnet1RouteTableAssociation
|
|
465
|
-
PublicSubnet2RouteTableAssociation: !Ref PublicSubnet2RouteTableAssociation
|
|
466
|
-
Username: 'application_user'
|
|
467
|
-
Permissions:
|
|
468
|
-
- 'SELECT'
|
|
469
|
-
- 'INSERT'
|
|
470
|
-
- 'UPDATE'
|
|
471
|
-
- 'DELETE'
|
|
472
|
-
- 'TRIGGER'
|
|
473
|
-
# Resource based metadata block to ignore reference to resources in other addon templates. Do not remove.
|
|
474
|
-
Metadata:
|
|
475
|
-
cfn-lint:
|
|
476
|
-
config:
|
|
477
|
-
ignore_checks:
|
|
478
|
-
# https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/rules.md
|
|
479
|
-
- E3005
|
|
480
|
-
DependsOn:
|
|
481
|
-
- VpcEndpoint
|
|
482
|
-
- {{ addon_config.prefix }}DBInstance
|
|
483
|
-
- AdditionalNatGateway1
|
|
484
|
-
- AdditionalNatGateway2
|
|
485
|
-
- AdditionalPrivateRoute1
|
|
486
|
-
- AdditionalPrivateRouteTable1
|
|
487
|
-
- AdditionalPrivateRouteTable1Association
|
|
488
|
-
- AdditionalPrivateRoute2
|
|
489
|
-
- AdditionalPrivateRouteTable2
|
|
490
|
-
- AdditionalPrivateRouteTable2Association
|
|
491
|
-
- {{ addon_config.prefix }}SecretRDSAttachment
|
|
492
|
-
- {{ addon_config.prefix }}DBIngress
|
|
493
|
-
- {{ addon_config.prefix }}SecretsManagerIngress
|
|
494
|
-
- {{ addon_config.prefix }}LambdaIngress
|
|
495
|
-
- {{ addon_config.prefix }}SecretsManagerEgress
|
|
496
|
-
- {{ addon_config.prefix }}LambdaEgress
|
|
497
|
-
- {{ addon_config.prefix }}HTTPSEgress
|
|
498
|
-
- {{ addon_config.prefix }}KeyAlias
|
|
499
|
-
|
|
500
|
-
{{ addon_config.prefix }}ReadOnlyUser:
|
|
501
|
-
Type: 'Custom::{{ addon_config.prefix }}ReadOnlyUser'
|
|
502
|
-
DeletionPolicy: !FindInMap [{{ addon_config.prefix }}EnvironmentConfigMap, !Ref Env, DeletionPolicy]
|
|
503
|
-
UpdateReplacePolicy: Retain
|
|
504
|
-
Properties:
|
|
505
|
-
ServiceToken: !GetAtt '{{ addon_config.prefix }}LambdaFunction.Arn'
|
|
506
|
-
CopilotApplication: !Sub "${App}"
|
|
507
|
-
CopilotEnvironment: !Sub "${Env}"
|
|
508
|
-
MasterUserSecret: !Ref {{ addon_config.prefix }}RDSSecret
|
|
509
|
-
SecretDescription: !Sub RDS application user secret for ${AWS::StackName}
|
|
510
|
-
SecretName: !Sub '/copilot/${App}/${Env}/secrets/{{ addon_config.name|upper|replace("-", "_") }}_READ_ONLY_USER'
|
|
511
|
-
DefaultPublicRoute: !Ref DefaultPublicRoute
|
|
512
|
-
InternetGateway: !Ref InternetGateway
|
|
513
|
-
InternetGatewayAttachment: !Ref InternetGatewayAttachment
|
|
514
|
-
PublicRouteTable: !Ref PublicRouteTable
|
|
515
|
-
PublicSubnet1RouteTableAssociation: !Ref PublicSubnet1RouteTableAssociation
|
|
516
|
-
PublicSubnet2RouteTableAssociation: !Ref PublicSubnet2RouteTableAssociation
|
|
517
|
-
Username: 'read_only_user'
|
|
518
|
-
Permissions:
|
|
519
|
-
- 'SELECT'
|
|
520
|
-
# Resource based metadata block to ignore reference to resources in other addon templates. Do not remove.
|
|
521
|
-
Metadata:
|
|
522
|
-
cfn-lint:
|
|
523
|
-
config:
|
|
524
|
-
ignore_checks:
|
|
525
|
-
# https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/rules.md
|
|
526
|
-
- E3005
|
|
527
|
-
DependsOn:
|
|
528
|
-
- VpcEndpoint
|
|
529
|
-
- {{ addon_config.prefix }}DBInstance
|
|
530
|
-
- AdditionalNatGateway1
|
|
531
|
-
- AdditionalNatGateway2
|
|
532
|
-
- AdditionalPrivateRoute1
|
|
533
|
-
- AdditionalPrivateRouteTable1
|
|
534
|
-
- AdditionalPrivateRouteTable1Association
|
|
535
|
-
- AdditionalPrivateRoute2
|
|
536
|
-
- AdditionalPrivateRouteTable2
|
|
537
|
-
- AdditionalPrivateRouteTable2Association
|
|
538
|
-
- {{ addon_config.prefix }}SecretRDSAttachment
|
|
539
|
-
- {{ addon_config.prefix }}DBIngress
|
|
540
|
-
- {{ addon_config.prefix }}SecretsManagerIngress
|
|
541
|
-
- {{ addon_config.prefix }}LambdaIngress
|
|
542
|
-
- {{ addon_config.prefix }}SecretsManagerEgress
|
|
543
|
-
- {{ addon_config.prefix }}LambdaEgress
|
|
544
|
-
- {{ addon_config.prefix }}HTTPSEgress
|
|
545
|
-
- {{ addon_config.prefix }}KeyAlias
|
|
546
|
-
|
|
547
|
-
{{ addon_config.prefix }}LambdaFunctionExecutionRole:
|
|
548
|
-
Type: AWS::IAM::Role
|
|
549
|
-
Properties:
|
|
550
|
-
RoleName: !Sub "${App}-${Env}-{{ addon_config.prefix }}-rds-user"
|
|
551
|
-
AssumeRolePolicyDocument:
|
|
552
|
-
Version: 2012-10-17
|
|
553
|
-
Statement:
|
|
554
|
-
- Effect: Allow
|
|
555
|
-
Action:
|
|
556
|
-
- 'sts:AssumeRole'
|
|
557
|
-
Principal:
|
|
558
|
-
Service:
|
|
559
|
-
- lambda.amazonaws.com
|
|
560
|
-
Policies:
|
|
561
|
-
- PolicyName: !Sub "${App}-${Env}-rds-user"
|
|
562
|
-
PolicyDocument:
|
|
563
|
-
Version: '2012-10-17'
|
|
564
|
-
Statement:
|
|
565
|
-
- Effect: Allow
|
|
566
|
-
Action:
|
|
567
|
-
- 'ec2:CreateNetworkInterface'
|
|
568
|
-
- 'ec2:DescribeNetworkInterfaces'
|
|
569
|
-
- 'ec2:DeleteNetworkInterface'
|
|
570
|
-
Resource:
|
|
571
|
-
- '*'
|
|
572
|
-
- Effect: Allow
|
|
573
|
-
Action:
|
|
574
|
-
- 'ssm:DeleteParameter'
|
|
575
|
-
- 'ssm:PutParameter'
|
|
576
|
-
- 'ssm:AddTagsToResource'
|
|
577
|
-
- 'kms:Decrypt'
|
|
578
|
-
Resource:
|
|
579
|
-
- '*'
|
|
580
|
-
- Effect: Allow
|
|
581
|
-
Action:
|
|
582
|
-
- 'secretsmanager:DescribeSecret'
|
|
583
|
-
- 'secretsmanager:GetRandomPassword'
|
|
584
|
-
- 'secretsmanager:GetSecretValue'
|
|
585
|
-
Resource:
|
|
586
|
-
- '*'
|
|
587
|
-
- Effect: Allow
|
|
588
|
-
Action:
|
|
589
|
-
- 'logs:CreateLogGroup'
|
|
590
|
-
- 'logs:CreateLogStream'
|
|
591
|
-
- 'logs:PutLogEvents'
|
|
592
|
-
Resource: 'arn:aws:logs:*:*:*'
|
|
593
|
-
|
|
594
|
-
{{ addon_config.prefix }}SubscriptionFilter:
|
|
595
|
-
Type: AWS::Logs::SubscriptionFilter
|
|
596
|
-
DependsOn:
|
|
597
|
-
- {{ addon_config.prefix }}DBInstance
|
|
598
|
-
Properties:
|
|
599
|
-
RoleArn: !Sub 'arn:aws:iam::${AWS::AccountId}:role/CWLtoSubscriptionFilterRole'
|
|
600
|
-
LogGroupName: !Sub '/aws/rds/instance/${{ '{' }}{{ addon_config.prefix }}DBInstance}/postgresql'
|
|
601
|
-
FilterName: !Sub '/aws/rds/instance/${App}/${Env}/${{ '{' }}{{ addon_config.prefix }}DBInstance}/postgresql'
|
|
602
|
-
FilterPattern: ''
|
|
603
|
-
DestinationArn: !If [{{ addon_config.prefix }}CreateProdSubFilter, '{{ log_destination.prod }}', '{{ log_destination.dev }}']
|