diff --git a/.header.md b/.header.md index 7b6479e..21dba43 100644 --- a/.header.md +++ b/.header.md @@ -83,8 +83,8 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal domain_name = "project-name-example.com" certificate_expiration_email = "example@example.com" s3_bucket_name = "project-name" - cluster_id = "" - cluster_secret = "" + namespace_id = "" + namespace_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` @@ -117,11 +117,7 @@ The internal name must match the name that you specify in the `environments_inte 4. Depending on your provider, update **External Domain Name Registrar** or **Route53 registered domain** with the *aws_route53_zone_name_servers* values. For more information, refer to [Configuring Amazon Route 53 as your DNS service](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring.html). -5. In the developer portal, choose **Cluster Manager**, then choose the **Customization** tab. Enable **External Secrets Store**. - -![Customization tab](https://raw.githubusercontent.com/aws-ia/terraform-aws-mendix-private-cloud/main/doc/deployment_guide/images/secrets-store.png) - -6. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. +5. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. ## Security @@ -206,6 +202,9 @@ In the Mendix Private Cloud portal, in the Cluster Manager, the status of your c ## Cleanup +Before cleaning up, make sure that you have deleted Mendix App environments. +Otherwise, you will need to manually remove some finalizers in the namespace and detach some roles from policies in AWS IAM. + To clean up your environment, run the following commands: ``` diff --git a/README.md b/README.md index aa3b939..f609f4f 100644 --- a/README.md +++ b/README.md @@ -84,8 +84,8 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal domain_name = "project-name-example.com" certificate_expiration_email = "example@example.com" s3_bucket_name = "project-name" - cluster_id = "" - cluster_secret = "" + namespace_id = "" + namespace_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` @@ -118,11 +118,7 @@ The internal name must match the name that you specify in the `environments_inte 4. Depending on your provider, update **External Domain Name Registrar** or **Route53 registered domain** with the *aws\_route53\_zone\_name\_servers* values. For more information, refer to [Configuring Amazon Route 53 as your DNS service](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring.html). -5. In the developer portal, choose **Cluster Manager**, then choose the **Customization** tab. Enable **External Secrets Store**. - -![Customization tab](https://raw.githubusercontent.com/aws-ia/terraform-aws-mendix-private-cloud/main/doc/deployment_guide/images/secrets-store.png) - -6. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. +5. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. ## Security @@ -207,6 +203,9 @@ In the Mendix Private Cloud portal, in the Cluster Manager, the status of your c ## Cleanup +Before cleaning up, make sure that you have deleted Mendix App environments. +Otherwise, you will need to manually remove some finalizers in the namespace and detach some roles from policies in AWS IAM. + To clean up your environment, run the following commands: ``` @@ -231,7 +230,7 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.14 | -| [aws](#requirement\_aws) | >= 4.35 | +| [aws](#requirement\_aws) | >= 5.10 | | [helm](#requirement\_helm) | >= 2.7.1 | | [kubectl](#requirement\_kubectl) | >= 1.14 | | [kubernetes](#requirement\_kubernetes) | >= 2.16.1 | @@ -242,9 +241,10 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.35 | +| [aws](#provider\_aws) | >= 5.10 | | [helm](#provider\_helm) | >= 2.7.1 | | [kubernetes](#provider\_kubernetes) | >= 2.16.1 | +| [random](#provider\_random) | >= 3.4.3 | ## Modules @@ -252,8 +252,8 @@ After you deploy this Partner Solution, confirm that your resources and services |------|--------|---------| | [container\_registry](#module\_container\_registry) | ./modules/container-registry | n/a | | [databases](#module\_databases) | ./modules/databases | n/a | -| [eks\_blueprints](#module\_eks\_blueprints) | github.com/aws-ia/terraform-aws-eks-blueprints | v4.28.0 | -| [eks\_blueprints\_kubernetes\_addons](#module\_eks\_blueprints\_kubernetes\_addons) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons | v4.28.0 | +| [eks\_blueprints](#module\_eks\_blueprints) | github.com/aws-ia/terraform-aws-eks-blueprints | v4.32.1 | +| [eks\_blueprints\_kubernetes\_addons](#module\_eks\_blueprints\_kubernetes\_addons) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons | v4.32.1 | | [file\_storage](#module\_file\_storage) | ./modules/file-storage | n/a | | [monitoring](#module\_monitoring) | ./modules/monitoring | n/a | | [vpc](#module\_vpc) | ./modules/vpc | n/a | @@ -263,9 +263,13 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Type | |------|------| | [aws_ebs_encryption_by_default.ebs_encryption](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_encryption_by_default) | resource | +| [aws_iam_policy.environment_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.provisioner_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.storage_provisioner_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_route53_zone.cluster_dns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | | [helm_release.mendix_installer](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [kubernetes_namespace.mendix](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | +| [random_string.random_eks_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_eks_cluster_auth.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster_auth) | data source | @@ -275,14 +279,16 @@ After you deploy this Partner Solution, confirm that your resources and services |------|-------------|------|---------|:--------:| | [aws\_region](#input\_aws\_region) | AWS Region name | `string` | n/a | yes | | [certificate\_expiration\_email](#input\_certificate\_expiration\_email) | Let's Encrypt certificate expiration email | `string` | n/a | yes | -| [cluster\_id](#input\_cluster\_id) | Mendix Private Cloud Cluster ID | `string` | n/a | yes | -| [cluster\_secret](#input\_cluster\_secret) | Mendix Private Cloud Cluster Secret | `string` | n/a | yes | | [domain\_name](#input\_domain\_name) | Domain name | `string` | n/a | yes | +| [namespace\_id](#input\_namespace\_id) | Mendix Private Cloud Namespace ID | `string` | n/a | yes | +| [namespace\_secret](#input\_namespace\_secret) | Mendix Private Cloud Namespace Secret | `string` | n/a | yes | | [s3\_bucket\_name](#input\_s3\_bucket\_name) | S3 bucket name | `string` | n/a | yes | | [allowed\_ips](#input\_allowed\_ips) | List of IP adresses allowed to access EKS cluster endpoint | `list(string)` |
[
"0.0.0.0/0"
]
| no | +| [eks\_cluster\_name\_prefix](#input\_eks\_cluster\_name\_prefix) | EKS name prefix for the new cluster | `string` | `"mendix-eks"` | no | | [eks\_node\_instance\_type](#input\_eks\_node\_instance\_type) | EKS instance type | `string` | `"t3.medium"` | no | | [environments\_internal\_names](#input\_environments\_internal\_names) | List of internal environments names | `list(string)` |
[
"app1"
]
| no | -| [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.10.0"` | no | +| [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.12.0"` | no | +| [postgres\_version](#input\_postgres\_version) | The version of Postgres that terraform would create. | `string` | `"14.8"` | no | ## Outputs diff --git a/charts/mendix-installer/templates/apps-secretproviderclass.yaml b/charts/mendix-installer/templates/apps-secretproviderclass.yaml deleted file mode 100644 index 06181c2..0000000 --- a/charts/mendix-installer/templates/apps-secretproviderclass.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- range $.Values.environmentsInternalNames }} ---- -apiVersion: secrets-store.csi.x-k8s.io/v1 -kind: SecretProviderClass -metadata: - name: {{ . }} - namespace: mendix - annotations: - privatecloud.mendix.com/environment-class: "true" -spec: - provider: aws - parameters: - objects: | - - objectName: "{{ $.Values.clusterName }}-{{ . }}-secrets" - objectType: secretsmanager - jmesPath: - - path: '"database-type"' - objectAlias: "database-type" - - path: '"database-jdbc-url"' - objectAlias: "database-jdbc-url" - - path: '"database-username"' - objectAlias: "database-username" - - path: '"database-password"' - objectAlias: "database-password" - - path: '"database-host"' - objectAlias: "database-host" - - path: '"database-name"' - objectAlias: "database-name" - - path: '"storage-service-name"' - objectAlias: "storage-service-name" - - path: '"storage-endpoint"' - objectAlias: "storage-endpoint" - - path: '"storage-bucket-name"' - objectAlias: "storage-bucket-name" -{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/templates/apps-serviceaccount.yaml b/charts/mendix-installer/templates/apps-serviceaccount.yaml deleted file mode 100644 index 660d0f4..0000000 --- a/charts/mendix-installer/templates/apps-serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- range $.Values.environmentsInternalNames }} ---- -apiVersion: v1 -automountServiceAccountToken: true -kind: ServiceAccount -metadata: - annotations: - eks.amazonaws.com/role-arn: arn:aws:iam::{{ $.Values.accountID }}:role/{{ $.Values.clusterName }}-app-role-{{ . }} - privatecloud.mendix.com/environment-account: "true" - name: {{ . }} - namespace: mendix -{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/templates/mendix-installer-configmap.yaml b/charts/mendix-installer/templates/mendix-installer-configmap.yaml index 813a7d9..b6c334f 100644 --- a/charts/mendix-installer/templates/mendix-installer-configmap.yaml +++ b/charts/mendix-installer/templates/mendix-installer-configmap.yaml @@ -6,10 +6,28 @@ metadata: data: mxpc-cli-installer-script: | #/bin/sh + wget https://cdn.mendix.com/mendix-for-private-cloud/mxpc-cli/mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz tar xvf mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz - ./mxpc-cli base-install --namespace mendix -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --clusterMode connected --clusterType generic - ./mxpc-cli apply-config -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --file mendix-installer-config-file/mendix-installer-config-file + ./mxpc-cli base-install --namespace mendix -i {{ .Values.namespaceID }} -s {{ .Values.namespaceSecret }} --clusterMode connected --clusterType generic --clusterTag="aws-reference-deployment" + + wget --output-document=custom.crt https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem + kubectl -n mendix create secret generic mendix-custom-tls --from-file=custom.crt=custom.crt + + ./mxpc-cli apply-config -i {{ .Values.namespaceID }} -s {{ .Values.namespaceSecret }} --file mendix-installer-config-file/mendix-installer-config-file + +{{- range $.Values.database_plans }} + ./mxpc-cli apply-config -i {{ $.Values.namespaceID }} -s {{ $.Values.namespaceSecret }} --file mendix-installer-config-db-{{ .name }}/mendix-installer-config-file + + export PGUSER={{ .user }} + export PGHOST={{ .host }} + export PGPASSWORD=$(cat mendix-rds-master-pass-{{ .name }}/rds-password) + + psql -c 'GRANT rds_iam TO {{ .user }};' + + kubectl -n mendix delete secret mendix-rds-master-pass-{{ .name }} +{{- end }} + kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"endpoint":{"ingress":{"annotations":{"cert-manager.io/cluster-issuer":"letsencrypt-prod"}}}}}' kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"endpoint":{"ingress":{"tlsSecretName":"tls-{{ .Values.appName }}"}}}}' kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"runtimeAutomountServiceAccountToken":true,"runtimeDeploymentPodAnnotations":{"linkerd.io/inject":"enabled","prometheus.io/path":"/metrics","prometheus.io/port":"8900","prometheus.io/scrape":"true"}}}' \ No newline at end of file diff --git a/charts/mendix-installer/templates/mendix-installer-job.yaml b/charts/mendix-installer/templates/mendix-installer-job.yaml index 665564e..d90feff 100644 --- a/charts/mendix-installer/templates/mendix-installer-job.yaml +++ b/charts/mendix-installer/templates/mendix-installer-job.yaml @@ -10,7 +10,7 @@ spec: containers: - name: mxpc-cli-installer image: alpine - command: ["/bin/sh", "-c", "wget https://dl.k8s.io/release/v1.25.0/bin/linux/amd64/kubectl; mv kubectl /usr/bin/kubectl; chmod +x /usr/bin/kubectl; /mxpc-cli-installer-script;"] + command: ["/bin/sh", "-c", "apk --update add postgresql-client; wget https://dl.k8s.io/release/v1.25.0/bin/linux/amd64/kubectl; mv kubectl /usr/bin/kubectl; chmod +x /usr/bin/kubectl; /mxpc-cli-installer-script;"] volumeMounts: - name: mxpc-cli-installer-script mountPath: /mxpc-cli-installer-script @@ -18,6 +18,14 @@ spec: - name: mendix-installer-config-file mountPath: mendix-installer-config-file readOnly: true +{{- range $.Values.database_plans }} + - name: "mendix-installer-config-db-{{ .name }}" + mountPath: "mendix-installer-config-db-{{ .name }}" + readOnly: true + - name: "mendix-rds-master-pass-{{ .name }}" + mountPath: "mendix-rds-master-pass-{{ .name }}" + readOnly: true +{{- end }} volumes: - name: mxpc-cli-installer-script configMap: @@ -26,4 +34,12 @@ spec: - name: mendix-installer-config-file secret: secretName: mendix-installer-config-file +{{- range $.Values.database_plans }} + - name: "mendix-installer-config-db-{{ .name }}" + secret: + secretName: "mendix-installer-config-db-{{ .name }}" + - name: "mendix-rds-master-pass-{{ .name }}" + secret: + secretName: "mendix-rds-master-pass-{{ .name }}" +{{- end }} restartPolicy: Never diff --git a/charts/mendix-installer/templates/mendix-installer-secret.yaml b/charts/mendix-installer/templates/mendix-installer-secret.yaml index 16adb02..77b8973 100644 --- a/charts/mendix-installer/templates/mendix-installer-secret.yaml +++ b/charts/mendix-installer/templates/mendix-installer-secret.yaml @@ -10,11 +10,11 @@ stringData: cluster_mode: connected mask: database_plan: false - storage_plan: false + storage_plan: true ingress: true registry: true proxy: false - custom_tls: false + custom_tls: true ingress: type: kubernetes-ingress enable_tls: true @@ -34,3 +34,64 @@ stringData: is_static_credential: false aws_iam_role: "{{ .Values.registry.iamRole }}" kubernetes_service_account: "mendix-builder" + storage_plan: + name: s3 + type: amazon-s3 + s3: + irsa_authentication: true + create_bucket: false + create_user: false + create_inline_policy: false + existing_bucket: "{{ .Values.storage_plan.existing_bucket }}" + existing_policy: "{{ .Values.storage_plan.existing_policy }}" + bucket_autogen_prefix: true + region: "{{ .Values.awsRegion }}" + admin_iam_role: "{{ .Values.storage_plan.admin_iam_role }}" + kubernetes_service_account: "{{ .Values.storage_plan.kubernetes_service_account }}" + oidc_url: "{{ .Values.storage_plan.oidc_url }}" + custom_tls: + ca_certificates_secret_name: mendix-custom-tls + +{{- range $.Values.database_plans }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "mendix-installer-config-db-{{ .name }}" + namespace: mendix +type: Opaque +stringData: + mendix-installer-config-file: | + namespace: mendix + cluster_mode: connected + mask: + database_plan: true + storage_plan: false + ingress: false + registry: false + proxy: false + custom_tls: false + database_plan: + name: "{{ .name }}" + type: postgres + postgres: + databaseprops: + host: "{{ .host }}" + port: {{ .port }} + user: "{{ .user }}" + password: "" + strict_tls: true + db_name: "{{ .db_name }}" + authentication_mode: aws-iam + aws_iam_role: "{{ .aws_iam_role }}" + kubernetes_service_account: "{{ .kubernetes_service_account }}" +--- +apiVersion: v1 +kind: Secret +metadata: + name: "mendix-rds-master-pass-{{ .name }}" + namespace: mendix +type: Opaque +stringData: + rds-password: "{{ .master_password }}" +{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/values.yaml b/charts/mendix-installer/values.yaml index 38ffc5b..1704c1d 100644 --- a/charts/mendix-installer/values.yaml +++ b/charts/mendix-installer/values.yaml @@ -1,6 +1,6 @@ appName: "{{.Name}}" -clusterID: "" -clusterSecret: "" +namespaceID: "" +namespaceSecret: "" mendixOperatorVersion: "" awsRegion: "" certificateExpirationEmail: "" @@ -11,6 +11,21 @@ registry: ingress: className: "" domainName: "" +database_plans: + - name: "" + host: "" + aws_iam_role: "" + kubernetes_service_account: "" + port: "" + user: "" + db_name: "" + master_password: "" +storage_plan: + existing_bucket: "" + existing_policy: "" + admin_iam_role: "" + oidc_url: "" + kubernetes_service_account: "" environmentsInternalNames: [] clusterName: "" accountID: "" \ No newline at end of file diff --git a/doc/deployment_guide/images/secrets-store.png b/doc/deployment_guide/images/secrets-store.png deleted file mode 100644 index a86eeb6..0000000 Binary files a/doc/deployment_guide/images/secrets-store.png and /dev/null differ diff --git a/examples/basic/.header.md b/examples/basic/.header.md index 6cedaaa..420b05e 100644 --- a/examples/basic/.header.md +++ b/examples/basic/.header.md @@ -1,17 +1,17 @@ ## Provisionning -Retrieve the cluster_id and cluster_secret on https://privatecloud.mendixcloud.com +Retrieve the namespace_id and namespace_secret on https://privatecloud.mendixcloud.com ``` aws_region="" domain_name="" certificate_expiration_email="" s3_bucket_name="" -cluster_id="" -cluster_secret="" +namespace_id="" +namespace_secret="" environments_internal_names = ["", "", ""] terraform init -terraform apply -auto-approve -var cluster_id=${cluster_id} -var cluster_secret=${cluster_secret} -var mendix_operator_version=${mendix_operator_version} -var aws_region=${aws_region} -var domain_name=${domain_name} -var certificate_expiration_email=${certificate_expiration_email} -var s3_bucket_name=${s3_bucket_name} +terraform apply -auto-approve -var namespace_id=${namespace_id} -var namespace_secret=${namespace_secret} -var mendix_operator_version=${mendix_operator_version} -var aws_region=${aws_region} -var domain_name=${domain_name} -var certificate_expiration_email=${certificate_expiration_email} -var s3_bucket_name=${s3_bucket_name} ``` ## Clean up diff --git a/examples/basic/main.tf b/examples/basic/main.tf index fdb21c0..7fed2ba 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -5,8 +5,8 @@ module "mendix_private_cloud_example" { domain_name = var.domain_name certificate_expiration_email = var.certificate_expiration_email s3_bucket_name = var.s3_bucket_name - cluster_id = var.cluster_id - cluster_secret = var.cluster_secret + namespace_id = var.namespace_id + namespace_secret = var.namespace_secret mendix_operator_version = var.mendix_operator_version } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index d8de4f3..5c2a115 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -13,14 +13,14 @@ variable "s3_bucket_name" { description = "S3 bucket name" } -variable "cluster_id" { +variable "namespace_id" { type = string - description = "Mendix Private Cloud Cluster ID" + description = "Mendix Private Cloud Namespace ID" } -variable "cluster_secret" { +variable "namespace_secret" { type = string - description = "Mendix Private Cloud Cluster Secret" + description = "Mendix Private Cloud Namespace Secret" } variable "mendix_operator_version" { diff --git a/helm-values/csi-secrets-store-provider-aws.yaml b/helm-values/csi-secrets-store-provider-aws.yaml deleted file mode 100644 index f1b2961..0000000 --- a/helm-values/csi-secrets-store-provider-aws.yaml +++ /dev/null @@ -1,2 +0,0 @@ -secrets-store-csi-driver: - install: false \ No newline at end of file diff --git a/helm-values/mendix-installer-values.yaml.tpl b/helm-values/mendix-installer-values.yaml.tpl index 85a1c30..3335f81 100644 --- a/helm-values/mendix-installer-values.yaml.tpl +++ b/helm-values/mendix-installer-values.yaml.tpl @@ -1,5 +1,5 @@ -clusterID: "${cluster_id}" -clusterSecret: "${cluster_secret}" +namespaceID: "${namespace_id}" +namespaceSecret: "${namespace_secret}" mendixOperatorVersion: "${mendix_operator_version}" awsRegion: "${aws_region}" certificateExpirationEmail: "${certificate_expiration_email}" @@ -10,6 +10,23 @@ registry: ingress: className: "nginx" domainName: "${ingress_domainname}" +database_plans: +%{ for index, address in database_server_addresses ~} + - name: "pg-${environments_internal_names[index]}" + host: "${address}" + aws_iam_role: "${storage_provisioner_iam_admin_role}" + kubernetes_service_account: mendix-storage-provisioner + port: "${database_ports[index]}" + user: "${database_usernames[index]}" + db_name: "${database_names[index]}" + master_password: "${database_passwords[index]}" +%{ endfor ~} +storage_plan: + existing_bucket: "${s3_bucket_name}" + existing_policy: "${environment_iam_template_policy}" + admin_iam_role: "${storage_provisioner_iam_admin_role}" + oidc_url: "${oidc_url}" + kubernetes_service_account: mendix-storage-provisioner environmentsInternalNames: %{ for name in environments_internal_names ~} - ${name} diff --git a/iam-templates/iam_environment_policy.json.tpl b/iam-templates/iam_environment_policy.json.tpl new file mode 100644 index 0000000..e990a4f --- /dev/null +++ b/iam-templates/iam_environment_policy.json.tpl @@ -0,0 +1,51 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowListingOfUserFolder", + "Action": [ + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::${filestorage_shared_bucket_name}" + ], + "Condition": { + "StringLike": { + "s3:prefix": [ + "$${aws:PrincipalTag/privatecloud.mendix.com/s3-prefix}/*", + "$${aws:PrincipalTag/privatecloud.mendix.com/s3-prefix}" + ] + } + } + }, + { + "Sid": "AllowAllS3ActionsInUserFolder", + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::${filestorage_shared_bucket_name}/$${aws:PrincipalTag/privatecloud.mendix.com/s3-prefix}/*" + ], + "Action": [ + "s3:AbortMultipartUpload", + "s3:DeleteObject", + "s3:GetObject", + "s3:ListMultipartUploadParts", + "s3:PutObject" + ] + }, + { + "Sid": "AllowConnectionToDatabase", + "Effect": "Allow", + "Action": "rds-db:connect", + "Resource": [ +%{ for index, db_instance_resource_id in db_instance_resource_ids ~} + %{ if index != length(db_instance_resource_ids) - 1 ~} + "arn:aws:rds-db:${aws_region}:${aws_account_id}:dbuser:${db_instance_resource_id}/$${aws:PrincipalTag/privatecloud.mendix.com/database-user}", + %{ else ~} + "arn:aws:rds-db:${aws_region}:${aws_account_id}:dbuser:${db_instance_resource_id}/$${aws:PrincipalTag/privatecloud.mendix.com/database-user}" + %{ endif ~} +%{ endfor ~} + ] + } + ] + } \ No newline at end of file diff --git a/iam-templates/iam_provisioner_policy.json.tpl b/iam-templates/iam_provisioner_policy.json.tpl new file mode 100644 index 0000000..5c18ac6 --- /dev/null +++ b/iam-templates/iam_provisioner_policy.json.tpl @@ -0,0 +1,64 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "LimitedAttachmentPermissions", + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy", + "iam:DetachRolePolicy" + ], + "Resource": "*", + "Condition": { + "ArnEquals": { + "iam:PolicyArn": [ + "${environment_policy_arn}" + ] + } + } + }, + { + "Sid": "ManageRoles", + "Effect": "Allow", + "Action": [ + "iam:CreateRole", + "iam:TagRole", + "iam:DeleteRole" + ], + "Resource": [ + "arn:aws:iam::${aws_account_id}:role/mendix-*" + ] + }, + { + "Sid": "AllowFileCleanup", + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::${filestorage_shared_bucket_name}" + ], + "Action": [ + "s3:AbortMultipartUpload", + "s3:DeleteObject", + "s3:GetObject", + "s3:ListMultipartUploadParts", + "s3:PutObject", + "s3:ListBucket" + ] + }, + { + "Sid": "AllowCreateRDSTenants", + "Effect": "Allow", + "Action": [ + "rds-db:connect" + ], + "Resource": [ +%{ for index, db_instance_resource_id in db_instance_resource_ids ~} + %{ if index != length(db_instance_resource_ids) - 1 ~} + "arn:aws:rds-db:${aws_region}:${aws_account_id}:dbuser:${db_instance_resource_id}/${db_instance_usernames[index]}", + %{ else ~} + "arn:aws:rds-db:${aws_region}:${aws_account_id}:dbuser:${db_instance_resource_id}/${db_instance_usernames[index]}" + %{ endif ~} +%{ endfor ~} + ] + } + ] + } \ No newline at end of file diff --git a/main.tf b/main.tf index 48fca2b..1e44f84 100644 --- a/main.tf +++ b/main.tf @@ -1,10 +1,21 @@ +locals { + cluster_name = "${var.eks_cluster_name_prefix}-${random_string.random_eks_suffix.result}" +} + +resource "random_string" "random_eks_suffix" { + length = 3 + min_lower = 3 + special = false +} + data "aws_eks_cluster_auth" "this" { name = module.eks_blueprints.eks_cluster_id } module "vpc" { - source = "./modules/vpc" - region = var.aws_region + source = "./modules/vpc" + region = var.aws_region + cluster_name = local.cluster_name } resource "aws_route53_zone" "cluster_dns" { @@ -21,23 +32,69 @@ module "databases" { for_each = toset(var.environments_internal_names) source = "./modules/databases" - identifier = "${module.vpc.cluster_name}-database-${each.key}" + identifier = "${local.cluster_name}-database-${each.key}" subnets = module.vpc.vpc_private_subnets + postgres_version = var.postgres_version cluster_primary_security_group_id = module.eks_blueprints.cluster_primary_security_group_id - file_storage_endpoint = module.file_storage.filestorage_regional_endpoint - filestorage_shared_bucket_arn = module.file_storage.filestorage_shared_bucket_arn - cluster_name = module.vpc.cluster_name - secrets_manager_name = "${module.vpc.cluster_name}-${each.key}-secrets" - aws_caller_identity_account_id = data.aws_caller_identity.current.account_id - oidc_provider = module.eks_blueprints.oidc_provider - environment_internal_name = each.key +} + +resource "aws_iam_policy" "environment_policy" { + name = "${local.cluster_name}-env-policy" + description = "Environment Template Policy" + + policy = templatefile("./iam-templates/iam_environment_policy.json.tpl", { + aws_region = var.aws_region + aws_account_id = data.aws_caller_identity.current.account_id + db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] + filestorage_shared_bucket_name = var.s3_bucket_name + }) +} + +resource "aws_iam_policy" "provisioner_policy" { + name = "${local.cluster_name}-provisioner-policy" + description = "Storage Provisioner admin Policy" + + policy = templatefile("./iam-templates/iam_provisioner_policy.json.tpl", { + aws_region = var.aws_region + aws_account_id = data.aws_caller_identity.current.account_id + db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] + db_instance_usernames = [for value in values(module.databases) : tostring(value.database_username[0])] + filestorage_shared_bucket_name = var.s3_bucket_name + environment_policy_arn = aws_iam_policy.environment_policy.arn + }) +} + +resource "aws_iam_role" "storage_provisioner_role" { + name = "${local.cluster_name}-storage-provisioner-irsa" + description = "Storage Provisioner admin Policy" + + assume_role_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Federated" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${module.eks_blueprints.oidc_provider}" + }, + "Action" : "sts:AssumeRoleWithWebIdentity", + "Condition" : { + "StringEquals" : { + "${module.eks_blueprints.oidc_provider}:aud" : "sts.amazonaws.com", + "${module.eks_blueprints.oidc_provider}:sub" : "system:serviceaccount:mendix:mendix-storage-provisioner" + } + } + } + ] + }) + + managed_policy_arns = [aws_iam_policy.provisioner_policy.arn] } data "aws_caller_identity" "current" {} module "container_registry" { source = "./modules/container-registry" - registry_repository_name = "${module.vpc.cluster_name}-ecr" + registry_repository_name = "${local.cluster_name}-ecr" region = var.aws_region account_id = data.aws_caller_identity.current.account_id oidc_provider = module.eks_blueprints.oidc_provider @@ -50,7 +107,7 @@ resource "aws_ebs_encryption_by_default" "ebs_encryption" { } module "eks_blueprints" { - source = "github.com/aws-ia/terraform-aws-eks-blueprints?ref=v4.28.0" + source = "github.com/aws-ia/terraform-aws-eks-blueprints?ref=v4.32.1" node_security_group_additional_rules = { cluster_to_nginx_webhook = { @@ -72,7 +129,7 @@ module "eks_blueprints" { } # EKS CLUSTER - cluster_name = module.vpc.cluster_name + cluster_name = local.cluster_name cluster_version = "1.24" vpc_id = module.vpc.vpc_id private_subnet_ids = module.vpc.vpc_private_subnets @@ -94,7 +151,7 @@ module "eks_blueprints" { } module "eks_blueprints_kubernetes_addons" { - source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons?ref=v4.28.0" + source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons?ref=v4.32.1" eks_cluster_id = module.eks_blueprints.eks_cluster_id eks_cluster_endpoint = module.eks_blueprints.eks_cluster_endpoint @@ -110,14 +167,6 @@ module "eks_blueprints_kubernetes_addons" { # Add-ons enable_aws_load_balancer_controller = true - enable_secrets_store_csi_driver = true - enable_secrets_store_csi_driver_provider_aws = true - csi_secrets_store_provider_aws_helm_config = { - values = [templatefile("${path.module}/helm-values/csi-secrets-store-provider-aws.yaml", { - hostname = var.domain_name - })] - } - enable_external_dns = true external_dns_route53_zone_arns = [ aws_route53_zone.cluster_dns.arn @@ -157,7 +206,7 @@ module "monitoring" { source = "./modules/monitoring" aws_region = var.aws_region account_id = data.aws_caller_identity.current.account_id - cluster_name = module.vpc.cluster_name + cluster_name = local.cluster_name oidc_provider = module.eks_blueprints.oidc_provider domain_name = var.domain_name @@ -177,18 +226,27 @@ resource "helm_release" "mendix_installer" { values = [ templatefile("${path.module}/helm-values/mendix-installer-values.yaml.tpl", { - cluster_name = module.vpc.cluster_name, - account_id = data.aws_caller_identity.current.account_id, - cluster_id = var.cluster_id, - cluster_secret = sensitive(var.cluster_secret), - mendix_operator_version = var.mendix_operator_version, - aws_region = module.vpc.region, - certificate_expiration_email = var.certificate_expiration_email - registry_pullurl = module.container_registry.container_registry_hostname, - registry_repository = module.container_registry.container_registry_name, - registry_iam_role = module.container_registry.container_irsa_role_arn, - ingress_domainname = var.domain_name, - environments_internal_names = var.environments_internal_names + cluster_name = local.cluster_name, + account_id = data.aws_caller_identity.current.account_id, + namespace_id = var.namespace_id, + namespace_secret = sensitive(var.namespace_secret), + mendix_operator_version = var.mendix_operator_version, + aws_region = module.vpc.region, + certificate_expiration_email = var.certificate_expiration_email + s3_bucket_name = var.s3_bucket_name + environment_iam_template_policy = aws_iam_policy.environment_policy.arn + storage_provisioner_iam_admin_role = aws_iam_role.storage_provisioner_role.arn + oidc_url = "https://${module.eks_blueprints.oidc_provider}" + database_server_addresses = [for value in values(module.databases) : tostring(value.database_server_address[0])] + database_ports = [for value in values(module.databases) : tostring(value.database_port[0])] + database_usernames = [for value in values(module.databases) : tostring(value.database_username[0])] + database_names = [for value in values(module.databases) : tostring(value.database_name[0])] + database_passwords = [for value in values(module.databases) : tostring(value.database_password[0])] + registry_pullurl = module.container_registry.container_registry_hostname, + registry_repository = module.container_registry.container_registry_name, + registry_iam_role = module.container_registry.container_irsa_role_arn, + ingress_domainname = var.domain_name, + environments_internal_names = var.environments_internal_names }) ] diff --git a/modules/databases/main.tf b/modules/databases/main.tf index f91e2f5..965e856 100644 --- a/modules/databases/main.tf +++ b/modules/databases/main.tf @@ -1,10 +1,9 @@ locals { database_engine = "postgres" - database_username = "mendix" + database_username = "postgres" database_port = 5432 } - resource "aws_db_subnet_group" "rds_subnet_group" { name = "${var.identifier}_subnet_group" subnet_ids = var.subnets @@ -19,97 +18,19 @@ resource "random_password" "password" { #IAM Authentication and performance insights are not needed. #tfsec:ignore:* resource "aws_db_instance" "default" { - allocated_storage = 10 - identifier = var.identifier - db_name = "postgres" - engine = local.database_engine - instance_class = var.rds_instance_class - port = local.database_port - username = local.database_username - password = random_password.password.result - storage_encrypted = true - backup_retention_period = 7 - skip_final_snapshot = true - db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name - vpc_security_group_ids = [var.cluster_primary_security_group_id] -} - -#tfsec:ignore:aws-ssm-secret-use-customer-key -resource "aws_secretsmanager_secret" "apps_secrets" { - name = var.secrets_manager_name - recovery_window_in_days = 7 -} - -resource "aws_secretsmanager_secret_version" "apps_secrets_version" { - secret_id = aws_secretsmanager_secret.apps_secrets.id - secret_string = jsonencode({ - storage-service-name = "com.mendix.storage.s3", - storage-endpoint = var.file_storage_endpoint - storage-bucket-name = var.environment_internal_name, - database-type = "PostgreSQL", - database-jdbc-url = "jdbc:postgresql://${aws_db_instance.default.address}:5432/${aws_db_instance.default.db_name}?sslmode=prefer" - database-name = "postgres", - database-username = "mendix", - database-password = aws_db_instance.default.password, - database-host = "${aws_db_instance.default.address}:5432" - }) -} - -resource "aws_iam_role" "app_irsa_role" { - name = "${var.cluster_name}-app-role-${var.environment_internal_name}" - assume_role_policy = jsonencode({ - "Version" : "2012-10-17", - "Statement" : [ - { - "Effect" : "Allow", - "Principal" : { - "Federated" : "arn:aws:iam::${var.aws_caller_identity_account_id}:oidc-provider/${var.oidc_provider}" - }, - "Action" : "sts:AssumeRoleWithWebIdentity", - "Condition" : { - "StringEquals" : { - "${var.oidc_provider}:aud" : "sts.amazonaws.com", - "${var.oidc_provider}:sub" : "system:serviceaccount:mendix:${var.environment_internal_name}" - } - } - } - ] - }) -} - -#https://docs.mendix.com/developerportal/deploy/private-cloud-cluster/ -#tfsec:ignore:aws-iam-no-policy-wildcards -resource "aws_iam_role_policy" "app_irsa_policy" { - name = "${var.cluster_name}-app-policy" - role = aws_iam_role.app_irsa_role.id - - policy = jsonencode({ - "Version" : "2012-10-17", - "Statement" : [ - { - "Sid" : "VisualEditor0", - "Effect" : "Allow", - "Action" : [ - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret" - ], - - "Resource" : aws_secretsmanager_secret.apps_secrets.arn - }, - { - "Action" : [ - "s3:AbortMultipartUpload", - "s3:DeleteObject", - "s3:GetObject", - "s3:ListMultipartUploadParts", - "s3:PutObject" - ], - "Effect" : "Allow", - "Resource" : [ - "${var.filestorage_shared_bucket_arn}/${var.environment_internal_name}/*" - ] - } - ] - }) + allocated_storage = 10 + identifier = var.identifier + db_name = "postgres" + engine = local.database_engine + engine_version = var.postgres_version + instance_class = var.rds_instance_class + port = local.database_port + username = local.database_username + password = random_password.password.result + storage_encrypted = true + backup_retention_period = 7 + skip_final_snapshot = true + db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name + vpc_security_group_ids = [var.cluster_primary_security_group_id] + iam_database_authentication_enabled = true } - diff --git a/modules/databases/outputs.tf b/modules/databases/outputs.tf index 59f2c2f..644eb3c 100644 --- a/modules/databases/outputs.tf +++ b/modules/databases/outputs.tf @@ -3,6 +3,11 @@ output "database_server_address" { value = aws_db_instance.default[*].address } +output "database_resource_id" { + description = "Resource ID within the AWS RDS instance" + value = aws_db_instance.default[*].resource_id +} + output "database_name" { description = "Database name within the AWS RDS instance" value = aws_db_instance.default[*].db_name diff --git a/modules/databases/variables.tf b/modules/databases/variables.tf index 7c0eb41..fbac3ef 100644 --- a/modules/databases/variables.tf +++ b/modules/databases/variables.tf @@ -1,5 +1,5 @@ variable "identifier" { - description = "VPC identifierD" + description = "VPC identifier" type = string } @@ -19,37 +19,7 @@ variable "rds_instance_class" { type = string } -variable "file_storage_endpoint" { - description = "S3 Regional endpoint" +variable "postgres_version" { type = string -} - -variable "secrets_manager_name" { - type = string - description = "Secrets Manager name" -} - -variable "cluster_name" { - type = string - description = "Kubernetes cluster name" -} - -variable "aws_caller_identity_account_id" { - type = string - description = "AWS Caller Identity Account ID" -} - -variable "oidc_provider" { - type = string - description = "The OpenID Connect identity provider (issuer URL without leading `https://`)" -} - -variable "environment_internal_name" { - type = string - description = "Environment internal name" -} - -variable "filestorage_shared_bucket_arn" { - type = string - description = "S3 shared bucket ARN" + description = "The version of Postgres that terraform would create." } \ No newline at end of file diff --git a/modules/vpc/main.tf b/modules/vpc/main.tf index 9cb4c92..b13552a 100644 --- a/modules/vpc/main.tf +++ b/modules/vpc/main.tf @@ -1,20 +1,10 @@ data "aws_availability_zones" "available" {} -locals { - cluster_name = "mendix-eks-${random_string.random.result}" -} - -resource "random_string" "random" { - length = 3 - min_lower = 3 - special = false -} - module "vpc" { source = "terraform-aws-modules/vpc/aws" - version = "3.2.0" + version = "4.0.1" - name = "${local.cluster_name}-vpc" + name = "${var.cluster_name}-vpc" cidr = "10.0.0.0/16" azs = data.aws_availability_zones.available.names private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] @@ -24,16 +14,16 @@ module "vpc" { enable_dns_hostnames = true tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" } public_subnet_tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" - "kubernetes.io/role/elb" = "1" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" + "kubernetes.io/role/elb" = "1" } private_subnet_tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" - "kubernetes.io/role/internal-elb" = "1" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" + "kubernetes.io/role/internal-elb" = "1" } } diff --git a/modules/vpc/outputs.tf b/modules/vpc/outputs.tf index 9edc176..a870c7c 100644 --- a/modules/vpc/outputs.tf +++ b/modules/vpc/outputs.tf @@ -4,11 +4,6 @@ output "region" { value = var.region } -output "cluster_name" { - description = "Kubernetes cluster name" - value = local.cluster_name -} - output "vpc_id" { description = "VPC ID" value = module.vpc.vpc_id diff --git a/modules/vpc/variables.tf b/modules/vpc/variables.tf index 4e80598..4b91e9b 100644 --- a/modules/vpc/variables.tf +++ b/modules/vpc/variables.tf @@ -1,4 +1,9 @@ variable "region" { type = string description = "AWS Region name" +} + +variable "cluster_name" { + type = string + description = "EKS cluster name" } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index bc53bdb..d4822a8 100644 --- a/outputs.tf +++ b/outputs.tf @@ -8,7 +8,7 @@ output "region" { # Kubernetes cluster output "cluster_name" { description = "Kubernetes cluster name" - value = module.vpc.cluster_name + value = local.cluster_name } output "vpc_private_subnets" { diff --git a/providers.tf b/providers.tf index ca18ee8..b67905b 100644 --- a/providers.tf +++ b/providers.tf @@ -13,7 +13,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.35" + version = ">= 5.10" } kubernetes = { source = "hashicorp/kubernetes" diff --git a/terraform.tfvars b/terraform.tfvars index 13c4596..83be3e8 100644 --- a/terraform.tfvars +++ b/terraform.tfvars @@ -1,7 +1,8 @@ aws_region = "" domain_name = "" +eks_cluster_name_prefix = "mx-private-cloud" certificate_expiration_email = "" s3_bucket_name = "" -cluster_id = "" -cluster_secret = "" +namespace_id = "" +namespace_secret = "" environments_internal_names = ["", "", ""] \ No newline at end of file diff --git a/test/examples_basic_test.go b/test/examples_basic_test.go index 3c12c27..4686a44 100644 --- a/test/examples_basic_test.go +++ b/test/examples_basic_test.go @@ -26,8 +26,8 @@ func TestExamplesBasicTest(t *testing.T) { "domain_name": uniqueId + "domain.com", "certificate_expiration_email": uniqueId + "@test.com", "s3_bucket_name": uniqueId + "-s3-bucket", - "cluster_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", - "cluster_secret": uniqueId + "UdfdTK7P0FD5", + "namespace_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", + "namespace_secret": uniqueId + "UdfdTK7P0FD5", "mendix_operator_version": "2.10.0", }, BackendConfig: map[string]interface{}{ @@ -56,8 +56,8 @@ func TestExamplesBasicTest(t *testing.T) { "domain_name": uniqueId + "domain.com", "certificate_expiration_email": uniqueId + "@test.com", "s3_bucket_name": uniqueId + "-s3-bucket", - "cluster_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", - "cluster_secret": uniqueId + "UdfdTK7P0FD5", + "namespace_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", + "namespace_secret": uniqueId + "UdfdTK7P0FD5", "mendix_operator_version": "2.10.0", }, BackendConfig: map[string]interface{}{ diff --git a/variables.tf b/variables.tf index 7de2778..0184cba 100644 --- a/variables.tf +++ b/variables.tf @@ -13,9 +13,14 @@ variable "s3_bucket_name" { description = "S3 bucket name" } -variable "cluster_id" { +variable "namespace_id" { type = string - description = "Mendix Private Cloud Cluster ID" + description = "Mendix Private Cloud Namespace ID" +} + +variable "namespace_secret" { + type = string + description = "Mendix Private Cloud Namespace Secret" } variable "eks_node_instance_type" { @@ -24,15 +29,21 @@ variable "eks_node_instance_type" { default = "t3.medium" } -variable "cluster_secret" { +variable "eks_cluster_name_prefix" { type = string - description = "Mendix Private Cloud Cluster Secret" + description = "EKS name prefix for the new cluster" + default = "mendix-eks" + + validation { + condition = length(var.eks_cluster_name_prefix) < 65 && can(regex("^[0-9A-Za-z][A-Za-z0-9\\-_]*", var.eks_cluster_name_prefix)) + error_message = "EKS name prefix max length is 65 and it should have the next patter: ^[0-9A-Za-z][A-Za-z0-9\\-_]*" + } } variable "mendix_operator_version" { type = string description = "Mendix Private Cloud Operator version" - default = "2.10.0" + default = "2.12.0" } variable "certificate_expiration_email" { @@ -55,4 +66,10 @@ variable "environments_internal_names" { condition = alltrue([for app in var.environments_internal_names : can(regex("^[a-z0-9]{1,8}$", app))]) error_message = "Use only lowercase letters and numbers, with a maximum of 8 characters and a minimum of 1 character." } +} + +variable "postgres_version" { + type = string + description = "The version of Postgres that terraform would create." + default = "14.8" } \ No newline at end of file