@percepta/create 3.6.2 → 3.6.3
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.
- package/README.md +37 -6
- package/dist/{git-ops-C2CIjuce.js → git-ops-BD7JNnal.js} +1 -1
- package/dist/{git-ops-C2CIjuce.js.map → git-ops-BD7JNnal.js.map} +1 -1
- package/dist/github-RCIMUq70.js +131 -0
- package/dist/github-RCIMUq70.js.map +1 -0
- package/dist/index.js +63 -122
- package/dist/index.js.map +1 -1
- package/dist/{init-sI9aIrkU.js → init-COp0nGdk.js} +4 -2
- package/dist/{init-sI9aIrkU.js.map → init-COp0nGdk.js.map} +1 -1
- package/dist/manifest-CqIDnbgs.js +58 -0
- package/dist/manifest-CqIDnbgs.js.map +1 -0
- package/dist/register-app-C7ZBpAaZ.js +103 -0
- package/dist/register-app-C7ZBpAaZ.js.map +1 -0
- package/dist/register-os-blueprint-DGjBUZYa.js +90 -0
- package/dist/register-os-blueprint-DGjBUZYa.js.map +1 -0
- package/dist/{status-CKe4aKso.js → status-BXYaQ4a2.js} +3 -3
- package/dist/{status-CKe4aKso.js.map → status-BXYaQ4a2.js.map} +1 -1
- package/dist/{sync-D1vkoofl.js → sync-BayU4w1j.js} +3 -3
- package/dist/{sync-D1vkoofl.js.map → sync-BayU4w1j.js.map} +1 -1
- package/dist/template-versions-CEIP9vhl.js +35 -0
- package/dist/template-versions-CEIP9vhl.js.map +1 -0
- package/dist/{upstream-gUHLWSR1.js → upstream-CZEzLrS4.js} +3 -3
- package/dist/{upstream-gUHLWSR1.js.map → upstream-CZEzLrS4.js.map} +1 -1
- package/dist/validate-dssldJAj.js +14 -0
- package/dist/validate-dssldJAj.js.map +1 -0
- package/package.json +1 -1
- package/template-versions.json +2 -2
- package/templates/infra/os.blueprint.yaml.template +138 -0
- package/templates/monorepo/README.md +41 -3
- package/templates/monorepo/auth/README.md +6 -3
- package/templates/monorepo/auth/package.json +2 -4
- package/templates/monorepo/auth/src/config/database.ts +1 -1
- package/templates/{webapp → monorepo}/docker-compose.yml +2 -2
- package/templates/monorepo/package.json.template +5 -2
- package/templates/monorepo/scripts/setup-local-databases.mjs +183 -0
- package/templates/webapp/AGENTS.md +13 -20
- package/templates/webapp/README.md +32 -36
- package/templates/webapp/agent-skills/database.md +21 -21
- package/templates/webapp/agent-skills/langfuse.md +7 -7
- package/templates/webapp/agent-skills/llm.md +4 -2
- package/templates/webapp/agent-skills/oneshot.md +7 -6
- package/templates/webapp/agent-skills/ryvn.md +12 -16
- package/templates/webapp/deploy/README.md +10 -51
- package/templates/webapp/drizzle.config.ts +2 -23
- package/templates/webapp/env.example.template +8 -14
- package/templates/webapp/package.json.template +5 -12
- package/templates/webapp/scripts/start.sh +12 -16
- package/templates/webapp/src/config/getEnvConfig.ts +4 -10
- package/templates/webapp/src/drizzle/db.ts +6 -21
- package/templates/webapp/src/startup-checks.ts +28 -7
- package/templates/monorepo/auth/scripts/setup-database.ts +0 -11
- package/templates/webapp/.github/workflows/__APP_NAME__-terraform-ryvn-release.yaml +0 -92
- package/templates/webapp/agent-skills/deploy.md +0 -92
- package/templates/webapp/deploy/ryvn/__APP_NAME__-terraform.service.yaml +0 -10
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml +0 -11
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +0 -154
- package/templates/webapp/terraform/README.md +0 -147
- package/templates/webapp/terraform/deploy.sh +0 -97
- package/templates/webapp/terraform/main.tf +0 -101
- package/templates/webapp/terraform/modules/cloudtrail/main.tf +0 -27
- package/templates/webapp/terraform/modules/cloudtrail/outputs.tf +0 -10
- package/templates/webapp/terraform/modules/cloudtrail/variables.tf +0 -15
- package/templates/webapp/terraform/modules/networking/main.tf +0 -118
- package/templates/webapp/terraform/modules/networking/outputs.tf +0 -38
- package/templates/webapp/terraform/modules/networking/variables.tf +0 -24
- package/templates/webapp/terraform/modules/rds/main.tf +0 -227
- package/templates/webapp/terraform/modules/rds/outputs.tf +0 -73
- package/templates/webapp/terraform/modules/rds/variables.tf +0 -61
- package/templates/webapp/terraform/modules/s3-logging/main.tf +0 -148
- package/templates/webapp/terraform/modules/s3-logging/outputs.tf +0 -10
- package/templates/webapp/terraform/modules/s3-logging/variables.tf +0 -16
- package/templates/webapp/terraform/modules/secrets/main.tf +0 -39
- package/templates/webapp/terraform/modules/secrets/outputs.tf +0 -9
- package/templates/webapp/terraform/modules/secrets/variables.tf +0 -51
- package/templates/webapp/terraform/outputs.tf +0 -102
- package/templates/webapp/terraform/providers.tf +0 -32
- package/templates/webapp/terraform/schema/main.tf +0 -4
- package/templates/webapp/terraform/schema/outputs.tf +0 -9
- package/templates/webapp/terraform/schema/variables.tf +0 -19
- package/templates/webapp/terraform/schema/versions.tf +0 -38
- package/templates/webapp/terraform/terraform.tfvars.example +0 -65
- package/templates/webapp/terraform/variables.tf +0 -129
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
data "aws_eks_cluster" "cluster" {
|
|
2
|
-
name = var.cluster_name
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
data "aws_iam_openid_connect_provider" "cluster_oidc_provider" {
|
|
6
|
-
url = data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
################################################################################
|
|
10
|
-
# IAM Role for Application Service Account
|
|
11
|
-
################################################################################
|
|
12
|
-
|
|
13
|
-
data "aws_iam_policy_document" "app_assume_role_policy" {
|
|
14
|
-
statement {
|
|
15
|
-
actions = ["sts:AssumeRoleWithWebIdentity"]
|
|
16
|
-
|
|
17
|
-
principals {
|
|
18
|
-
type = "Federated"
|
|
19
|
-
identifiers = [data.aws_iam_openid_connect_provider.cluster_oidc_provider.arn]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
condition {
|
|
23
|
-
test = "StringEquals"
|
|
24
|
-
variable = "${trimsuffix(replace(data.aws_iam_openid_connect_provider.cluster_oidc_provider.url, "https://", ""), "/")}:sub"
|
|
25
|
-
values = ["system:serviceaccount:${var.namespace}:${var.kubernetes_service_account}"]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
condition {
|
|
29
|
-
test = "StringEquals"
|
|
30
|
-
variable = "${trimsuffix(replace(data.aws_iam_openid_connect_provider.cluster_oidc_provider.url, "https://", ""), "/")}:aud"
|
|
31
|
-
values = ["sts.amazonaws.com"]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
resource "aws_iam_role" "app_service_account_role" {
|
|
37
|
-
name = "__APP_NAME_UPPER__-App-Role-${var.name}-${var.environment}"
|
|
38
|
-
assume_role_policy = data.aws_iam_policy_document.app_assume_role_policy.json
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# Networking Module - Get VPC and subnet information
|
|
42
|
-
module "networking" {
|
|
43
|
-
source = "./modules/networking"
|
|
44
|
-
|
|
45
|
-
vpc_id = var.vpc_id
|
|
46
|
-
subnet_ids = var.subnet_ids
|
|
47
|
-
subnet_tags = var.subnet_tags
|
|
48
|
-
ingress_cidr_blocks = var.ingress_cidr_blocks
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# RDS Module - Create or use existing RDS cluster
|
|
52
|
-
module "rds" {
|
|
53
|
-
source = "./modules/rds"
|
|
54
|
-
|
|
55
|
-
name = var.name
|
|
56
|
-
environment = var.environment
|
|
57
|
-
existing_cluster_name = var.existing_rds_cluster_name
|
|
58
|
-
create_new_cluster = var.create_new_rds
|
|
59
|
-
vpc_id = var.vpc_id
|
|
60
|
-
subnet_ids = module.networking.subnet_ids
|
|
61
|
-
engine_version = var.rds_engine_version
|
|
62
|
-
port = var.rds_port
|
|
63
|
-
instance_class = var.rds_instance_class
|
|
64
|
-
edw_allowed_principals = var.edw_allowed_principals
|
|
65
|
-
edw_vpc_cidr_blocks = var.edw_vpc_cidr_blocks
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
# S3 Logging Module - Create S3 bucket for access logs
|
|
69
|
-
module "s3_logging" {
|
|
70
|
-
source = "./modules/s3-logging"
|
|
71
|
-
|
|
72
|
-
name = var.name
|
|
73
|
-
environment = var.environment
|
|
74
|
-
s3_expiration_days = var.s3_bucket_expiration_days
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
# CloudTrail Module - Create CloudTrail trail for S3 data event logging
|
|
78
|
-
module "cloudtrail" {
|
|
79
|
-
source = "./modules/cloudtrail"
|
|
80
|
-
|
|
81
|
-
name = var.name
|
|
82
|
-
environment = var.environment
|
|
83
|
-
logging_bucket_name = module.s3_logging.s3_bucket_name
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# Secrets Module - Create EKS secrets for all credentials
|
|
87
|
-
module "secrets" {
|
|
88
|
-
source = "./modules/secrets"
|
|
89
|
-
|
|
90
|
-
namespace = var.namespace
|
|
91
|
-
cluster_name = var.cluster_name
|
|
92
|
-
|
|
93
|
-
# Database credentials
|
|
94
|
-
db_host = module.rds.host
|
|
95
|
-
db_port = module.rds.port
|
|
96
|
-
db_name = module.rds.database_name
|
|
97
|
-
db_username = module.rds.username
|
|
98
|
-
db_password = module.rds.password
|
|
99
|
-
db_ssl_cert = module.rds.ssl_cert
|
|
100
|
-
db_url = module.rds.connection_url
|
|
101
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
################################################################################
|
|
2
|
-
# CloudTrail Trail
|
|
3
|
-
################################################################################
|
|
4
|
-
|
|
5
|
-
# Note: The S3 bucket policy for CloudTrail is managed in the s3-logging module
|
|
6
|
-
# to avoid conflicts with multiple bucket policy resources
|
|
7
|
-
resource "aws_cloudtrail" "trail" {
|
|
8
|
-
name = "${var.name}-trail-${var.environment}"
|
|
9
|
-
s3_bucket_name = var.logging_bucket_name
|
|
10
|
-
s3_key_prefix = "cloudtrail/"
|
|
11
|
-
include_global_service_events = true
|
|
12
|
-
is_multi_region_trail = true
|
|
13
|
-
enable_logging = true
|
|
14
|
-
enable_log_file_validation = true
|
|
15
|
-
|
|
16
|
-
event_selector {
|
|
17
|
-
read_write_type = "All"
|
|
18
|
-
include_management_events = true
|
|
19
|
-
exclude_management_event_sources = []
|
|
20
|
-
|
|
21
|
-
data_resource {
|
|
22
|
-
type = "AWS::S3::Object"
|
|
23
|
-
values = ["arn:aws:s3"]
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
variable "name" {
|
|
2
|
-
description = "Base name for resources"
|
|
3
|
-
type = string
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
variable "environment" {
|
|
7
|
-
description = "Environment name (e.g. dev, staging, prod)"
|
|
8
|
-
type = string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
variable "logging_bucket_name" {
|
|
12
|
-
description = "Name of the S3 bucket to store CloudTrail logs"
|
|
13
|
-
type = string
|
|
14
|
-
}
|
|
15
|
-
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
data "aws_vpc" "vpc" {
|
|
2
|
-
id = var.vpc_id
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
# Get the private subnets assigned to the vpc
|
|
6
|
-
data "aws_subnets" "subnets" {
|
|
7
|
-
filter {
|
|
8
|
-
name = "vpc-id"
|
|
9
|
-
values = [data.aws_vpc.vpc.id]
|
|
10
|
-
}
|
|
11
|
-
tags = var.subnet_tags
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
data "aws_subnet" "subnet" {
|
|
15
|
-
count = length(local.subnet_ids)
|
|
16
|
-
id = local.subnet_ids[count.index]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
locals {
|
|
20
|
-
subnet_ids = var.subnet_ids != null ? var.subnet_ids : data.aws_subnets.subnets.ids
|
|
21
|
-
vpc_cidr = data.aws_vpc.vpc.cidr_block
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
################################################################################
|
|
25
|
-
# Security Group for VPC Endpoints
|
|
26
|
-
################################################################################
|
|
27
|
-
|
|
28
|
-
resource "aws_security_group" "vpc_endpoints" {
|
|
29
|
-
name_prefix = "__APP_NAME__-vpc-endpoints-"
|
|
30
|
-
vpc_id = data.aws_vpc.vpc.id
|
|
31
|
-
description = "Security group for __APP_NAME_UPPER__ VPC endpoints"
|
|
32
|
-
|
|
33
|
-
ingress {
|
|
34
|
-
description = "HTTPS from VPC"
|
|
35
|
-
from_port = 443
|
|
36
|
-
to_port = 443
|
|
37
|
-
protocol = "tcp"
|
|
38
|
-
cidr_blocks = [data.aws_vpc.vpc.cidr_block]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
egress {
|
|
42
|
-
description = "All outbound traffic"
|
|
43
|
-
from_port = 0
|
|
44
|
-
to_port = 0
|
|
45
|
-
protocol = "-1"
|
|
46
|
-
cidr_blocks = ["0.0.0.0/0"]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
tags = {
|
|
50
|
-
Name = "__APP_NAME__-vpc-endpoints"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
################################################################################
|
|
55
|
-
# VPC Endpoints for AWS Services
|
|
56
|
-
################################################################################
|
|
57
|
-
|
|
58
|
-
# S3 VPC Endpoint (Gateway type for better performance and cost)
|
|
59
|
-
resource "aws_vpc_endpoint" "s3" {
|
|
60
|
-
vpc_id = data.aws_vpc.vpc.id
|
|
61
|
-
service_name = "com.amazonaws.${data.aws_region.current.name}.s3"
|
|
62
|
-
|
|
63
|
-
policy = jsonencode({
|
|
64
|
-
Version = "2012-10-17"
|
|
65
|
-
Statement = [
|
|
66
|
-
{
|
|
67
|
-
Effect = "Allow"
|
|
68
|
-
Principal = "*"
|
|
69
|
-
Action = [
|
|
70
|
-
"s3:GetObject",
|
|
71
|
-
"s3:PutObject",
|
|
72
|
-
"s3:DeleteObject",
|
|
73
|
-
"s3:ListBucket"
|
|
74
|
-
]
|
|
75
|
-
Resource = "*"
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
tags = {
|
|
81
|
-
Name = "__APP_NAME__-s3-endpoint"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
# Get current AWS region
|
|
86
|
-
data "aws_region" "current" {}
|
|
87
|
-
|
|
88
|
-
################################################################################
|
|
89
|
-
# Security Group for Ingress CIDR blocks
|
|
90
|
-
################################################################################
|
|
91
|
-
|
|
92
|
-
resource "aws_security_group" "ingress" {
|
|
93
|
-
for_each = var.ingress_cidr_blocks
|
|
94
|
-
|
|
95
|
-
name_prefix = "__APP_NAME__-${each.key}-"
|
|
96
|
-
vpc_id = data.aws_vpc.vpc.id
|
|
97
|
-
description = "Security group for ${each.key}"
|
|
98
|
-
|
|
99
|
-
ingress {
|
|
100
|
-
description = "All TCP from specified CIDRs"
|
|
101
|
-
from_port = 0
|
|
102
|
-
to_port = 65535
|
|
103
|
-
protocol = "tcp"
|
|
104
|
-
cidr_blocks = each.value
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
egress {
|
|
108
|
-
description = "All outbound traffic"
|
|
109
|
-
from_port = 0
|
|
110
|
-
to_port = 0
|
|
111
|
-
protocol = "-1"
|
|
112
|
-
cidr_blocks = ["0.0.0.0/0"]
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
tags = {
|
|
116
|
-
Name = "__APP_NAME__-${each.key}"
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
output "vpc_id" {
|
|
2
|
-
description = "VPC ID"
|
|
3
|
-
value = data.aws_vpc.vpc.id
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
output "vpc_cidr" {
|
|
7
|
-
description = "VPC CIDR block"
|
|
8
|
-
value = local.vpc_cidr
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
output "subnet_ids" {
|
|
12
|
-
description = "List of subnet IDs"
|
|
13
|
-
value = local.subnet_ids
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
output "availability_zones" {
|
|
17
|
-
description = "List of availability zones for the subnets"
|
|
18
|
-
value = data.aws_subnet.subnet[*].availability_zone
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
################################################################################
|
|
22
|
-
# VPC Endpoint Outputs
|
|
23
|
-
################################################################################
|
|
24
|
-
|
|
25
|
-
output "vpc_endpoint_security_group_id" {
|
|
26
|
-
description = "Security group ID for VPC endpoints"
|
|
27
|
-
value = aws_security_group.vpc_endpoints.id
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
output "s3_vpc_endpoint_id" {
|
|
31
|
-
description = "S3 VPC endpoint ID"
|
|
32
|
-
value = aws_vpc_endpoint.s3.id
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
output "ingress_cidr_blocks" {
|
|
36
|
-
description = "Map of dynamically created security groups for ingress"
|
|
37
|
-
value = aws_security_group.ingress
|
|
38
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
variable "vpc_id" {
|
|
2
|
-
description = "VPC ID where resources will be deployed"
|
|
3
|
-
type = string
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
variable "subnet_ids" {
|
|
7
|
-
description = "List of subnet IDs for resources"
|
|
8
|
-
type = list(string)
|
|
9
|
-
default = null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
variable "subnet_tags" {
|
|
13
|
-
description = "Tags for subnet selection"
|
|
14
|
-
type = map(string)
|
|
15
|
-
default = {
|
|
16
|
-
"kubernetes.io/role/internal-elb" = "1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
variable "ingress_cidr_blocks" {
|
|
21
|
-
description = "A map of security group names to a list of CIDR blocks to allow access from."
|
|
22
|
-
type = map(list(string))
|
|
23
|
-
default = {}
|
|
24
|
-
}
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
data "aws_region" "current" {}
|
|
2
|
-
|
|
3
|
-
data "http" "rds_ca" {
|
|
4
|
-
url = "https://truststore.pki.rds.amazonaws.com/${data.aws_region.current.name}/${data.aws_region.current.name}-bundle.pem"
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
data "aws_vpc" "vpc" {
|
|
8
|
-
id = var.vpc_id
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
data "aws_subnet" "subnet" {
|
|
12
|
-
count = length(var.subnet_ids)
|
|
13
|
-
id = var.subnet_ids[count.index]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
# Check if existing cluster exists
|
|
17
|
-
data "aws_rds_cluster" "existing" {
|
|
18
|
-
count = var.existing_cluster_name != null ? 1 : 0
|
|
19
|
-
cluster_identifier = var.existing_cluster_name
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
resource "random_pet" "name" {
|
|
23
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
24
|
-
length = 2
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
resource "random_password" "master_password" {
|
|
28
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
29
|
-
length = 16
|
|
30
|
-
special = true
|
|
31
|
-
override_special = "_!%^"
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
locals {
|
|
36
|
-
cluster_name = var.existing_cluster_name != null ? var.existing_cluster_name : (var.create_new_cluster ? "${var.name}-${random_pet.name[0].id}" : null)
|
|
37
|
-
|
|
38
|
-
# Use existing cluster details if available, otherwise use new cluster details
|
|
39
|
-
cluster_endpoint = var.existing_cluster_name != null ? data.aws_rds_cluster.existing[0].endpoint : (var.create_new_cluster ? aws_rds_cluster.rds[0].endpoint : null)
|
|
40
|
-
cluster_port = var.existing_cluster_name != null ? data.aws_rds_cluster.existing[0].port : (var.create_new_cluster ? aws_rds_cluster.rds[0].port : null)
|
|
41
|
-
master_username = var.existing_cluster_name != null ? data.aws_rds_cluster.existing[0].master_username : (var.create_new_cluster ? aws_rds_cluster.rds[0].master_username : null)
|
|
42
|
-
master_password = var.existing_cluster_name != null ? null : (var.create_new_cluster ? random_password.master_password[0].result : null)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# Security group for new RDS cluster
|
|
46
|
-
resource "aws_security_group" "security_group" {
|
|
47
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
48
|
-
name = "rds-__APP_NAME__-${random_pet.name[0].id}"
|
|
49
|
-
description = "Security group for __APP_NAME_UPPER__ RDS ${random_pet.name[0].id}"
|
|
50
|
-
vpc_id = data.aws_vpc.vpc.id
|
|
51
|
-
|
|
52
|
-
ingress {
|
|
53
|
-
description = "Allow Postgres from VPC"
|
|
54
|
-
from_port = var.port
|
|
55
|
-
to_port = var.port
|
|
56
|
-
protocol = "tcp"
|
|
57
|
-
cidr_blocks = [data.aws_vpc.vpc.cidr_block]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
egress {
|
|
61
|
-
from_port = 0
|
|
62
|
-
to_port = 0
|
|
63
|
-
protocol = "-1"
|
|
64
|
-
cidr_blocks = ["0.0.0.0/0"]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
# Subnet group for new RDS cluster
|
|
69
|
-
resource "aws_db_subnet_group" "subnet_group" {
|
|
70
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
71
|
-
name = "rds-__APP_NAME__-${random_pet.name[0].id}"
|
|
72
|
-
description = "Subnet group for __APP_NAME_UPPER__ RDS ${random_pet.name[0].id}"
|
|
73
|
-
subnet_ids = var.subnet_ids
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
# New RDS cluster
|
|
77
|
-
resource "aws_rds_cluster" "rds" {
|
|
78
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
79
|
-
cluster_identifier = local.cluster_name
|
|
80
|
-
engine = "aurora-postgresql"
|
|
81
|
-
engine_mode = "provisioned"
|
|
82
|
-
engine_version = var.engine_version
|
|
83
|
-
vpc_security_group_ids = [aws_security_group.security_group[0].id]
|
|
84
|
-
db_subnet_group_name = aws_db_subnet_group.subnet_group[0].name
|
|
85
|
-
availability_zones = slice(data.aws_subnet.subnet[*].availability_zone, 0, min(3, length(data.aws_subnet.subnet)))
|
|
86
|
-
database_name = "__DB_NAME__"
|
|
87
|
-
port = var.port
|
|
88
|
-
master_username = "__APP_NAME_SNAKE___admin"
|
|
89
|
-
master_password = random_password.master_password[0].result
|
|
90
|
-
storage_encrypted = true
|
|
91
|
-
backup_retention_period = 5
|
|
92
|
-
preferred_backup_window = "07:00-09:00"
|
|
93
|
-
|
|
94
|
-
skip_final_snapshot = true
|
|
95
|
-
enable_http_endpoint = true
|
|
96
|
-
|
|
97
|
-
serverlessv2_scaling_configuration {
|
|
98
|
-
max_capacity = 1.0
|
|
99
|
-
min_capacity = 0.0
|
|
100
|
-
seconds_until_auto_pause = 3600
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# RDS cluster instance for new cluster
|
|
105
|
-
resource "aws_rds_cluster_instance" "instance" {
|
|
106
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
107
|
-
identifier = "${local.cluster_name}-instance-${count.index}"
|
|
108
|
-
cluster_identifier = aws_rds_cluster.rds[0].id
|
|
109
|
-
instance_class = var.instance_class
|
|
110
|
-
engine = aws_rds_cluster.rds[0].engine
|
|
111
|
-
engine_version = aws_rds_cluster.rds[0].engine_version
|
|
112
|
-
publicly_accessible = false
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
# Store master password in AWS Secrets Manager for new cluster
|
|
116
|
-
resource "aws_secretsmanager_secret" "master_password" {
|
|
117
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
118
|
-
name_prefix = "rds-__APP_NAME__-master-password-${random_pet.name[0].id}-"
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
resource "aws_secretsmanager_secret_version" "master_password" {
|
|
122
|
-
count = var.create_new_cluster && var.existing_cluster_name == null ? 1 : 0
|
|
123
|
-
secret_id = aws_secretsmanager_secret.master_password[0].id
|
|
124
|
-
secret_string = random_password.master_password[0].result
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
################################################################################
|
|
128
|
-
# EDW Readonly User Resources
|
|
129
|
-
################################################################################
|
|
130
|
-
|
|
131
|
-
# Generate secure password for readonly user
|
|
132
|
-
resource "random_password" "readonly_user_password" {
|
|
133
|
-
length = 32
|
|
134
|
-
special = true
|
|
135
|
-
# Use PostgreSQL-safe special characters
|
|
136
|
-
override_special = "!#$%&*()-_=+[]{}<>:?"
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
# Store readonly user credentials in Secrets Manager
|
|
140
|
-
resource "aws_secretsmanager_secret" "readonly_user_credentials" {
|
|
141
|
-
name_prefix = "rds-__APP_NAME__-readonly-${var.name}-${var.environment}-"
|
|
142
|
-
description = "Readonly database credentials for EDW access to __APP_NAME_UPPER__ database"
|
|
143
|
-
|
|
144
|
-
tags = {
|
|
145
|
-
Name = "__APP_NAME__-readonly-credentials"
|
|
146
|
-
Environment = var.environment
|
|
147
|
-
Purpose = "EDW"
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
resource "aws_secretsmanager_secret_version" "readonly_user_credentials" {
|
|
152
|
-
secret_id = aws_secretsmanager_secret.readonly_user_credentials.id
|
|
153
|
-
secret_string = jsonencode({
|
|
154
|
-
username = "__APP_NAME_SNAKE___readonly"
|
|
155
|
-
password = random_password.readonly_user_password.result
|
|
156
|
-
host = local.cluster_endpoint
|
|
157
|
-
port = local.cluster_port
|
|
158
|
-
database = "__DB_NAME__"
|
|
159
|
-
engine = "postgres"
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
# Cross-account IAM role for EDW to assume
|
|
164
|
-
resource "aws_iam_role" "edw_secret_reader_role" {
|
|
165
|
-
count = length(var.edw_allowed_principals) > 0 ? 1 : 0
|
|
166
|
-
name = "__APP_NAME_UPPER__-EDW-SecretReader-${var.name}-${var.environment}"
|
|
167
|
-
|
|
168
|
-
assume_role_policy = jsonencode({
|
|
169
|
-
Version = "2012-10-17"
|
|
170
|
-
Statement = [
|
|
171
|
-
{
|
|
172
|
-
Effect = "Allow"
|
|
173
|
-
Principal = {
|
|
174
|
-
AWS = var.edw_allowed_principals
|
|
175
|
-
}
|
|
176
|
-
Action = "sts:AssumeRole"
|
|
177
|
-
}
|
|
178
|
-
]
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
tags = {
|
|
182
|
-
Name = "__APP_NAME__-edw-secret-reader"
|
|
183
|
-
Environment = var.environment
|
|
184
|
-
Purpose = "EDW"
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
# IAM policy to allow reading the readonly credentials secret
|
|
189
|
-
resource "aws_iam_policy" "edw_secret_reader_policy" {
|
|
190
|
-
count = length(var.edw_allowed_principals) > 0 ? 1 : 0
|
|
191
|
-
name = "__APP_NAME_UPPER__-EDW-SecretReader-Policy-${var.name}-${var.environment}"
|
|
192
|
-
description = "Allows EDW to read __APP_NAME_UPPER__ readonly database credentials from Secrets Manager"
|
|
193
|
-
|
|
194
|
-
policy = jsonencode({
|
|
195
|
-
Version = "2012-10-17"
|
|
196
|
-
Statement = [
|
|
197
|
-
{
|
|
198
|
-
Effect = "Allow"
|
|
199
|
-
Action = [
|
|
200
|
-
"secretsmanager:GetSecretValue",
|
|
201
|
-
"secretsmanager:DescribeSecret"
|
|
202
|
-
]
|
|
203
|
-
Resource = aws_secretsmanager_secret.readonly_user_credentials.arn
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
resource "aws_iam_role_policy_attachment" "edw_secret_reader_attach" {
|
|
210
|
-
count = length(var.edw_allowed_principals) > 0 ? 1 : 0
|
|
211
|
-
role = aws_iam_role.edw_secret_reader_role[0].name
|
|
212
|
-
policy_arn = aws_iam_policy.edw_secret_reader_policy[0].arn
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
# Add ingress rule to security group for EDW VPC CIDR blocks
|
|
216
|
-
resource "aws_security_group_rule" "edw_ingress" {
|
|
217
|
-
count = var.create_new_cluster && var.existing_cluster_name == null && length(var.edw_vpc_cidr_blocks) > 0 ? 1 : 0
|
|
218
|
-
type = "ingress"
|
|
219
|
-
description = "Allow Postgres from EDW VPC via VPC peering"
|
|
220
|
-
from_port = var.port
|
|
221
|
-
to_port = var.port
|
|
222
|
-
protocol = "tcp"
|
|
223
|
-
cidr_blocks = var.edw_vpc_cidr_blocks
|
|
224
|
-
security_group_id = aws_security_group.security_group[0].id
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
output "host" {
|
|
2
|
-
description = "RDS cluster endpoint"
|
|
3
|
-
value = local.cluster_endpoint
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
output "port" {
|
|
7
|
-
description = "RDS cluster port"
|
|
8
|
-
value = local.cluster_port
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
output "database_name" {
|
|
12
|
-
description = "Database name"
|
|
13
|
-
value = "__DB_NAME__"
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
output "username" {
|
|
17
|
-
description = "Database username (master user)"
|
|
18
|
-
value = local.master_username
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
output "password" {
|
|
22
|
-
description = "Database password (master user)"
|
|
23
|
-
value = local.master_password
|
|
24
|
-
sensitive = true
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
output "ssl_cert" {
|
|
28
|
-
description = "RDS CA certificate"
|
|
29
|
-
value = data.http.rds_ca.response_body
|
|
30
|
-
sensitive = true
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
output "connection_url" {
|
|
34
|
-
description = "PostgreSQL connection URL"
|
|
35
|
-
value = "postgresql://${local.master_username}:${local.master_password}@${local.cluster_endpoint}:${local.cluster_port}/__DB_NAME__"
|
|
36
|
-
sensitive = true
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
output "cluster_name" {
|
|
40
|
-
description = "RDS cluster name"
|
|
41
|
-
value = local.cluster_name
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
output "master_username" {
|
|
45
|
-
description = "RDS master username (for new clusters only)"
|
|
46
|
-
value = local.master_username
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
output "master_password" {
|
|
50
|
-
description = "RDS master password (for new clusters only)"
|
|
51
|
-
value = local.master_password
|
|
52
|
-
sensitive = true
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
output "readonly_username" {
|
|
56
|
-
description = "Readonly database username for EDW access"
|
|
57
|
-
value = "__APP_NAME_SNAKE___readonly"
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
output "readonly_user_secret_arn" {
|
|
61
|
-
description = "ARN of the Secrets Manager secret containing readonly user credentials"
|
|
62
|
-
value = aws_secretsmanager_secret.readonly_user_credentials.arn
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
output "readonly_user_secret_name" {
|
|
66
|
-
description = "Name of the Secrets Manager secret containing readonly user credentials"
|
|
67
|
-
value = aws_secretsmanager_secret.readonly_user_credentials.name
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
output "readonly_user_secret_reader_role_arn" {
|
|
71
|
-
description = "ARN of the IAM role that EDW can assume to read the readonly credentials secret"
|
|
72
|
-
value = length(var.edw_allowed_principals) > 0 ? aws_iam_role.edw_secret_reader_role[0].arn : null
|
|
73
|
-
}
|