From d976ec7d099bf52bfdaca640527faf4fda948433 Mon Sep 17 00:00:00 2001 From: David Fry Date: Fri, 19 May 2023 12:35:15 +0100 Subject: [PATCH] first draft commit --- .../foundation/app-yamls/certmanager-app.yaml | 34 + argocd/foundation/app-yamls/consul-app.yaml | 34 + .../app-yamls/external-dns-app.yaml | 34 + argocd/foundation/app-yamls/ingress-app.yaml | 33 + .../app-yamls/stateful-services-app.yaml | 33 + argocd/foundation/app-yamls/storage-app.yaml | 34 + argocd/foundation/app-yamls/vault-app.yaml | 33 + .../ansible/control-center-deploy/ansible.tf | 50 + .../templates/inventory.yaml.tmpl | 40 + .../control-center-deploy/variables.tf | 55 + .../control-center-netmaker-deploy/ansible.tf | 69 + .../templates/inventory.yaml.tmpl | 30 + .../variables.tf | 60 + terraform/ansible/k8s-deploy/ansible.tf | 53 + .../k8s-deploy/templates/inventory.yaml.tmpl | 36 + terraform/ansible/k8s-deploy/variables.tf | 59 + terraform/aws/base-infra/data.tf | 23 + terraform/aws/base-infra/infra.tf | 102 + terraform/aws/base-infra/module_providers.tf | 6 + terraform/aws/base-infra/netmaker.tf | 116 + terraform/aws/base-infra/output.tf | 52 + terraform/aws/base-infra/route53.tf | 42 + .../templates/bastion.user_data.tmpl | 11 + terraform/aws/base-infra/variables.tf | 104 + terraform/aws/base-k8s/infra.tf | 264 ++ terraform/aws/base-k8s/loadbalancer.tf | 189 ++ terraform/aws/base-k8s/outputs.tf | 126 + terraform/aws/base-k8s/security-groups.tf | 141 + .../base-k8s/templates/cloud-config-base.yaml | 11 + terraform/aws/base-k8s/variables.tf | 173 + terraform/aws/control-center-infra/iam.tf | 46 + terraform/aws/control-center-infra/infra.tf | 87 + terraform/aws/control-center-infra/outputs.tf | 176 + .../aws/control-center-infra/random-pws.tf | 57 + terraform/aws/control-center-infra/route53.tf | 83 + .../control-center-infra/security-groups.tf | 98 + .../aws/control-center-infra/variables.tf | 223 ++ .../aws/post-config-control-center/backup.tf | 85 + .../module_providers.tf | 6 + .../aws/post-config-control-center/ses.tf | 15 + .../post-config-control-center/variables.tf | 25 + terraform/aws/post-config-k8s/ext-dns.tf | 51 + .../aws/post-config-k8s/gitlab-variables.tf | 62 + .../aws/post-config-k8s/longhorn_backups.tf | 53 + .../aws/post-config-k8s/module_providers.tf | 11 + terraform/aws/post-config-k8s/output.tf | 35 + terraform/aws/post-config-k8s/variables.tf | 46 + terraform/aws/post-config-k8s/vault-pre.tf | 37 + .../init/ansible-cc-deploy/terragrunt.hcl | 47 + .../ansible-cc-netmaker-deploy/terragrunt.hcl | 53 + terraform/control-center/init/aws-vars.yaml | 2 + .../control-center/init/common-vars.yaml | 3 + .../init/control-center-deploy/terragrunt.hcl | 56 + .../terragrunt.hcl | 79 + .../terragrunt.hcl | 67 + terraform/control-center/init/destroyall.sh | 3 + .../control-center/init/environment.yaml | 26 + .../control-center/init/movestatetogitlab.sh | 63 + terraform/control-center/init/runall.sh | 2 + terraform/control-center/init/setlocalenv.sh | 3 + terraform/control-center/init/terragrunt.hcl | 36 + .../foundation-install/certmanager-config.tf | 24 + terraform/foundation-install/consul-config.tf | 18 + .../foundation-install/external-dns-config.tf | 23 + .../generate-files/generate-config.tf | 30 + .../certmanager/app/certmanager-app.yaml.tpl | 34 + .../certmanager/chart/Chart.yaml.tpl | 7 + .../certmanager/chart/values.yaml.tpl | 2 + .../lets-cluster-issuer.yaml.tpl | 29 + .../certman-extsecret.yaml.tpl | 24 + .../templates/consul/Chart.yaml.tpl | 7 + .../templates/consul/app/consul-app.yaml.tpl | 34 + .../templates/consul/values.yaml.tpl | 11 + .../app/external-dns-app.yaml.tpl | 34 + .../external-dns/chart/Chart.yaml.tpl | 7 + .../external-dns/chart/values.yaml.tpl | 15 + .../extdns-extsecret.yaml.tpl | 33 + .../ingress/app/ingress-app.yaml.tpl | 33 + .../charts/nginx-external/Chart.yaml.tpl | 7 + .../charts/nginx-external/values.yaml.tpl | 30 + .../charts/nginx-internal/Chart.yaml.tpl | 7 + .../charts/nginx-internal/values.yaml.tpl | 29 + .../ingress/ingress-external.yaml.tpl | 34 + .../ingress/ingress-internal.yaml.tpl | 34 + .../ingress/lets-wildcard-cert.yaml.tpl | 16 + .../templates/istio/app/istio-app.yaml.tpl | 34 + .../templates/istio/chart/Chart.yaml.tpl | 10 + .../templates/istio/chart/values.yaml.tpl | 550 ++++ .../istio/lets-wildcard-cert.yaml.tpl | 16 + .../keycloak/app/keycloak-app.yaml.tpl | 34 + .../custom-resources/keycloak-cr.yaml.tpl | 19 + ...cloakrealmimports.k8s.keycloak.org-v1.yaml | 2248 +++++++++++++ .../keycloaks.k8s.keycloak.org-v1.yaml | 2917 +++++++++++++++++ .../keycloak/operator/kubernetes.yaml | 235 ++ .../app/stateful-resources-app.yaml.tpl | 33 + .../external-name-services.yaml.tpl | 10 + .../stateful-resources-kustomization.yaml.tpl | 18 + .../stateful-resources/values-kafka.yaml.tpl | 111 + .../values-mongodb.yaml.tpl | 71 + .../stateful-resources/values-mysql.yaml.tpl | 318 ++ .../stateful-resources/values-redis.yaml.tpl | 1662 ++++++++++ .../stateful-resources/vault-crs.yaml.tpl | 75 + .../storage/app/storage-app.yaml.tpl | 34 + .../templates/storage/chart/Chart.yaml.tpl | 7 + .../templates/storage/chart/values.yaml.tpl | 21 + .../custom-resources/longhorn-job.yaml.tpl | 13 + .../longhorn-extsecret.yaml.tpl | 24 + .../templates/vault/app/vault-app.yaml.tpl | 33 + .../vault-config-operator/Chart.yaml.tpl | 7 + .../vault-config-operator/values.yaml.tpl | 50 + .../vault/charts/vault/Chart.yaml.tpl | 7 + .../vault/charts/vault/values.yaml.tpl | 89 + .../templates/vault/post-config.yaml.tpl | 100 + .../vault/vault-config-operator.yaml.tpl | 34 + .../templates/vault/vault-extsecret.yaml.tpl | 46 + .../templates/vault/vault-helm.yaml.tpl | 34 + terraform/foundation-install/gitlab.tf | 33 + terraform/foundation-install/ingress.tf | 30 + .../stateful-resources-config.tf.bak | 50 + .../foundation-install/storage-config.tf | 25 + terraform/foundation-install/variables.tf | 457 +++ terraform/foundation-install/vault.tf | 43 + .../ci-templates/bootstrap/.gitlab-ci.yml | 149 + .../bootstrap/.gitlab/ci/Dockerfile | 4 + .../.gitlab/scripts/seedenvproject.sh | 16 + .../ci-templates/bootstrap/setcivars.sh | 4 + .../ci-templates/k8s-cluster/.gitlab-ci.yml | 135 + .../k8s-cluster/.gitlab/ci/Dockerfile | 4 + .../k8s-cluster/.gitlab/scripts/pushtorepo.sh | 18 + .../ci-templates/k8s-cluster/setcivars.sh | 16 + .../control-center-gitlab-config/gitlab.tf | 131 + .../control-center-gitlab-config/outputs.tf | 14 + .../control-center-gitlab-config/variables.tf | 51 + .../environment-gitlab-config/gitlab.tf | 115 + .../environment-gitlab-config/variables.tf | 8 + .../k8s/ansible-k8s-deploy/terragrunt.hcl | 54 + terraform/k8s/aws-vars.yaml | 1 + terraform/k8s/common-vars.yaml | 10 + terraform/k8s/foundation-build/terragrunt.hcl | 99 + terraform/k8s/k8s-deploy/terragrunt.hcl | 64 + terraform/k8s/setlocalvars.sh | 17 + terraform/k8s/stateful-resources.json | 427 +++ terraform/k8s/terragrunt.hcl | 84 + 143 files changed, 15124 insertions(+) create mode 100644 argocd/foundation/app-yamls/certmanager-app.yaml create mode 100644 argocd/foundation/app-yamls/consul-app.yaml create mode 100644 argocd/foundation/app-yamls/external-dns-app.yaml create mode 100644 argocd/foundation/app-yamls/ingress-app.yaml create mode 100644 argocd/foundation/app-yamls/stateful-services-app.yaml create mode 100644 argocd/foundation/app-yamls/storage-app.yaml create mode 100644 argocd/foundation/app-yamls/vault-app.yaml create mode 100644 terraform/ansible/control-center-deploy/ansible.tf create mode 100644 terraform/ansible/control-center-deploy/templates/inventory.yaml.tmpl create mode 100644 terraform/ansible/control-center-deploy/variables.tf create mode 100644 terraform/ansible/control-center-netmaker-deploy/ansible.tf create mode 100644 terraform/ansible/control-center-netmaker-deploy/templates/inventory.yaml.tmpl create mode 100644 terraform/ansible/control-center-netmaker-deploy/variables.tf create mode 100644 terraform/ansible/k8s-deploy/ansible.tf create mode 100644 terraform/ansible/k8s-deploy/templates/inventory.yaml.tmpl create mode 100644 terraform/ansible/k8s-deploy/variables.tf create mode 100644 terraform/aws/base-infra/data.tf create mode 100644 terraform/aws/base-infra/infra.tf create mode 100644 terraform/aws/base-infra/module_providers.tf create mode 100644 terraform/aws/base-infra/netmaker.tf create mode 100644 terraform/aws/base-infra/output.tf create mode 100644 terraform/aws/base-infra/route53.tf create mode 100644 terraform/aws/base-infra/templates/bastion.user_data.tmpl create mode 100644 terraform/aws/base-infra/variables.tf create mode 100644 terraform/aws/base-k8s/infra.tf create mode 100644 terraform/aws/base-k8s/loadbalancer.tf create mode 100644 terraform/aws/base-k8s/outputs.tf create mode 100644 terraform/aws/base-k8s/security-groups.tf create mode 100644 terraform/aws/base-k8s/templates/cloud-config-base.yaml create mode 100644 terraform/aws/base-k8s/variables.tf create mode 100644 terraform/aws/control-center-infra/iam.tf create mode 100644 terraform/aws/control-center-infra/infra.tf create mode 100644 terraform/aws/control-center-infra/outputs.tf create mode 100644 terraform/aws/control-center-infra/random-pws.tf create mode 100644 terraform/aws/control-center-infra/route53.tf create mode 100644 terraform/aws/control-center-infra/security-groups.tf create mode 100644 terraform/aws/control-center-infra/variables.tf create mode 100644 terraform/aws/post-config-control-center/backup.tf create mode 100644 terraform/aws/post-config-control-center/module_providers.tf create mode 100644 terraform/aws/post-config-control-center/ses.tf create mode 100644 terraform/aws/post-config-control-center/variables.tf create mode 100644 terraform/aws/post-config-k8s/ext-dns.tf create mode 100644 terraform/aws/post-config-k8s/gitlab-variables.tf create mode 100644 terraform/aws/post-config-k8s/longhorn_backups.tf create mode 100644 terraform/aws/post-config-k8s/module_providers.tf create mode 100644 terraform/aws/post-config-k8s/output.tf create mode 100644 terraform/aws/post-config-k8s/variables.tf create mode 100644 terraform/aws/post-config-k8s/vault-pre.tf create mode 100644 terraform/control-center/init/ansible-cc-deploy/terragrunt.hcl create mode 100644 terraform/control-center/init/ansible-cc-netmaker-deploy/terragrunt.hcl create mode 100644 terraform/control-center/init/aws-vars.yaml create mode 100644 terraform/control-center/init/common-vars.yaml create mode 100644 terraform/control-center/init/control-center-deploy/terragrunt.hcl create mode 100644 terraform/control-center/init/control-center-env-gitlab-config/terragrunt.hcl create mode 100644 terraform/control-center/init/control-center-gitlab-config/terragrunt.hcl create mode 100755 terraform/control-center/init/destroyall.sh create mode 100644 terraform/control-center/init/environment.yaml create mode 100755 terraform/control-center/init/movestatetogitlab.sh create mode 100755 terraform/control-center/init/runall.sh create mode 100644 terraform/control-center/init/setlocalenv.sh create mode 100644 terraform/control-center/init/terragrunt.hcl create mode 100644 terraform/foundation-install/certmanager-config.tf create mode 100644 terraform/foundation-install/consul-config.tf create mode 100644 terraform/foundation-install/external-dns-config.tf create mode 100644 terraform/foundation-install/generate-files/generate-config.tf create mode 100644 terraform/foundation-install/generate-files/templates/certmanager/app/certmanager-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/certmanager/chart/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/certmanager/chart/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/certmanager/custom-resources/lets-cluster-issuer.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/certmanager/external-secrets/certman-extsecret.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/consul/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/consul/app/consul-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/consul/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/external-dns/app/external-dns-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/external-dns/chart/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/external-dns/chart/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/external-dns/external-secrets/extdns-extsecret.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/app/ingress-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/charts/nginx-external/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/charts/nginx-external/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/charts/nginx-internal/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/charts/nginx-internal/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/ingress-external.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/ingress-internal.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/ingress/lets-wildcard-cert.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/istio/app/istio-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/istio/chart/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/istio/chart/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/istio/lets-wildcard-cert.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/keycloak/app/keycloak-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/keycloak/custom-resources/keycloak-cr.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/keycloak/operator/keycloakrealmimports.k8s.keycloak.org-v1.yaml create mode 100644 terraform/foundation-install/generate-files/templates/keycloak/operator/keycloaks.k8s.keycloak.org-v1.yaml create mode 100644 terraform/foundation-install/generate-files/templates/keycloak/operator/kubernetes.yaml create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/app/stateful-resources-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/external-name-services.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/stateful-resources-kustomization.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/values-kafka.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/values-mongodb.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/values-mysql.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/values-redis.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/stateful-resources/vault-crs.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/storage/app/storage-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/storage/chart/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/storage/chart/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/storage/custom-resources/longhorn-job.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/storage/external-secrets/longhorn-extsecret.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/app/vault-app.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/charts/vault/Chart.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/charts/vault/values.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/post-config.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/vault-config-operator.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/vault-extsecret.yaml.tpl create mode 100644 terraform/foundation-install/generate-files/templates/vault/vault-helm.yaml.tpl create mode 100644 terraform/foundation-install/gitlab.tf create mode 100644 terraform/foundation-install/ingress.tf create mode 100644 terraform/foundation-install/stateful-resources-config.tf.bak create mode 100644 terraform/foundation-install/storage-config.tf create mode 100644 terraform/foundation-install/variables.tf create mode 100644 terraform/foundation-install/vault.tf create mode 100644 terraform/gitlab/ci-templates/bootstrap/.gitlab-ci.yml create mode 100644 terraform/gitlab/ci-templates/bootstrap/.gitlab/ci/Dockerfile create mode 100755 terraform/gitlab/ci-templates/bootstrap/.gitlab/scripts/seedenvproject.sh create mode 100644 terraform/gitlab/ci-templates/bootstrap/setcivars.sh create mode 100644 terraform/gitlab/ci-templates/k8s-cluster/.gitlab-ci.yml create mode 100644 terraform/gitlab/ci-templates/k8s-cluster/.gitlab/ci/Dockerfile create mode 100755 terraform/gitlab/ci-templates/k8s-cluster/.gitlab/scripts/pushtorepo.sh create mode 100644 terraform/gitlab/ci-templates/k8s-cluster/setcivars.sh create mode 100644 terraform/gitlab/control-center-gitlab-config/gitlab.tf create mode 100644 terraform/gitlab/control-center-gitlab-config/outputs.tf create mode 100644 terraform/gitlab/control-center-gitlab-config/variables.tf create mode 100644 terraform/gitlab/environment-gitlab-config/gitlab.tf create mode 100644 terraform/gitlab/environment-gitlab-config/variables.tf create mode 100644 terraform/k8s/ansible-k8s-deploy/terragrunt.hcl create mode 100644 terraform/k8s/aws-vars.yaml create mode 100644 terraform/k8s/common-vars.yaml create mode 100644 terraform/k8s/foundation-build/terragrunt.hcl create mode 100644 terraform/k8s/k8s-deploy/terragrunt.hcl create mode 100644 terraform/k8s/setlocalvars.sh create mode 100644 terraform/k8s/stateful-resources.json create mode 100644 terraform/k8s/terragrunt.hcl diff --git a/argocd/foundation/app-yamls/certmanager-app.yaml b/argocd/foundation/app-yamls/certmanager-app.yaml new file mode 100644 index 000000000..f48a7b69f --- /dev/null +++ b/argocd/foundation/app-yamls/certmanager-app.yaml @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-8" + name: certmanager-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/certmanager + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: certmanager + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/consul-app.yaml b/argocd/foundation/app-yamls/consul-app.yaml new file mode 100644 index 000000000..8fdb363a6 --- /dev/null +++ b/argocd/foundation/app-yamls/consul-app.yaml @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-9" + name: consul-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/consul + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: consul + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/external-dns-app.yaml b/argocd/foundation/app-yamls/external-dns-app.yaml new file mode 100644 index 000000000..a86106431 --- /dev/null +++ b/argocd/foundation/app-yamls/external-dns-app.yaml @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-8" + name: external-dns-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/external-dns + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: external-dns + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/ingress-app.yaml b/argocd/foundation/app-yamls/ingress-app.yaml new file mode 100644 index 000000000..9a891a896 --- /dev/null +++ b/argocd/foundation/app-yamls/ingress-app.yaml @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-7" + name: ingress-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/ingress + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + destination: + namespace: argocd + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/stateful-services-app.yaml b/argocd/foundation/app-yamls/stateful-services-app.yaml new file mode 100644 index 000000000..53972815e --- /dev/null +++ b/argocd/foundation/app-yamls/stateful-services-app.yaml @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-4" + name: stateful-services-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/stateful-services + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + destination: + namespace: stateful-services + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/storage-app.yaml b/argocd/foundation/app-yamls/storage-app.yaml new file mode 100644 index 000000000..25518ae73 --- /dev/null +++ b/argocd/foundation/app-yamls/storage-app.yaml @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-10" + name: storage-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/storage + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: longhorn-system + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/argocd/foundation/app-yamls/vault-app.yaml b/argocd/foundation/app-yamls/vault-app.yaml new file mode 100644 index 000000000..e860987ae --- /dev/null +++ b/argocd/foundation/app-yamls/vault-app.yaml @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-5" + name: vault-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: infra/apps/vault + repoURL: 'https://gitlab.labs.mojaloop.live/iac/argo.git' + targetRevision: HEAD + destination: + namespace: vault + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/terraform/ansible/control-center-deploy/ansible.tf b/terraform/ansible/control-center-deploy/ansible.tf new file mode 100644 index 000000000..47171a657 --- /dev/null +++ b/terraform/ansible/control-center-deploy/ansible.tf @@ -0,0 +1,50 @@ + +resource "local_sensitive_file" "ansible_inventory" { + content = templatefile( + "${path.module}/templates/inventory.yaml.tmpl", + { all_hosts = merge(var.docker_hosts, var.gitlab_hosts, var.bastion_hosts), + gitlab_hosts = var.gitlab_hosts, + docker_hosts = var.docker_hosts, + bastion_hosts = var.bastion_hosts, + bastion_hosts_var_maps = var.bastion_hosts_var_maps, + docker_hosts_var_maps = merge(var.docker_hosts_var_maps, local.jumphostmap), + gitlab_hosts_var_maps = merge(var.gitlab_hosts_var_maps, local.jumphostmap), + all_hosts_var_maps = merge(var.all_hosts_var_maps, local.ssh_private_key_file_map)} + + ) + filename = "${local.ansible_output_dir}/inventory" + file_permission = "0600" +} + +resource "null_resource" "run_ansible" { + provisioner "local-exec" { + command = <<-EOT + ansible-galaxy collection install ${var.ansible_collection_url},${var.ansible_collection_tag} + ansible-playbook mojaloop.iac.control_center_deploy -i ${local_sensitive_file.ansible_inventory.filename} + EOT + working_dir = path.module + } + triggers = { + inventory_file_sha_hex = local_sensitive_file.ansible_inventory.id + ansible_collection_tag = var.ansible_collection_tag + } + depends_on = [ + local_sensitive_file.ansible_inventory + ] +} + +resource "local_sensitive_file" "ec2_ssh_key" { + content = var.ansible_bastion_key + filename = "${local.ansible_output_dir}/sshkey" + file_permission = "0600" +} + +locals { + jumphostmap = { + ansible_ssh_common_args = "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ProxyCommand=\"ssh -W %h:%p -i ${local_sensitive_file.ec2_ssh_key.filename} -o StrictHostKeyChecking=no -q ${var.ansible_bastion_os_username}@${var.ansible_bastion_public_ip}\"" + } + ansible_output_dir = "${var.ansible_base_output_dir}/control-center-deploy" + ssh_private_key_file_map = { + ansible_ssh_private_key_file = local_sensitive_file.ec2_ssh_key.filename + } +} diff --git a/terraform/ansible/control-center-deploy/templates/inventory.yaml.tmpl b/terraform/ansible/control-center-deploy/templates/inventory.yaml.tmpl new file mode 100644 index 000000000..2223e8ecc --- /dev/null +++ b/terraform/ansible/control-center-deploy/templates/inventory.yaml.tmpl @@ -0,0 +1,40 @@ +all: + hosts: + %{~ for name, ip in all_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in all_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +gitlab: + hosts: + %{~ for name, ip in gitlab_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in gitlab_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +docker: + hosts: + %{~ for name, ip in docker_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in docker_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +bastion: + hosts: + %{~ for name, ip in bastion_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in bastion_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} \ No newline at end of file diff --git a/terraform/ansible/control-center-deploy/variables.tf b/terraform/ansible/control-center-deploy/variables.tf new file mode 100644 index 000000000..20a31bad2 --- /dev/null +++ b/terraform/ansible/control-center-deploy/variables.tf @@ -0,0 +1,55 @@ +variable "ansible_collection_url" { + default = "git+https://github.com/mojaloop/iac-ansible-collection-roles.git#/mojaloop/iac" +} + +variable "ansible_collection_tag" { + default = "main" +} + +variable "ansible_bastion_key" { + description = "ssh key for bastion host" + sensitive = true +} + +variable "ansible_bastion_public_ip" { + description = "ip for bastion host" +} + +variable "ansible_bastion_os_username" { + description = "username for bastion host" +} + +variable "ansible_base_output_dir" { + description = "where to read/write ansible inv/etc" + default = "/iac-run-dir/output" +} +variable "gitlab_hosts" { + type = map + description = "map of hosts to run gitlab server" +} +variable "docker_hosts" { + type = map + description = "map of hosts to run docker server" +} +variable "bastion_hosts" { + type = map + description = "map of hosts to run bastion and netclient" +} + +variable "bastion_hosts_var_maps" { + type = map + description = "var map for bastion hosts" +} + +variable "docker_hosts_var_maps" { + type = map + description = "var map for docker hosts" +} +variable "gitlab_hosts_var_maps" { + type = map + description = "var map for gitlab hosts" +} +variable "all_hosts_var_maps" { + type = map + description = "var map for all hosts" +} diff --git a/terraform/ansible/control-center-netmaker-deploy/ansible.tf b/terraform/ansible/control-center-netmaker-deploy/ansible.tf new file mode 100644 index 000000000..5febfa22d --- /dev/null +++ b/terraform/ansible/control-center-netmaker-deploy/ansible.tf @@ -0,0 +1,69 @@ + +resource "local_sensitive_file" "ansible_inventory" { + content = templatefile( + "${path.module}/templates/inventory.yaml.tmpl", + { all_hosts = merge(var.bastion_hosts, var.netmaker_hosts), + bastion_hosts = var.bastion_hosts, + netmaker_hosts = var.netmaker_hosts, + bastion_hosts_var_maps = merge(var.bastion_hosts_var_maps, local.bastion_hosts_var_maps), + netmaker_hosts_var_maps = merge(var.netmaker_hosts_var_maps, local.netmaker_hosts_var_maps), + all_hosts_var_maps = merge(var.all_hosts_var_maps, local.ssh_private_key_file_map) } + ) + filename = "${local.ansible_base_output_dir}/inventory" + file_permission = "0600" +} + +resource "null_resource" "run_ansible" { + provisioner "local-exec" { + command = <<-EOT + ansible-galaxy collection install ${var.ansible_collection_url},${var.ansible_collection_tag} + ansible-playbook mojaloop.iac.control_center_netmaker_deploy -i ${local_sensitive_file.ansible_inventory.filename} + EOT + working_dir = path.module + } + triggers = { + inventory_file_sha_hex = local_sensitive_file.ansible_inventory.id + ansible_collection_tag = var.ansible_collection_tag + } + depends_on = [ + local_sensitive_file.ansible_inventory + ] +} + +resource "local_sensitive_file" "ec2_ssh_key" { + content = var.ansible_bastion_key + filename = "${local.ansible_base_output_dir}/sshkey" + file_permission = "0600" +} + +data "local_sensitive_file" "netmaker_keys" { + filename = local.enrollment_key_list_file_location + depends_on = [ + null_resource.run_ansible + ] +} + +output "netmaker_token_map" { + value =local.token_map + sensitive = true +} + +locals { + + ansible_base_output_dir = "${var.ansible_base_output_dir}/control-center-post-config" + netmaker_hosts_var_maps = { + enable_oauth = var.enable_netmaker_oidc + enrollment_key_list_file_location = local.enrollment_key_list_file_location + enrollment_key_list = jsonencode(concat(["bastion"], keys(var.env_map))) + } + bastion_hosts_var_maps = { + enrollment_key_list_file_location = local.enrollment_key_list_file_location + netclient_enrollment_key = "${local.netmaker_control_network_name}-bastion" + } + ssh_private_key_file_map = { + ansible_ssh_private_key_file = local_sensitive_file.ec2_ssh_key.filename + } + enrollment_key_list_file_location = "${local.ansible_base_output_dir}/keylist.json" + netmaker_control_network_name = var.netmaker_hosts_var_maps.netmaker_control_network_name + token_map = { for netkey in jsondecode(data.local_sensitive_file.netmaker_keys.content) : replace(netkey.tags[0], "${local.netmaker_control_network_name}-", "") => {"netmaker_token" = netkey.token }} +} diff --git a/terraform/ansible/control-center-netmaker-deploy/templates/inventory.yaml.tmpl b/terraform/ansible/control-center-netmaker-deploy/templates/inventory.yaml.tmpl new file mode 100644 index 000000000..64e7ec371 --- /dev/null +++ b/terraform/ansible/control-center-netmaker-deploy/templates/inventory.yaml.tmpl @@ -0,0 +1,30 @@ +all: + hosts: + %{~ for name, ip in all_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in all_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +bastion: + hosts: + %{~ for name, ip in bastion_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in bastion_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +netmaker: + hosts: + %{~ for name, ip in netmaker_hosts ~} + ${name}: + ansible_host: ${ip} + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in netmaker_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} \ No newline at end of file diff --git a/terraform/ansible/control-center-netmaker-deploy/variables.tf b/terraform/ansible/control-center-netmaker-deploy/variables.tf new file mode 100644 index 000000000..7134dc433 --- /dev/null +++ b/terraform/ansible/control-center-netmaker-deploy/variables.tf @@ -0,0 +1,60 @@ +variable "ansible_collection_url" { + default = "git+https://github.com/mojaloop/iac-ansible-collection-roles.git#/mojaloop/iac" +} + +variable "ansible_collection_tag" { + default = "main" +} + +variable "enable_netmaker_oidc" { + type = bool + description = "enable creation of netmaker oidc" +} + +variable "ansible_bastion_key" { + description = "ssh key for bastion host" + sensitive = true +} + +variable "ansible_bastion_public_ip" { + description = "ip for bastion host" +} + +variable "ansible_bastion_os_username" { + description = "username for bastion host" +} + +variable "inventory_filename" { + description = "output ansible inventory filename" + default = "inventory" +} + +variable "ansible_base_output_dir" { + description = "where to read/write ansible inv/etc" + default = "/iac-run-dir/output" +} + +variable "bastion_hosts" { + type = map + description = "map of hosts to run bastion and netclient" +} +variable "netmaker_hosts" { + type = map + description = "map of hosts to run netmaker server" +} +variable "bastion_hosts_var_maps" { + type = map + description = "var map for bastion hosts" +} +variable "netmaker_hosts_var_maps" { + type = map + description = "var map for netmaker hosts" +} +variable "all_hosts_var_maps" { + type = map + description = "var map for all hosts" +} +variable "env_map" { + type = map + description = "env repos to configure" +} \ No newline at end of file diff --git a/terraform/ansible/k8s-deploy/ansible.tf b/terraform/ansible/k8s-deploy/ansible.tf new file mode 100644 index 000000000..504b0fa54 --- /dev/null +++ b/terraform/ansible/k8s-deploy/ansible.tf @@ -0,0 +1,53 @@ + +resource "local_sensitive_file" "ansible_inventory" { + content = templatefile( + "${path.module}/templates/inventory.yaml.tmpl", + { all_hosts = merge(var.master_hosts, var.agent_hosts, var.bastion_hosts), + master_hosts = var.master_hosts, + agent_hosts = var.agent_hosts, + bastion_hosts = var.bastion_hosts, + bastion_hosts_var_maps = var.bastion_hosts_var_maps, + agent_hosts_var_maps = merge(var.agent_hosts_var_maps, local.jumphostmap), + master_hosts_var_maps = merge(var.master_hosts_var_maps, local.jumphostmap, local.master_hosts_var_maps), + all_hosts_var_maps = merge(var.all_hosts_var_maps, local.ssh_private_key_file_map)} + + ) + filename = "${local.ansible_output_dir}/inventory" + file_permission = "0600" +} + +resource "null_resource" "run_ansible" { + provisioner "local-exec" { + command = <<-EOT + ansible-galaxy collection install ${var.ansible_collection_url},${var.ansible_collection_tag} + ansible-playbook mojaloop.iac.${var.ansible_playbook_name} -i ${local_sensitive_file.ansible_inventory.filename} + EOT + working_dir = path.module + } + triggers = { + inventory_file_sha_hex = local_sensitive_file.ansible_inventory.id + ansible_collection_tag = var.ansible_collection_tag + } + depends_on = [ + local_sensitive_file.ansible_inventory + ] +} + +resource "local_sensitive_file" "ec2_ssh_key" { + content = var.ansible_bastion_key + filename = "${local.ansible_output_dir}/sshkey" + file_permission = "0600" +} + +locals { + jumphostmap = { + ansible_ssh_common_args = "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ProxyCommand=\"ssh -W %h:%p -i ${local_sensitive_file.ec2_ssh_key.filename} -o StrictHostKeyChecking=no -q ${var.ansible_bastion_os_username}@${var.ansible_bastion_public_ip}\"" + } + ansible_output_dir = "${var.ansible_base_output_dir}/k8s-deploy" + ssh_private_key_file_map = { + ansible_ssh_private_key_file = local_sensitive_file.ec2_ssh_key.filename + } + master_hosts_var_maps = { + kubeconfig_local_location = local.ansible_output_dir + } +} diff --git a/terraform/ansible/k8s-deploy/templates/inventory.yaml.tmpl b/terraform/ansible/k8s-deploy/templates/inventory.yaml.tmpl new file mode 100644 index 000000000..62368108e --- /dev/null +++ b/terraform/ansible/k8s-deploy/templates/inventory.yaml.tmpl @@ -0,0 +1,36 @@ +all: + hosts: + %{~ for host in all_hosts ~} + ${host}: + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in all_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +master: + hosts: + %{~ for host in master_hosts ~} + ${host}: + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in master_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +agent: + hosts: + %{~ for host in agent_hosts ~} + ${host}: + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in agent_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} +bastion: + hosts: + %{~ for host in bastion_hosts ~} + ${host}: + %{~ endfor ~} + vars: + %{~ for varmapkey, varmapval in bastion_hosts_var_maps ~} + ${varmapkey}: '${varmapval}' + %{~ endfor ~} \ No newline at end of file diff --git a/terraform/ansible/k8s-deploy/variables.tf b/terraform/ansible/k8s-deploy/variables.tf new file mode 100644 index 000000000..420d6e87f --- /dev/null +++ b/terraform/ansible/k8s-deploy/variables.tf @@ -0,0 +1,59 @@ +variable "ansible_collection_url" { + default = "git+https://github.com/mojaloop/iac-ansible-collection-roles.git#/mojaloop/iac" +} + +variable "ansible_collection_tag" { + default = "main" +} + +variable "ansible_playbook_name" { + default = "argok3s_cluster_deploy" +} + +variable "ansible_bastion_key" { + description = "ssh key for bastion host" + sensitive = true +} + +variable "ansible_bastion_public_ip" { + description = "ip for bastion host" +} + +variable "ansible_bastion_os_username" { + description = "username for bastion host" +} + +variable "ansible_base_output_dir" { + description = "where to read/write ansible inv/etc" + default = "/iac-run-dir/output" +} +variable "master_hosts" { + type = map + description = "map of hosts to run master nodes" +} +variable "agent_hosts" { + type = map + description = "map of hosts to run agent nodes" +} +variable "bastion_hosts" { + type = map + description = "map of hosts to run bastion and netclient" +} + +variable "bastion_hosts_var_maps" { + type = map + description = "var map for bastion hosts" +} + +variable "agent_hosts_var_maps" { + type = map + description = "var map for agent node hosts" +} +variable "master_hosts_var_maps" { + type = map + description = "var map for master node hosts" +} +variable "all_hosts_var_maps" { + type = map + description = "var map for all hosts" +} diff --git a/terraform/aws/base-infra/data.tf b/terraform/aws/base-infra/data.tf new file mode 100644 index 000000000..af7c21958 --- /dev/null +++ b/terraform/aws/base-infra/data.tf @@ -0,0 +1,23 @@ +data "aws_route53_zone" "public" { + count = var.create_public_zone ? 0 : 1 + name = "${local.cluster_domain}." +} + +data "aws_route53_zone" "private" { + count = var.create_private_zone ? 0 : 1 + name = "${local.cluster_domain}.internal." +} + +data "aws_route53_zone" "cluster_parent" { + count = var.manage_parent_domain ? 0 : 1 + name = "${local.cluster_parent_domain}." +} + +data "aws_route53_zone" "cluster_parent_parent" { + count = (var.manage_parent_domain && var.manage_parent_domain_ns) ? 1 : 0 + name = "${local.cluster_parent_parent_domain}." +} + +data "aws_availability_zones" "available" { + state = "available" +} \ No newline at end of file diff --git a/terraform/aws/base-infra/infra.tf b/terraform/aws/base-infra/infra.tf new file mode 100644 index 000000000..359e4ae9f --- /dev/null +++ b/terraform/aws/base-infra/infra.tf @@ -0,0 +1,102 @@ +############################# +### VPC +############################# + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "2.17.0" + + name = local.cluster_domain + cidr = var.vpc_cidr + + azs = local.azs + public_subnets = local.public_subnet_cidrs + private_subnets = local.private_subnet_cidrs + + create_database_subnet_group = false + + enable_dns_hostnames = true + enable_dns_support = true + enable_nat_gateway = true + + tags = merge({}, local.common_tags) + private_route_table_tags = { + subnet-type = "private-cluster" + } +} + +module "subnet_addrs" { + source = "hashicorp/subnets/cidr" + + base_cidr_block = var.vpc_cidr + networks = [ + for subnet in concat(local.private_subnets_list, local.public_subnets_list) : { + name = subnet + new_bits = var.block_size + } + ] + +} + +resource "aws_security_group" "bastion" { + name = "${local.cluster_domain}-bastion" + vpc_id = module.vpc.vpc_id + tags = merge({ Name = "${local.cluster_domain}-bastion" }, local.common_tags) +} + +resource "aws_security_group_rule" "bastion_ssh" { + type = "ingress" + from_port = 22 + to_port = 22 + protocol = "TCP" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.bastion.id +} + +resource "aws_security_group_rule" "bastion_wireguard" { + type = "ingress" + from_port = 51820 + to_port = 51825 + protocol = "udp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.bastion.id + description = "wireguard client access" +} + +resource "aws_security_group_rule" "bastion_egress_all" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.bastion.id +} + +resource "aws_instance" "bastion" { + ami = var.bastion_ami + instance_type = "t2.micro" + subnet_id = element(module.vpc.public_subnets, 0) + user_data = templatefile("${path.module}/templates/bastion.user_data.tmpl", { ssh_keys = local.ssh_keys }) + key_name = local.cluster_domain + + vpc_security_group_ids = [aws_security_group.bastion.id, module.vpc.default_security_group_id] + + tags = merge({ Name = "${local.cluster_domain}-bastion" }, local.common_tags) + volume_tags = merge({ Name = "${local.cluster_domain}-bastion" }, local.common_tags) + + lifecycle { + ignore_changes = [ + ami + ] + } +} + +resource "tls_private_key" "ec2_ssh_key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "aws_key_pair" "generated_key" { + key_name = local.cluster_domain + public_key = tls_private_key.ec2_ssh_key.public_key_openssh +} diff --git a/terraform/aws/base-infra/module_providers.tf b/terraform/aws/base-infra/module_providers.tf new file mode 100644 index 000000000..8e0b615ba --- /dev/null +++ b/terraform/aws/base-infra/module_providers.tf @@ -0,0 +1,6 @@ +terraform { + required_version = "~> 1.0" + required_providers { + aws = "~> 3.7" + } +} \ No newline at end of file diff --git a/terraform/aws/base-infra/netmaker.tf b/terraform/aws/base-infra/netmaker.tf new file mode 100644 index 000000000..605a2dce6 --- /dev/null +++ b/terraform/aws/base-infra/netmaker.tf @@ -0,0 +1,116 @@ +module "vpc_netmaker" { + count = var.enable_netmaker ? 1 : 0 + source = "terraform-aws-modules/vpc/aws" + version = "2.17.0" + + name = "${var.cluster_name}-netmaker" + cidr = var.netmaker_vpc_cidr + + azs = [local.azs[0]] + public_subnets = [module.netmaker_subnet_addrs[0].network_cidr_blocks["netmaker-public"]] + + create_database_subnet_group = false + + enable_dns_hostnames = true + enable_dns_support = true + + tags = merge({}, local.common_tags) + +} + +module "netmaker_subnet_addrs" { + count = var.enable_netmaker ? 1 : 0 + source = "hashicorp/subnets/cidr" + + base_cidr_block = var.netmaker_vpc_cidr + networks = [ + { + name = "netmaker-public" + new_bits = 1 + }, + ] + +} + +resource "aws_security_group" "netmaker" { + count = var.enable_netmaker ? 1 : 0 + name = "${local.cluster_domain}-netmaker" + vpc_id = module.vpc_netmaker[0].vpc_id + tags = merge({ Name = "${local.cluster_domain}-netmaker" }, local.common_tags) +} + +resource "aws_security_group_rule" "netmaker_ssh" { + count = var.enable_netmaker ? 1 : 0 + type = "ingress" + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.netmaker[0].id + description = "ssh access" + +} + +resource "aws_security_group_rule" "netmaker_wireguard" { + count = var.enable_netmaker ? 1 : 0 + type = "ingress" + from_port = 51820 + to_port = 51825 + protocol = "udp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.netmaker[0].id + description = "wireguard client access" +} + +resource "aws_security_group_rule" "netmaker_stun" { + count = var.enable_netmaker ? 1 : 0 + type = "ingress" + description = "netmaker stun server access" + from_port = 3478 + to_port = 3478 + protocol = "udp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.netmaker[0].id + +} + +resource "aws_security_group_rule" "netmaker_proxy" { + count = var.enable_netmaker ? 1 : 0 + type = "ingress" + description = "netmaker proxy access" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.netmaker[0].id +} + + +resource "aws_security_group_rule" "netmaker_egress_all" { + count = var.enable_netmaker ? 1 : 0 + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.netmaker[0].id +} + +resource "aws_instance" "netmaker" { + count = var.enable_netmaker ? 1 : 0 + ami = var.bastion_ami + instance_type = "t3.small" + subnet_id = element(module.vpc_netmaker[0].public_subnets, 0) + user_data = templatefile("${path.module}/templates/bastion.user_data.tmpl", { ssh_keys = local.ssh_keys }) + key_name = local.cluster_domain + + vpc_security_group_ids = [aws_security_group.netmaker[0].id, module.vpc_netmaker[0].default_security_group_id] + + tags = merge({ Name = "${local.cluster_domain}-netmaker" }, local.common_tags) + + lifecycle { + ignore_changes = [ + ami + ] + } +} diff --git a/terraform/aws/base-infra/output.tf b/terraform/aws/base-infra/output.tf new file mode 100644 index 000000000..2bf031078 --- /dev/null +++ b/terraform/aws/base-infra/output.tf @@ -0,0 +1,52 @@ +output "bastion_public_ip" { + description = "Bastion Instance Hostname" + value = aws_instance.bastion.public_ip +} + +output "ssh_private_key" { + description = "Private key in PEM format" + value = tls_private_key.ec2_ssh_key.private_key_pem + sensitive = true +} + +output "nat_public_ips" { + description = "nat gateway public ips" + value = module.vpc.nat_public_ips +} + +output "private_zone" { + value = local.private_zone +} + +output "public_zone" { + value = local.public_zone +} + +output "vpc_id" { + value = module.vpc.vpc_id +} + +output "public_subnets" { + value = module.vpc.public_subnets +} + +output "private_subnets" { + value = module.vpc.private_subnets +} + +output "default_security_group_id" { + value = module.vpc.default_security_group_id +} + +output "private_subnets_cidr_blocks" { + value = module.vpc.private_subnets_cidr_blocks +} + +output "netmaker_public_ip" { + description = "Netmaker Instance Hostname" + value = var.enable_netmaker ? aws_instance.netmaker[0].public_ip : null +} + +output "key_pair_name" { + value = local.cluster_domain +} \ No newline at end of file diff --git a/terraform/aws/base-infra/route53.tf b/terraform/aws/base-infra/route53.tf new file mode 100644 index 000000000..c0230ecd9 --- /dev/null +++ b/terraform/aws/base-infra/route53.tf @@ -0,0 +1,42 @@ +resource "aws_route53_zone" "private" { + force_destroy = var.route53_zone_force_destroy + count = var.create_private_zone ? 1 : 0 + name = "${local.cluster_domain}.internal." + + vpc { + vpc_id = module.vpc.vpc_id + } + tags = merge({ Name = "${local.cluster_domain}-private" }, local.common_tags) +} + +resource "aws_route53_zone" "public" { + force_destroy = var.route53_zone_force_destroy + count = var.create_public_zone ? 1 : 0 + name = "${local.cluster_domain}." + tags = merge({ Name = "${local.cluster_domain}-public" }, local.common_tags) +} + +resource "aws_route53_record" "public_ns" { + count = var.create_public_zone ? 1 : 0 + zone_id = local.cluster_parent_zone_id + name = local.cluster_domain + type = "NS" + ttl = "30" + records = aws_route53_zone.public[0].name_servers +} + +resource "aws_route53_zone" "cluster_parent" { + force_destroy = var.route53_zone_force_destroy + count = var.manage_parent_domain ? 1 : 0 + name = "${local.cluster_parent_domain}." + tags = merge({ Name = "${local.cluster_domain}-cluster-parent" }, local.common_tags) +} + +resource "aws_route53_record" "cluster_ns" { + count = (var.manage_parent_domain && var.manage_parent_domain_ns) ? 1 : 0 + zone_id = data.aws_route53_zone.cluster_parent_parent[0].zone_id + name = local.cluster_parent_domain + type = "NS" + ttl = "30" + records = aws_route53_zone.cluster_parent[0].name_servers +} \ No newline at end of file diff --git a/terraform/aws/base-infra/templates/bastion.user_data.tmpl b/terraform/aws/base-infra/templates/bastion.user_data.tmpl new file mode 100644 index 000000000..c1a66faec --- /dev/null +++ b/terraform/aws/base-infra/templates/bastion.user_data.tmpl @@ -0,0 +1,11 @@ +#cloud-config +%{ if length(ssh_keys) > 0 } +ssh_authorized_keys: +%{ for ssh_key in ssh_keys } +- ${ssh_key} +%{ endfor } +%{ endif } +runcmd: +- apt-get update +- apt-get install -y software-properties-common +- DEBIAN_FRONTEND=noninteractive apt-get upgrade -y diff --git a/terraform/aws/base-infra/variables.tf b/terraform/aws/base-infra/variables.tf new file mode 100644 index 000000000..9efbd597c --- /dev/null +++ b/terraform/aws/base-infra/variables.tf @@ -0,0 +1,104 @@ +### +# Required variables without default values +### +variable "cluster_name" { + description = "Cluster name, lower case and without spaces. This will be used to set tags and name resources" + type = string +} + +variable "domain" { + description = "Domain to attach the cluster to." + type = string +} + +variable "tags" { + description = "Contains default tags for this project" + type = map(string) + default = {} +} + +variable "vpc_cidr" { + default = "10.25.0.0/22" + type = string + description = "CIDR Subnet to use for the VPC, will be split into multiple /24s for the required private and public subnets" +} + +variable "create_public_zone" { + default = true + type = bool + description = "Whether to create public zone in route53. true or false, default true" +} + +variable "create_private_zone" { + default = true + type = bool + description = "Whether to create private zone in route53. true or false, default true" +} + variable "manage_parent_domain" { + default = false + type = bool + description = "whether parent domain should be created and managed here" + } + + variable "manage_parent_domain_ns" { + default = false + type = bool + description = "whether ns record should be created for parent domain in that parent's zone that should already exist" + } + +variable "az_count" { + type = number + default = 1 + description = "Number of azs" +} + +variable "route53_zone_force_destroy" { + description = "destroy public zone on destroy of env" + type = bool + default = false +} + +variable "bastion_ami" { + description = "ami for bastion" +} +variable "netmaker_ami" { + description = "ami for netmaker" + default = "none for enable_netmaker false" +} + +variable "block_size" { + type = number + default = 2 +} + +variable "enable_netmaker" { + type = bool + default = false +} + +variable "netmaker_vpc_cidr" { + type = string + default = "10.26.0.0/24" +} + +### +# Local copies of variables to allow for parsing +### +locals { + name = var.cluster_name + cluster_domain = "${replace(var.cluster_name, "-", "")}.${var.domain}" + cluster_parent_domain = join(".", [for idx, part in split(".", local.cluster_domain) : part if idx > 0]) + cluster_parent_parent_domain = join(".", [for idx, part in split(".", local.cluster_parent_domain) : part if idx > 0]) + identifying_tags = { Cluster = var.cluster_name, Domain = local.cluster_domain} + common_tags = merge(local.identifying_tags, var.tags) + azs = slice(data.aws_availability_zones.available.names, 0, var.az_count) + public_zone = var.create_public_zone ? aws_route53_zone.public[0] : data.aws_route53_zone.public[0] + private_zone = var.create_private_zone ? aws_route53_zone.private[0] : data.aws_route53_zone.private[0] + cluster_parent_zone_id = var.manage_parent_domain ? aws_route53_zone.cluster_parent[0].zone_id : data.aws_route53_zone.cluster_parent[0].zone_id + cluster_parent_parent_zone_id = (var.manage_parent_domain && var.manage_parent_domain_ns) ? data.aws_route53_zone.cluster_parent_parent[0].zone_id : null + ssh_keys = [] + public_subnets_list = [for az in local.azs : "public-${az}"] + private_subnets_list = [for az in local.azs : "private-${az}"] + public_subnet_cidrs = [for subnet_name in local.public_subnets_list : module.subnet_addrs.network_cidr_blocks[subnet_name]] + private_subnet_cidrs = [for subnet_name in local.private_subnets_list : module.subnet_addrs.network_cidr_blocks[subnet_name]] +} \ No newline at end of file diff --git a/terraform/aws/base-k8s/infra.tf b/terraform/aws/base-k8s/infra.tf new file mode 100644 index 000000000..43315ea1d --- /dev/null +++ b/terraform/aws/base-k8s/infra.tf @@ -0,0 +1,264 @@ +module "ubuntu_focal_ami" { + source = "git::https://github.com/mojaloop/iac-shared-modules.git//aws/ami-ubuntu?ref=v1.0.41" + release = "20.04" +} + +module "base_infra" { + source = "../base-infra" + cluster_name = var.cluster_name + domain = var.domain + tags = var.tags + vpc_cidr = var.vpc_cidr + create_public_zone = var.create_public_zone + create_private_zone = var.create_private_zone + manage_parent_domain = var.manage_parent_domain + manage_parent_domain_ns = var.manage_parent_domain_ns + az_count = var.az_count + route53_zone_force_destroy = var.route53_zone_force_destroy + bastion_ami = module.ubuntu_focal_ami.id +} + +module "post_config" { + source = "../post-config-k8s" + name = var.cluster_name + domain = var.domain + tags = var.tags + private_zone_id = module.base_infra.private_zone.id + public_zone_id = module.base_infra.public_zone.id + current_gitlab_project_id = var.current_gitlab_project_id + longhorn_backup_s3_destroy = var.longhorn_backup_s3_destroy +} + +############################# +### Create Nodes +############################# +resource "aws_launch_template" "master" { + name_prefix = "${local.name}-master" + image_id = module.ubuntu_focal_ami.id + instance_type = var.master_instance_type + user_data = data.template_cloudinit_config.master.rendered + key_name = module.base_infra.key_pair_name + + block_device_mappings { + device_name = "/dev/sda1" + + ebs { + encrypted = true + volume_type = "gp2" + volume_size = var.master_volume_size + } + } + + network_interfaces { + delete_on_termination = true + security_groups = local.master_security_groups + } + + + tags = merge( + { Name = "${local.name}-master" }, + local.common_tags + ) + + + tag_specifications { + resource_type = "instance" + + tags = merge( + { Name = "${local.name}-master" }, + local.common_tags + ) + } + tag_specifications { + resource_type = "volume" + + tags = merge( + { Name = "${local.name}-master" }, + local.common_tags + ) + } + tag_specifications { + resource_type = "network-interface" + + tags = merge( + { Name = "${local.name}-master" }, + local.common_tags + ) + } + lifecycle { + ignore_changes = [ + image_id + ] + } +} + +resource "aws_launch_template" "agent" { + name_prefix = "${local.name}-agent" + image_id = module.ubuntu_focal_ami.id + instance_type = var.agent_instance_type + user_data = data.template_cloudinit_config.agent.rendered + key_name = module.base_infra.key_pair_name + + block_device_mappings { + device_name = "/dev/sda1" + + ebs { + encrypted = true + volume_type = "gp2" + volume_size = var.agent_volume_size + } + } + + network_interfaces { + delete_on_termination = true + security_groups = [aws_security_group.ingress.id, aws_security_group.self.id, module.base_infra.default_security_group_id] + } + + tags = merge( + { Name = "${local.name}-agent" }, + local.common_tags + ) + + tag_specifications { + resource_type = "instance" + + tags = merge( + { Name = "${local.name}-agent" }, + local.common_tags + ) + } + tag_specifications { + resource_type = "volume" + + tags = merge( + { Name = "${local.name}-agent" }, + local.common_tags + ) + } + tag_specifications { + resource_type = "network-interface" + + tags = merge( + { Name = "${local.name}-agent" }, + local.common_tags + ) + } + lifecycle { + ignore_changes = [ + image_id + ] + } +} + +resource "aws_autoscaling_group" "master" { + name_prefix = "${local.name}-master" + desired_capacity = var.master_node_count + max_size = var.master_node_count + min_size = var.master_node_count + vpc_zone_identifier = module.base_infra.private_subnets + + # Join the master to the internal load balancer for the kube api on 6443 + target_group_arns = [ + aws_lb_target_group.internal_kubeapi.arn + ] + + launch_template { + id = aws_launch_template.master.id + version = "$Latest" + } + tags = concat( + [ + { + "key" = "Name" + "value" = "${local.name}-master" + "propagate_at_launch" = false + }, + { + "key" = "Cluster" + "value" = var.cluster_name + "propagate_at_launch" = false + }, + { + "key" = "Domain" + "value" = local.base_domain + "propagate_at_launch" = false + } + ] + ) +} + +resource "aws_autoscaling_group" "agent" { + name_prefix = "${local.name}-agent" + desired_capacity = var.agent_node_count + max_size = var.agent_node_count + min_size = var.agent_node_count + vpc_zone_identifier = module.base_infra.private_subnets + + target_group_arns = [ + aws_lb_target_group.external_http.arn, + aws_lb_target_group.external_https.arn, + aws_lb_target_group.internal_http.arn, + aws_lb_target_group.internal_https.arn, + aws_lb_target_group.wireguard.arn + ] + + launch_template { + id = aws_launch_template.agent.id + version = "$Latest" + } + tags = concat( + [ + { + "key" = "Name" + "value" = "${local.name}-agent" + "propagate_at_launch" = false + }, + { + "key" = "Cluster" + "value" = var.cluster_name + "propagate_at_launch" = false + }, + { + "key" = "Domain" + "value" = local.base_domain + "propagate_at_launch" = false + } + ] + ) + +} + +data "aws_instances" "master" { + instance_tags = merge({ Name = "${local.name}-master" }, local.identifying_tags) + depends_on = [aws_autoscaling_group.master] +} + +data "aws_instances" "agent" { + count = var.agent_node_count > 0 ? 1 : 0 + instance_tags = merge({ Name = "${local.name}-agent" }, local.identifying_tags) + depends_on = [aws_autoscaling_group.agent] +} + +data "template_cloudinit_config" "agent" { + gzip = true + base64_encode = true + + # Main cloud-config configuration file. + part { + filename = "init.cfg" + content_type = "text/cloud-config" + content = templatefile("${path.module}/templates/cloud-config-base.yaml", { ssh_keys = local.ssh_keys }) + } +} + +data "template_cloudinit_config" "master" { + gzip = true + base64_encode = true + + # Main cloud-config configuration file. + part { + filename = "init.cfg" + content_type = "text/cloud-config" + content = templatefile("${path.module}/templates/cloud-config-base.yaml", { ssh_keys = local.ssh_keys }) + } +} \ No newline at end of file diff --git a/terraform/aws/base-k8s/loadbalancer.tf b/terraform/aws/base-k8s/loadbalancer.tf new file mode 100644 index 000000000..8ae38ebe7 --- /dev/null +++ b/terraform/aws/base-k8s/loadbalancer.tf @@ -0,0 +1,189 @@ +# +# Internal load balancer +# +resource "aws_lb" "internal" { # for internal traffic, including kube traffic + internal = true + load_balancer_type = "network" + enable_cross_zone_load_balancing = true + subnets = module.base_infra.private_subnets + tags = merge({ Name = "${local.base_domain}-internal" }, local.common_tags) +} + +resource "aws_lb_listener" "internal_kubeapi" { + load_balancer_arn = aws_lb.internal.arn + port = var.kubeapi_port + protocol = "TCP" + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.internal_kubeapi.arn + } +} + +resource "aws_lb_target_group" "internal_kubeapi" { + port = var.kubeapi_port + protocol = "TCP" + vpc_id = module.base_infra.vpc_id + tags = merge({ Name = "${local.base_domain}-internal-kubeapi" }, local.common_tags) +} + +resource "aws_lb_listener" "internal_https" { + load_balancer_arn = aws_lb.internal.arn + port = "443" + protocol = "TCP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.internal_https.arn + } +} + +resource "aws_lb_target_group" "internal_https" { + port = var.target_group_internal_https_port + protocol = "TCP" + vpc_id = module.base_infra.vpc_id + + health_check { + interval = 10 + timeout = 6 + path = "/healthz" + port = var.target_group_internal_http_port + protocol = "HTTP" + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-399" + } + + tags = merge({ Name = "${local.base_domain}-internal-https" }, local.common_tags) +} + + +resource "aws_lb_listener" "internal_http" { + load_balancer_arn = aws_lb.internal.arn + port = "80" + protocol = "TCP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.internal_http.arn + } +} +resource "aws_lb_target_group" "internal_http" { + port = var.target_group_internal_http_port + protocol = "TCP" + vpc_id = module.base_infra.vpc_id + + health_check { + interval = 10 + timeout = 6 + path = "/healthz" + port = var.target_group_internal_http_port + protocol = "HTTP" + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-399" + } + + tags = merge({ Name = "${local.base_domain}-internal-http" }, local.common_tags) +} + +# +# External load balancer +# + + +resource "aws_lb" "lb" { + internal = false + load_balancer_type = "network" + subnets = module.base_infra.public_subnets + tags = merge({ Name = "${local.base_domain}-public" }, local.common_tags) +} + +resource "aws_lb_listener" "external_https" { + load_balancer_arn = aws_lb.lb.arn + port = "443" + protocol = "TCP" + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.external_https.arn + } +} + +resource "aws_lb_listener" "external_http" { + load_balancer_arn = aws_lb.lb.arn + port = "80" + protocol = "TCP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.external_http.arn + } +} + +resource "aws_lb_listener" "wireguard" { + load_balancer_arn = aws_lb.lb.arn + port = var.wireguard_port + protocol = "UDP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.wireguard.arn + } +} + +resource "aws_lb_target_group" "external_https" { + port = var.target_group_external_https_port + protocol = "TCP" + vpc_id = module.base_infra.vpc_id + preserve_client_ip = true + proxy_protocol_v2 = true + + health_check { + interval = 10 + timeout = 6 + path = "/healthz" + port = var.target_group_external_http_port + protocol = "HTTP" + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-399" + } + + tags = merge({ Name = "${local.base_domain}-external-https" }, local.common_tags) +} + +resource "aws_lb_target_group" "external_http" { + port = var.target_group_external_http_port + protocol = "TCP" + vpc_id = module.base_infra.vpc_id + preserve_client_ip = true + proxy_protocol_v2 = true + + health_check { + interval = 10 + timeout = 6 + path = "/healthz" + port = var.target_group_external_http_port + protocol = "HTTP" + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-399" + } + + tags = merge({ Name = "${local.base_domain}-external-http" }, local.common_tags) +} + + +resource "aws_lb_target_group" "wireguard" { + port = var.wireguard_port + protocol = "UDP" + vpc_id = module.base_infra.vpc_id + + # TODO: can't health check against a UDP port, but need to have a health check when backend is an instance. + # check tcp port 80 (ingress) for now, but probably need to add a http sidecar or something to act as a health check for wireguard + health_check { + protocol = "TCP" + port = var.target_group_external_http_port + } + + tags = merge({ Name = "${local.base_domain}-wireguard" }, local.common_tags) +} diff --git a/terraform/aws/base-k8s/outputs.tf b/terraform/aws/base-k8s/outputs.tf new file mode 100644 index 000000000..02537007a --- /dev/null +++ b/terraform/aws/base-k8s/outputs.tf @@ -0,0 +1,126 @@ +output "nat_public_ips" { + description = "nat gateway public ips" + value = module.base_infra.nat_public_ips +} + +output "internal_load_balancer_dns" { + value = aws_lb.internal.dns_name +} + +output "external_load_balancer_dns" { + value = aws_lb.lb.dns_name +} + +output "private_subdomain" { + value = module.base_infra.private_zone.name +} + +output "public_subdomain" { + value = module.base_infra.public_zone.name +} + +output "longhorn_backups_bucket_name" { + value = module.post_config.longhorn_backups_bucket_name +} + +output "gitlab_key_route53_external_dns_access_key" { + value = module.post_config.gitlab_key_route53_external_dns_access_key +} + +output "gitlab_key_route53_external_dns_secret_key" { + value = module.post_config.gitlab_key_route53_external_dns_secret_key +} + +output "gitlab_key_longhorn_backups_access_key" { + value = module.post_config.gitlab_key_longhorn_backups_access_key +} + +output "gitlab_key_longhorn_backups_secret_key" { + value = module.post_config.gitlab_key_longhorn_backups_secret_key +} + +output "gitlab_key_vault_iam_user_access_key" { + value = module.post_config.gitlab_key_vault_iam_user_access_key +} + +output "gitlab_key_vault_iam_user_secret_key" { + value = module.post_config.gitlab_key_vault_iam_user_secret_key +} + +output "vault_kms_seal_kms_key_id" { + value = module.post_config.vault_kms_seal_kms_key_id +} +output "target_group_internal_https_port" { + value = var.target_group_internal_https_port +} +output "target_group_internal_http_port" { + value = var.target_group_internal_http_port +} +output "target_group_external_https_port" { + value = var.target_group_external_https_port +} +output "target_group_external_http_port" { + value = var.target_group_external_http_port +} + + +###new items + +output "bastion_ssh_key" { + sensitive = true + value = module.base_infra.ssh_private_key +} + +output "bastion_public_ip" { + value = module.base_infra.bastion_public_ip +} + +output "bastion_os_username" { + value = var.os_user_name +} + +output "master_hosts_var_maps" { + sensitive = true + value = { + repo_url = var.gitlab_project_url + gitlab_server_url = var.gitlab_server_url + gitlab_project_id = var.current_gitlab_project_id + repo_username = var.gitlab_username + repo_password = var.gitlab_token + } +} + +output "all_hosts_var_maps" { + value = { + ansible_ssh_user = var.os_user_name + ansible_ssh_retries = "10" + base_domain = local.base_domain + } +} + +output "agent_hosts_var_maps" { + sensitive = false + value = { + master_ip = data.aws_instances.master.private_ips[0] + } +} + +output "bastion_hosts_var_maps" { + sensitive = true + value = { + ansible_ssh_common_args = "-o StrictHostKeyChecking=no" + netmaker_join_token = module.post_config.netmaker_token + } +} + +output "bastion_hosts" { + value = { bastion = module.base_infra.bastion_public_ip } +} + +output "agent_hosts" { + value = { for i, id in data.aws_instances.agent[0].ids : id => data.aws_instances.agent[0].private_ips[i] } +} + +output "master_hosts" { + value = { for i, id in data.aws_instances.master.ids : id => data.aws_instances.master.private_ips[i] } +} \ No newline at end of file diff --git a/terraform/aws/base-k8s/security-groups.tf b/terraform/aws/base-k8s/security-groups.tf new file mode 100644 index 000000000..a109aa845 --- /dev/null +++ b/terraform/aws/base-k8s/security-groups.tf @@ -0,0 +1,141 @@ +############################# +### Access Control +############################# + +resource "aws_security_group" "ingress" { + name = "${local.base_domain}-ingress" + vpc_id = module.base_infra.vpc_id + tags = merge({ Name = "${local.base_domain}-ingress" }, local.common_tags) +} + +resource "aws_security_group_rule" "ingress_http" { + type = "ingress" + from_port = var.target_group_external_http_port + to_port = var.target_group_external_http_port + protocol = "TCP" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_https" { + type = "ingress" + from_port = var.target_group_external_https_port + to_port = var.target_group_external_https_port + protocol = "TCP" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_http_internal" { + type = "ingress" + from_port = var.target_group_internal_http_port + to_port = var.target_group_internal_http_port + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_https_internal" { + type = "ingress" + from_port = var.target_group_internal_https_port + to_port = var.target_group_internal_https_port + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_vpn" { + type = "ingress" + from_port = var.wireguard_port + to_port = var.wireguard_port + protocol = "UDP" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_self" { + type = "ingress" + from_port = 0 + to_port = 0 + protocol = "-1" + self = true + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group_rule" "ingress_egress_all" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.ingress.id +} + +resource "aws_security_group" "self" { + name = "${local.base_domain}-self" + vpc_id = module.base_infra.vpc_id + tags = merge({ Name = "${local.base_domain}-self" }, local.common_tags) +} + +resource "aws_security_group_rule" "self_self" { + type = "ingress" + from_port = 0 + to_port = 0 + protocol = "-1" + self = true + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_master" { + type = "ingress" + from_port = 6443 + to_port = 6443 + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_https_external" { + type = "ingress" + from_port = 443 + to_port = 443 + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_http_external" { + type = "ingress" + from_port = 80 + to_port = 80 + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_https_internal" { + type = "ingress" + from_port = 8443 + to_port = 8443 + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_http_internal" { + type = "ingress" + from_port = 8080 + to_port = 8080 + protocol = "TCP" + cidr_blocks = [var.vpc_cidr] + security_group_id = aws_security_group.self.id +} + +resource "aws_security_group_rule" "self_egress_all" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.self.id +} diff --git a/terraform/aws/base-k8s/templates/cloud-config-base.yaml b/terraform/aws/base-k8s/templates/cloud-config-base.yaml new file mode 100644 index 000000000..c1a66faec --- /dev/null +++ b/terraform/aws/base-k8s/templates/cloud-config-base.yaml @@ -0,0 +1,11 @@ +#cloud-config +%{ if length(ssh_keys) > 0 } +ssh_authorized_keys: +%{ for ssh_key in ssh_keys } +- ${ssh_key} +%{ endfor } +%{ endif } +runcmd: +- apt-get update +- apt-get install -y software-properties-common +- DEBIAN_FRONTEND=noninteractive apt-get upgrade -y diff --git a/terraform/aws/base-k8s/variables.tf b/terraform/aws/base-k8s/variables.tf new file mode 100644 index 000000000..2fb6cee78 --- /dev/null +++ b/terraform/aws/base-k8s/variables.tf @@ -0,0 +1,173 @@ +### +# Required variables without default values +### +variable "cluster_name" { + description = "Cluster name, lower case and without spaces. This will be used to set tags and name resources" + type = string +} + +variable "domain" { + description = "Base domain to attach the cluster to." + type = string +} + +variable "tags" { + description = "Contains default tags for this project" + type = map(string) + default = {} +} + +variable "gitlab_project_url" { + type = string + description = "url for gitlab project" +} +variable "gitlab_username" { + type = string + description = "username to use wth gitlab" +} + +variable "gitlab_token" { + type = string + description = "token to use wth gitlab" + sensitive = true +} + +variable "current_gitlab_project_id" { + type = string + description = "current_gitlab_project_id" +} + +variable "gitlab_server_url" { + type = string + description = "gitlab_server_url to use wth gitlab" +} + +variable "vpc_cidr" { + default = "10.106.0.0/23" + type = string + description = "CIDR Subnet to use for the VPC, will be split into multiple /24s for the required private and public subnets" +} + +variable "create_public_zone" { + default = true + type = bool + description = "Whether to create public zone in route53. true or false, default true" +} + +variable "create_private_zone" { + default = true + type = bool + description = "Whether to create private zone in route53. true or false, default true" +} + +variable "manage_parent_domain" { + default = true + type = bool + description = "Whether to manage parent domain in terraform, default true" +} + +variable "manage_parent_domain_ns" { + default = true + type = bool + description = "Whether to manage parent domain ns record in terraform, default true" +} + +variable "master_node_count" { + type = number + default = 1 + description = "Number of master nodes to deploy" +} +variable "master_volume_size" { + type = number + default = 50 + description = "EBS Volume size (GB) attached to the master instance" +} +variable "master_instance_type" { + type = string + default = "t3.large" +} + +variable "agent_volume_size" { + type = number + default = 50 + description = "EBS Volume size (GB) attached to the agent/node instances" +} +variable "agent_node_count" { + type = number + default = 3 + description = "Number of agent nodes to deploy" +} +variable "agent_instance_type" { + type = string + default = "t3.large" +} + +variable "az_count" { + type = number + default = 1 + description = "Number of azs" +} + +variable "route53_zone_force_destroy" { + description = "destroy public zone on destroy of env" + type = bool + default = false +} + +variable "longhorn_backup_s3_destroy" { + description = "destroy s3 backup on destroy of env" + type = bool + default = false +} + +variable "os_user_name" { + default = "ubuntu" + type = string + description = "os username for bastion host" +} + +variable "kubeapi_port" { + type = number + description = "kubeapi_port" + default = 6443 +} + +variable "wireguard_port" { + type = number + description = "wireguard_port" + default = 51820 +} +variable "target_group_internal_https_port" { + type = number + description = "target_group_internal_https_port" + default = 31443 +} +variable "target_group_internal_http_port" { + type = number + description = "target_group_internal_http_port" + default = 31080 +} + +variable "target_group_external_https_port" { + type = number + description = "target_group_external_https_port" + default = 32443 + +} +variable "target_group_external_http_port" { + type = number + description = "target_group_external_http_port" + default = 32080 +} + +### +# Local copies of variables to allow for parsing +### +locals { + name = var.cluster_name + base_domain = "${replace(var.cluster_name, "-", "")}.${var.domain}" + identifying_tags = { Cluster = var.cluster_name, Domain = local.base_domain} + common_tags = merge(local.identifying_tags, var.tags) + master_security_groups = [aws_security_group.self.id, module.base_infra.default_security_group_id] + ssh_keys = [] # This has been replaced with a dynamically generated key, but could be extended to allow passing additional ssh keys if needed +} \ No newline at end of file diff --git a/terraform/aws/control-center-infra/iam.tf b/terraform/aws/control-center-infra/iam.tf new file mode 100644 index 000000000..08dba067d --- /dev/null +++ b/terraform/aws/control-center-infra/iam.tf @@ -0,0 +1,46 @@ + + +resource "aws_iam_instance_profile" "gitlab" { + name = "${replace(var.domain, ".", "-")}-${var.cluster_name}-gitlab" + role = aws_iam_role.gitlab.name +} + +resource "aws_iam_role" "gitlab" { + name = "${replace(var.domain, ".", "-")}-${var.cluster_name}-gitlab" + path = "/" + + assume_role_policy = data.aws_iam_policy_document.gitlab.json +} + +data "aws_iam_policy_document" "gitlab" { + statement { + sid = "" + + actions = [ + "sts:AssumeRole", + ] + + principals { + type = "Service" + identifiers = ["ec2.amazonaws.com"] + } + + effect = "Allow" + } +} + +resource "aws_iam_user" "gitlab_ci_iam_user" { + name = "${var.cluster_name}-gitlab-ci" + tags = merge({ Name = "${local.name}-gitlab-ci" }, local.common_tags) +} + +resource "aws_iam_access_key" "gitlab_ci_iam_user_key" { + user = aws_iam_user.gitlab_ci_iam_user.name +} + +resource "aws_iam_user_group_membership" "iac_group" { + user = aws_iam_user.gitlab_ci_iam_user.name + groups = [ + var.iac_group_name + ] +} \ No newline at end of file diff --git a/terraform/aws/control-center-infra/infra.tf b/terraform/aws/control-center-infra/infra.tf new file mode 100644 index 000000000..e792d4512 --- /dev/null +++ b/terraform/aws/control-center-infra/infra.tf @@ -0,0 +1,87 @@ +module "ubuntu_focal_ami" { + source = "git::https://github.com/mojaloop/iac-shared-modules.git//aws/ami-ubuntu?ref=v1.0.41" + release = "20.04" +} + +module "base_infra" { + source = "../base-infra" + + cluster_name = var.cluster_name + domain = var.domain + tags = var.tags + vpc_cidr = var.vpc_cidr + create_public_zone = var.create_public_zone + create_private_zone = var.create_private_zone + az_count = var.az_count + route53_zone_force_destroy = var.route53_zone_force_destroy + bastion_ami = module.ubuntu_focal_ami.id + netmaker_ami = module.ubuntu_focal_ami.id + enable_netmaker = var.enable_netmaker +} + +module "post_config" { + source = "../post-config-control-center" + name = local.name + domain = local.base_domain + zone_id = module.base_infra.public_zone.zone_id + tags = var.tags + days_retain_gitlab_snapshot = var.days_retain_gitlab_snapshot +} + +resource "aws_instance" "gitlab_server" { + ami = module.ubuntu_focal_ami.id + instance_type = var.gitlab_instance_type + associate_public_ip_address = true + vpc_security_group_ids = [aws_security_group.gitlab_server.id] + iam_instance_profile = aws_iam_instance_profile.gitlab.name + key_name = module.base_infra.key_pair_name + subnet_id = module.base_infra.public_subnets[0] + tags = merge({ Name = "${local.name}-gitlab-server" }, local.common_tags) + + volume_tags = merge({ Name = "${local.name}-gitlab-server" }, local.common_tags) + root_block_device { + delete_on_termination = var.delete_storage_on_term + volume_type = "gp2" + volume_size = var.gitlab_server_root_vol_size + } + + ebs_block_device { + delete_on_termination = var.delete_storage_on_term + device_name = "/dev/xvdb" + volume_type = "gp2" + volume_size = var.gitlab_server_extra_vol_size + } + + lifecycle { + ignore_changes = [ + ami + ] + } +} + +resource "aws_instance" "docker_server" { + ami = module.ubuntu_focal_ami.id + instance_type = var.docker_server_instance_type + associate_public_ip_address = false + vpc_security_group_ids = [aws_security_group.docker_server.id] + key_name = module.base_infra.key_pair_name + subnet_id = module.base_infra.private_subnets[0] + tags = merge({ Name = "${local.name}-docker-server" }, local.common_tags) + volume_tags = merge({ Name = "${local.name}-docker-server" }, local.common_tags) + root_block_device { + delete_on_termination = var.delete_storage_on_term + volume_type = "gp2" + volume_size = var.docker_server_root_vol_size + } + ebs_block_device { + delete_on_termination = var.delete_storage_on_term + device_name = "/dev/xvdb" + volume_type = "gp2" + volume_size = var.docker_server_extra_vol_size + } + lifecycle { + ignore_changes = [ + ami + ] + } +} diff --git a/terraform/aws/control-center-infra/outputs.tf b/terraform/aws/control-center-infra/outputs.tf new file mode 100644 index 000000000..b88fc04fe --- /dev/null +++ b/terraform/aws/control-center-infra/outputs.tf @@ -0,0 +1,176 @@ +output "gitlab_root_password" { + sensitive = true + value = random_password.gitlab_root_password.result +} + +output "gitlab_root_token" { + sensitive = true + value = random_password.gitlab_root_token.result +} + +output "gitlab_s3_access_key" { + sensitive = true + value = random_password.gitlab_s3_access_key.result +} + +output "gitlab_s3_access_secret" { + sensitive = true + value = random_password.gitlab_s3_access_secret.result +} + +output "admin_s3_access_key" { + sensitive = true + value = random_password.admin_s3_access_key.result +} + +output "admin_s3_access_secret" { + sensitive = true + value = random_password.admin_s3_access_secret.result +} + +output "nexus_admin_password" { + sensitive = true + value = random_password.nexus_admin_password.result +} + +output "netmaker_oidc_callback_url" { + value = var.enable_netmaker ? "https://${aws_route53_record.netmaker_api[0].name}/api/oauth/callback" : "" +} + +output "gitlab_server_hostname" { + value = aws_route53_record.gitlab_server_public.fqdn +} + +output "bastion_ssh_key" { + sensitive = true + value = module.base_infra.ssh_private_key +} + +output "bastion_public_ip" { + value = module.base_infra.bastion_public_ip +} + +output "bastion_os_username" { + value = var.os_user_name +} + +output "nexus_docker_repo_listening_port" { + value = var.nexus_docker_repo_listening_port +} + +output "nexus_fqdn" { + value = aws_route53_record.nexus_server_private.fqdn +} + +output "gitlab_hosts_var_maps" { + sensitive = true + value = { + ansible_hostname = aws_route53_record.gitlab_server_public.fqdn + smtp_server_enable = var.smtp_server_enable + smtp_server_address = var.smtp_server_address + smtp_server_port = var.smtp_server_port + smtp_server_user = var.smtp_server_user + smtp_server_pw = var.smtp_server_pw + smtp_server_mail_domain = var.smtp_server_mail_domain + enable_github_oauth = var.enable_github_oauth + github_oauth_id = var.github_oauth_id + github_oauth_secret = var.github_oauth_secret + letsencrypt_endpoint = var.acme_api_endpoint + server_password = random_password.gitlab_root_password.result + server_token = random_password.gitlab_root_token.result + server_hostname = aws_route53_record.gitlab_server_public.fqdn + enable_pages = false + gitlab_version = var.gitlab_version + s3_username = random_password.gitlab_s3_access_key.result + s3_password = random_password.gitlab_s3_access_secret.result + s3_server_url = "http://${aws_route53_record.seaweedfs_server_private.fqdn}:${var.seaweedfs_s3_listening_port}" + backup_ebs_volume_id = aws_instance.gitlab_server.ebs_block_device.*.volume_id[0] + } +} + +output "all_hosts_var_maps" { + value = { + ansible_ssh_user = var.os_user_name + ansible_ssh_retries = "10" + base_domain = local.base_domain + gitlab_external_url = "https://${aws_route53_record.gitlab_server_public.fqdn}" + } +} + +output "docker_hosts_var_maps" { + sensitive = true + value = { + ansible_hostname = aws_route53_record.gitlab_runner_server_private.fqdn + gitlab_server_hostname = aws_route53_record.gitlab_server_public.fqdn + gitlab_runner_version = var.gitlab_runner_version + seaweedfs_s3_server_host = aws_route53_record.seaweedfs_server_private.fqdn + seaweedfs_s3_listening_port = var.seaweedfs_s3_listening_port + seaweedfs_s3_admin_user = "admin" + seaweedfs_s3_admin_access_key = random_password.admin_s3_access_key.result + seaweedfs_s3_admin_secret_key = random_password.admin_s3_access_secret.result + seaweedfs_s3_gitlab_user = "gitlab" + seaweedfs_s3_gitlab_access_key = random_password.gitlab_s3_access_key.result + seaweedfs_s3_gitlab_secret_key = random_password.gitlab_s3_access_secret.result + nexus_admin_password = random_password.nexus_admin_password.result + nexus_docker_repo_listening_port = var.nexus_docker_repo_listening_port + docker_extra_volume_name = "docker-extra" + docker_extra_vol_mount = true + docker_extra_ebs_volume_id = aws_instance.docker_server.ebs_block_device.*.volume_id[0] + docker_extra_volume_size_mb = aws_instance.docker_server.ebs_block_device.*.volume_size[0] * 1074 + seaweedfs_num_volumes = 100 + } +} + +output "netmaker_hosts_var_maps" { + sensitive = true + value = { + netmaker_base_domain = aws_route53_record.public_netmaker_ns[0].name + netmaker_server_public_ip = module.base_infra.netmaker_public_ip + netmaker_image_version = var.netmaker_image_version + netmaker_master_key = random_password.netmaker_master_key.result + netmaker_mq_pw = random_password.netmaker_mq_pw.result + netmaker_admin_password = random_password.netmaker_admin_password.result + netmaker_oidc_issuer = "https://${aws_route53_record.gitlab_server_public.fqdn}" + netmaker_control_network_name = var.netmaker_control_network_name + ansible_ssh_common_args = "-o StrictHostKeyChecking=no" + } +} + +output "bastion_hosts_var_maps" { + value = { + netmaker_image_version = var.netmaker_image_version + ansible_ssh_common_args = "-o StrictHostKeyChecking=no" + } +} + +output "bastion_hosts" { + value = { bastion = module.base_infra.bastion_public_ip } +} + +output "docker_hosts" { + value = { docker = aws_instance.docker_server.private_ip } +} + +output "gitlab_hosts" { + value = { gitlab_server = aws_instance.gitlab_server.private_ip } +} + +output "netmaker_hosts" { + value = { netmaker_server = module.base_infra.netmaker_public_ip } +} + +output "iac_user_key_id" { + description = "key id for iac user for gitlab-ci" + value = aws_iam_access_key.gitlab_ci_iam_user_key.id + sensitive = false +} + +output "iac_user_key_secret" { + description = "key secret for iac user for gitlab-ci" + value = aws_iam_access_key.gitlab_ci_iam_user_key.secret + sensitive = true +} + +output "public_zone_name" { + value = module.base_infra.public_zone.name +} diff --git a/terraform/aws/control-center-infra/random-pws.tf b/terraform/aws/control-center-infra/random-pws.tf new file mode 100644 index 000000000..b77a0cad2 --- /dev/null +++ b/terraform/aws/control-center-infra/random-pws.tf @@ -0,0 +1,57 @@ +resource "random_password" "gitlab_root_password" { + length = 16 + special = true + override_special = "_" +} + +resource "random_password" "gitlab_root_token" { + length = 20 + special = true + override_special = "_" +} + +resource "random_password" "gitlab_s3_access_key" { + length = 20 + special = false +} + +resource "random_password" "gitlab_s3_access_secret" { + length = 20 + special = true + override_special = "_" +} + +resource "random_password" "admin_s3_access_key" { + length = 20 + special = false +} + +resource "random_password" "admin_s3_access_secret" { + length = 20 + special = true + override_special = "_" +} + +resource "random_password" "nexus_admin_password" { + length = 20 + special = true + override_special = "_" +} + +resource "random_password" "netmaker_master_key" { + length = 30 + special = true + override_special = "_" +} + +resource "random_password" "netmaker_mq_pw" { + length = 30 + special = true + override_special = "_" +} + +resource "random_password" "netmaker_admin_password" { + length = 30 + special = true + override_special = "_" +} diff --git a/terraform/aws/control-center-infra/route53.tf b/terraform/aws/control-center-infra/route53.tf new file mode 100644 index 000000000..9b9691a9d --- /dev/null +++ b/terraform/aws/control-center-infra/route53.tf @@ -0,0 +1,83 @@ +resource "aws_route53_record" "gitlab_server_public" { + zone_id = module.base_infra.public_zone.id + name = "gitlab" + type = "CNAME" + ttl = "300" + records = [aws_instance.gitlab_server.public_dns] +} + +resource "aws_route53_zone" "public_netmaker" { + count = var.enable_netmaker ? 1 : 0 + force_destroy = var.route53_zone_force_destroy + name = "netmaker.${module.base_infra.public_zone.name}" + tags = merge({ Name = "${local.name}-public-netmaker" }, local.common_tags) +} + +resource "aws_route53_record" "public_netmaker_ns" { + count = var.enable_netmaker ? 1 : 0 + zone_id = module.base_infra.public_zone.id + name = "netmaker.${module.base_infra.public_zone.name}" + type = "NS" + ttl = "30" + records = aws_route53_zone.public_netmaker[0].name_servers +} + +resource "aws_route53_record" "netmaker_dashboard" { + count = var.enable_netmaker ? 1 : 0 + zone_id = aws_route53_zone.public_netmaker[0].id + name = "dashboard.${aws_route53_zone.public_netmaker[0].name}" + type = "A" + ttl = "300" + records = [module.base_infra.netmaker_public_ip] +} + +resource "aws_route53_record" "netmaker_api" { + count = var.enable_netmaker ? 1 : 0 + zone_id = aws_route53_zone.public_netmaker[0].id + name = "api.${aws_route53_zone.public_netmaker[0].name}" + type = "A" + ttl = "300" + records = [module.base_infra.netmaker_public_ip] +} + +resource "aws_route53_record" "netmaker_broker" { + count = var.enable_netmaker ? 1 : 0 + zone_id = aws_route53_zone.public_netmaker[0].id + name = "broker.${aws_route53_zone.public_netmaker[0].name}" + type = "A" + ttl = "300" + records = [module.base_infra.netmaker_public_ip] +} + +resource "aws_route53_record" "netmaker_stun" { + count = var.enable_netmaker ? 1 : 0 + zone_id = aws_route53_zone.public_netmaker[0].id + name = "stun.${aws_route53_zone.public_netmaker[0].name}" + type = "A" + ttl = "300" + records = [module.base_infra.netmaker_public_ip] +} + +resource "aws_route53_record" "nexus_server_private" { + zone_id = module.base_infra.private_zone.id + name = "nexus" + type = "A" + ttl = "300" + records = [aws_instance.docker_server.private_ip] +} + +resource "aws_route53_record" "seaweedfs_server_private" { + zone_id = module.base_infra.private_zone.id + name = "seaweedfs" + type = "A" + ttl = "300" + records = [aws_instance.docker_server.private_ip] +} + +resource "aws_route53_record" "gitlab_runner_server_private" { + zone_id = module.base_infra.private_zone.id + name = "gitlab_runner" + type = "A" + ttl = "300" + records = [aws_instance.docker_server.private_ip] +} \ No newline at end of file diff --git a/terraform/aws/control-center-infra/security-groups.tf b/terraform/aws/control-center-infra/security-groups.tf new file mode 100644 index 000000000..8b7c646c7 --- /dev/null +++ b/terraform/aws/control-center-infra/security-groups.tf @@ -0,0 +1,98 @@ +resource "aws_security_group" "gitlab_server" { + name = "gitlab_server" + vpc_id = module.base_infra.vpc_id + description = "GitLab security group (SSH, HTTP/S inbound access is allowed)" + + tags = var.tags + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + } + + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 5050 + to_port = 5050 + protocol = "tcp" + cidr_blocks = concat([var.vpc_cidr], local.nat_gatewway_cidr_blocks) + description = "GitLab Container Registry" + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_security_group" "docker_server" { + name = "docker_server" + vpc_id = module.base_infra.vpc_id + description = "docker_server security group (SSH, individual docker service ports)" + + tags = var.tags + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + } + + + ingress { + description = "nexus admin access" + from_port = var.nexus_admin_listening_port + to_port = var.nexus_admin_listening_port + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + } + + ingress { + description = "nexus docker repo http access" + from_port = var.nexus_docker_repo_listening_port + to_port = var.nexus_docker_repo_listening_port + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + } + + ingress { + description = "seaweedfs s3 access" + from_port = var.seaweedfs_s3_listening_port + to_port = var.seaweedfs_s3_listening_port + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + lifecycle { + create_before_destroy = true + } +} \ No newline at end of file diff --git a/terraform/aws/control-center-infra/variables.tf b/terraform/aws/control-center-infra/variables.tf new file mode 100644 index 000000000..9a7890916 --- /dev/null +++ b/terraform/aws/control-center-infra/variables.tf @@ -0,0 +1,223 @@ +variable "cluster_name" { + description = "Cluster name, lower case and without spaces. This will be used to set tags and name resources" + type = string +} + +variable "domain" { + description = "Base domain to attach the cluster to." + type = string +} + +variable "tags" { + description = "Contains default tags for this project" + type = map(string) + default = {} +} + +variable "vpc_cidr" { + default = "10.25.0.0/22" + type = string + description = "CIDR Subnet to use for the VPC" +} + +variable "create_public_zone" { + default = true + type = bool + description = "Whether to create public zone in route53. true or false, default true" +} + +variable "create_private_zone" { + default = true + type = bool + description = "Whether to create private zone in route53. true or false, default true" +} + +variable "route53_zone_force_destroy" { + description = "destroy public zone on destroy of env" + type = bool + default = false +} + +variable "az_count" { + type = number + default = 1 + description = "Number of azs" +} + +variable "os_user_name" { + default = "ubuntu" + type = string + description = "os username for bastion host" +} + +variable "delete_storage_on_term" { + description = "delete_storage_on_term" + type = bool + default = false +} + +variable "enable_github_oauth" { + type = bool + description = "enable auth from github oauth app" + default = false +} + +variable "github_oauth_id" { + type = string + description = "github oauth id" + default = "" +} + +variable "github_oauth_secret" { + type = string + description = "github oauth secret" + default = "" + sensitive = true +} + +variable "smtp_server_enable" { + type = bool + description = "enable smtp server (ses)" + default = false +} + +variable "smtp_server_address" { + type = string + description = "smtp_server_address" + default = "" +} + +variable "smtp_server_port" { + type = number + description = "smtp_server_port" + default = 587 +} + +variable "smtp_server_user" { + type = string + description = "smtp_server_user" + default = "" +} + +variable "smtp_server_pw" { + type = string + description = "smtp_server_pw" + default = "" + sensitive = true +} + +variable "smtp_server_mail_domain" { + type = string + description = "smtp_server_mail_domain" + default = "" +} + +variable "acme_api_endpoint" { + type = string + description = "endpoint for acme certs" + default = "https://acme-v02.api.letsencrypt.org/directory" +} + +variable "nexus_docker_repo_listening_port" { + type = number + default = 8082 + description = "which port to listen for hosting docker repo on nexus" +} + +variable "nexus_admin_listening_port" { + type = number + default = 8081 + description = "which port to listen for nexus admin" +} + +variable "seaweedfs_s3_listening_port" { + type = number + default = 8333 + description = "which port to listen for seaweed s3" +} + +variable "days_retain_gitlab_snapshot" { + type = number + description = "number of days to retain gitlab snapshots" + default = 7 +} + +variable "gitlab_instance_type" { + type = string + default = "m5.large" + description = "vm size for gitlab server" +} + +variable "docker_server_instance_type" { + type = string + default = "m5.2xlarge" + description = "vm size for docker server" +} + +variable "gitlab_server_root_vol_size" { + type = number + default = 40 + description = "root vol size for gitlab server" +} + +variable "gitlab_server_extra_vol_size" { + type = number + default = 100 + description = "extra vol size for gitlab server" +} + +variable "docker_server_root_vol_size" { + type = number + default = 40 + description = "root vol size for docker server" +} + +variable "docker_server_extra_vol_size" { + type = number + default = 100 + description = "extra vol size for docker server" +} + +variable "gitlab_version" { + type = string + description = "gitlab_version" + default = "15.11.0" +} + +variable "gitlab_runner_version" { + type = string + description = "gitlab_runner_version" + default = "15.11.0" +} + +variable "enable_netmaker" { + type = bool + default = true + description = "enable creation of netmaker vpc/vm" +} + +variable "netmaker_image_version" { + type = string + description = "netmaker_image_version" + default = "0.18.7" +} + +variable "netmaker_control_network_name" { + type = string + description = "control center netmaker network name" + default = "cntrlctr" +} + +variable "iac_group_name" { + type = string + description = "iac group name" + default = "admin" +} + +locals { + name = var.cluster_name + base_domain = "${replace(var.cluster_name, "-", "")}.${var.domain}" + identifying_tags = { Cluster = var.cluster_name, Domain = local.base_domain} + common_tags = merge(local.identifying_tags, var.tags) + nat_gatewway_cidr_blocks = [for ip in module.base_infra.nat_public_ips : "${ip}/32"] +} \ No newline at end of file diff --git a/terraform/aws/post-config-control-center/backup.tf b/terraform/aws/post-config-control-center/backup.tf new file mode 100644 index 000000000..a45afbb05 --- /dev/null +++ b/terraform/aws/post-config-control-center/backup.tf @@ -0,0 +1,85 @@ +resource "aws_iam_role" "dlm_lifecycle_role" { + name = "dlm-lifecycle-role-${var.domain}" + + assume_role_policy = < val } +} + +include "root" { + path = find_in_parent_folders() +} diff --git a/terraform/control-center/init/ansible-cc-netmaker-deploy/terragrunt.hcl b/terraform/control-center/init/ansible-cc-netmaker-deploy/terragrunt.hcl new file mode 100644 index 000000000..c73dc9714 --- /dev/null +++ b/terraform/control-center/init/ansible-cc-netmaker-deploy/terragrunt.hcl @@ -0,0 +1,53 @@ +terraform { + source = "git::https://github.com/mojaloop/iac-modules.git//terraform/ansible/control-center-netmaker-deploy?ref=${get_env("IAC_TERRAFORM_MODULES_TAG")}" +} + +dependency "control_center_deploy" { + config_path = "../control-center-deploy" + mock_outputs = { + bastion_hosts = {} + netmaker_hosts = {} + bastion_hosts_var_maps = {} + netmaker_hosts_var_maps = {} + all_hosts_var_maps = {} + gitlab_server_hostname = "temporary-dummy-id" + bastion_ssh_key = "key" + bastion_os_username = "null" + bastion_public_ip = "null" + } + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "show"] +} + +dependency "control_center_gitlab_config" { + config_path = "../control-center-gitlab-config" + mock_outputs = { + netmaker_hosts_var_maps = {} + } + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] +} + +inputs = { + bastion_hosts = dependency.control_center_deploy.outputs.bastion_hosts + netmaker_hosts = dependency.control_center_deploy.outputs.netmaker_hosts + bastion_hosts_var_maps = dependency.control_center_deploy.outputs.bastion_hosts_var_maps + netmaker_hosts_var_maps = merge(dependency.control_center_deploy.outputs.netmaker_hosts_var_maps, dependency.control_center_gitlab_config.outputs.netmaker_hosts_var_maps) + all_hosts_var_maps = dependency.control_center_deploy.outputs.all_hosts_var_maps + enable_netmaker_oidc = local.env_vars.enable_netmaker_oidc + ansible_bastion_key = dependency.control_center_deploy.outputs.bastion_ssh_key + ansible_bastion_os_username = dependency.control_center_deploy.outputs.bastion_os_username + ansible_bastion_public_ip = dependency.control_center_deploy.outputs.bastion_public_ip + ansible_collection_tag = local.env_vars.ansible_collection_tag + ansible_base_output_dir = get_env("ANSIBLE_BASE_OUTPUT_DIR") + env_map = local.env_map +} + +locals { + env_vars = yamldecode( + file("${find_in_parent_folders("environment.yaml")}")) + env_map = { for val in local.env_vars.envs : + val["env"] => val } +} + +include "root" { + path = find_in_parent_folders() +} diff --git a/terraform/control-center/init/aws-vars.yaml b/terraform/control-center/init/aws-vars.yaml new file mode 100644 index 000000000..c30b5e185 --- /dev/null +++ b/terraform/control-center/init/aws-vars.yaml @@ -0,0 +1,2 @@ +aws_provider_version: "~> 3.7" +awsutils_provider_version: ">= 0.11.0" \ No newline at end of file diff --git a/terraform/control-center/init/common-vars.yaml b/terraform/control-center/init/common-vars.yaml new file mode 100644 index 000000000..95c23e3b9 --- /dev/null +++ b/terraform/control-center/init/common-vars.yaml @@ -0,0 +1,3 @@ +tf_version: ">= 1.1" +local_provider_version: "~> 2.2" +gitlab_provider_version: "~> 15.11" \ No newline at end of file diff --git a/terraform/control-center/init/control-center-deploy/terragrunt.hcl b/terraform/control-center/init/control-center-deploy/terragrunt.hcl new file mode 100644 index 000000000..9b25883bd --- /dev/null +++ b/terraform/control-center/init/control-center-deploy/terragrunt.hcl @@ -0,0 +1,56 @@ +terraform { + source = "git::https://github.com/mojaloop/iac-modules.git//terraform/${get_env("CONTROL_CENTER_CLOUD_PROVIDER")}/control-center-infra?ref=${get_env("IAC_TERRAFORM_MODULES_TAG")}" +} + + +generate "required_providers_override" { + path = "required_providers_override.tf" + + if_exists = "overwrite_terragrunt" + + contents = < merge(local.env_map[key], dependency.ansible_cc_netmaker_deploy.outputs.netmaker_token_map[key]) if length(dependency.ansible_cc_netmaker_deploy.outputs.netmaker_token_map) > 0 } + iac_group_id = dependency.control_center_gitlab_config.outputs.iac_group_id +} + +locals { + env_vars = yamldecode( + file("${find_in_parent_folders("environment.yaml")}") + ) + common_vars = yamldecode( + file("${find_in_parent_folders("common-vars.yaml")}") + ) + + env_map = { for val in local.env_vars.envs : + val["env"] => { + cloud_platform = val["cloud_platform"] + k8s_cluster_type = val["k8s_cluster_type"] + cloud_platform = val["cloud_platform"] + domain = val["domain"] + iac_terraform_modules_tag = val["iac_terraform_modules_tag"] + enable-vault-oauth-to-gitlab = val["enable-vault-oauth-to-gitlab"] + } + } +} + +include "root" { + path = find_in_parent_folders() +} + + + +generate "required_providers_override" { + path = "required_providers_override.tf" + + if_exists = "overwrite_terragrunt" + + contents = </tmp/archivedhttpstate.sh +export PRIVATE_REPO_USER=${PRIVATE_REPO_USER} +export PRIVATE_REPO_TOKEN=${PRIVATE_REPO_TOKEN} +export AWS_PROFILE=${AWS_PROFILE} +export TF_HTTP_USERNAME=${TF_HTTP_USERNAME} +export PROJECT_ID=${PROJECT_ID} +export GITLAB_URL=${GITLAB_URL} +export TF_STATE_BASE_ADDRESS=${TF_STATE_BASE_ADDRESS} +export TF_HTTP_LOCK_METHOD=${TF_HTTP_LOCK_METHOD} +export TF_HTTP_UNLOCK_METHOD=${TF_HTTP_UNLOCK_METHOD} +export TF_HTTP_RETRY_WAIT_MIN=${TF_HTTP_RETRY_WAIT_MIN} +export TF_HTTP_PASSWORD=${TF_HTTP_PASSWORD} +export IAC_TEMPLATES_TAG=${IAC_TEMPLATES_TAG} +EOT +cat <<'EOT' >terragrunt.hcl +skip = true +generate "backend" { + path = "backend.tf" + if_exists = "overwrite_terragrunt" + contents = <:,: + # The control plane has different scopes depending on component, but can configure default log level across all components + # If empty, default scope and level will be used as configured in code + logging: + level: "default:info" + + omitSidecarInjectorConfigMap: false + + # Whether to restrict the applications namespace the controller manages; + # If not set, controller watches all namespaces + oneNamespace: false + + # Configure whether Operator manages webhook configurations. The current behavior + # of Istiod is to manage its own webhook configurations. + # When this option is set as true, Istio Operator, instead of webhooks, manages the + # webhook configurations. When this option is set as false, webhooks manage their + # own webhook configurations. + operatorManageWebhooks: false + + # Custom DNS config for the pod to resolve names of services in other + # clusters. Use this to add additional search domains, and other settings. + # see + # https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config + # This does not apply to gateway pods as they typically need a different + # set of DNS settings than the normal application pods (e.g., in + # multicluster scenarios). + # NOTE: If using templates, follow the pattern in the commented example below. + #podDNSSearchNamespaces: + #- global + #- "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global" + + # Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and + # system-node-critical, it is better to configure this in order to make sure your Istio pods + # will not be killed because of low priority class. + # Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + # for more detail. + priorityClassName: "" + + proxy: + image: proxyv2 + + # This controls the 'policy' in the sidecar injector. + autoInject: enabled + + # CAUTION: It is important to ensure that all Istio helm charts specify the same clusterDomain value + # cluster domain. Default value is "cluster.local". + clusterDomain: "cluster.local" + + # Per Component log level for proxy, applies to gateways and sidecars. If a component level is + # not set, then the global "logLevel" will be used. + componentLogLevel: "misc:error" + + # If set, newly injected sidecars will have core dumps enabled. + enableCoreDump: false + + # istio ingress capture allowlist + # examples: + # Redirect only selected ports: --includeInboundPorts="80,8080" + excludeInboundPorts: "" + includeInboundPorts: "*" + + # istio egress capture allowlist + # https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly + # example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16" + # would only capture egress traffic on those two IP Ranges, all other outbound traffic would + # be allowed by the sidecar + includeIPRanges: "*" + excludeIPRanges: "" + includeOutboundPorts: "" + excludeOutboundPorts: "" + + # Log level for proxy, applies to gateways and sidecars. + # Expected values are: trace|debug|info|warning|error|critical|off + logLevel: warning + + #If set to true, istio-proxy container will have privileged securityContext + privileged: false + + # The number of successive failed probes before indicating readiness failure. + readinessFailureThreshold: 30 + + # The initial delay for readiness probes in seconds. + readinessInitialDelaySeconds: 1 + + # The period between readiness probes. + readinessPeriodSeconds: 2 + + # Resources for the sidecar. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + # Default port for Pilot agent health checks. A value of 0 will disable health checking. + statusPort: 15020 + + # Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver. + # If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file. + tracer: "zipkin" + + # Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready + holdApplicationUntilProxyStarts: false + + proxy_init: + # Base name for the proxy_init container, used to configure iptables. + image: proxyv2 + + # configure remote pilot and istiod service and endpoint + remotePilotAddress: "" + + ############################################################################################## + # The following values are found in other charts. To effectively modify these values, make # + # make sure they are consistent across your Istio helm charts # + ############################################################################################## + + # The customized CA address to retrieve certificates for the pods in the cluster. + # CSR clients such as the Istio Agent and ingress gateways can use this to specify the CA endpoint. + # If not set explicitly, default to the Istio discovery address. + caAddress: "" + + # Configure a remote cluster data plane controlled by an external istiod. + # When set to true, istiod is not deployed locally and only a subset of the other + # discovery charts are enabled. + externalIstiod: false + + # Configure a remote cluster as the config cluster for an external istiod. + configCluster: false + + # Configure the policy for validating JWT. + # Currently, two options are supported: "third-party-jwt" and "first-party-jwt". + jwtPolicy: "third-party-jwt" + + # Mesh ID means Mesh Identifier. It should be unique within the scope where + # meshes will interact with each other, but it is not required to be + # globally/universally unique. For example, if any of the following are true, + # then two meshes must have different Mesh IDs: + # - Meshes will have their telemetry aggregated in one place + # - Meshes will be federated together + # - Policy will be written referencing one mesh from the other + # + # If an administrator expects that any of these conditions may become true in + # the future, they should ensure their meshes have different Mesh IDs + # assigned. + # + # Within a multicluster mesh, each cluster must be (manually or auto) + # configured to have the same Mesh ID value. If an existing cluster 'joins' a + # multicluster mesh, it will need to be migrated to the new mesh ID. Details + # of migration TBD, and it may be a disruptive operation to change the Mesh + # ID post-install. + # + # If the mesh admin does not specify a value, Istio will use the value of the + # mesh's Trust Domain. The best practice is to select a proper Trust Domain + # value. + meshID: "" + + # Configure the mesh networks to be used by the Split Horizon EDS. + # + # The following example defines two networks with different endpoints association methods. + # For `network1` all endpoints that their IP belongs to the provided CIDR range will be + # mapped to network1. The gateway for this network example is specified by its public IP + # address and port. + # The second network, `network2`, in this example is defined differently with all endpoints + # retrieved through the specified Multi-Cluster registry being mapped to network2. The + # gateway is also defined differently with the name of the gateway service on the remote + # cluster. The public IP for the gateway will be determined from that remote service (only + # LoadBalancer gateway service type is currently supported, for a NodePort type gateway service, + # it still need to be configured manually). + # + # meshNetworks: + # network1: + # endpoints: + # - fromCidr: "192.168.0.1/24" + # gateways: + # - address: 1.1.1.1 + # port: 80 + # network2: + # endpoints: + # - fromRegistry: reg1 + # gateways: + # - registryServiceName: istio-ingressgateway.istio-system.svc.cluster.local + # port: 443 + # + meshNetworks: {} + + # Use the user-specified, secret volume mounted key and certs for Pilot and workloads. + mountMtlsCerts: false + + multiCluster: + # Set to true to connect two kubernetes clusters via their respective + # ingressgateway services when pods in each cluster cannot directly + # talk to one another. All clusters should be using Istio mTLS and must + # have a shared root CA for this model to work. + enabled: false + # Should be set to the name of the cluster this installation will run in. This is required for sidecar injection + # to properly label proxies + clusterName: "" + + # Network defines the network this cluster belong to. This name + # corresponds to the networks in the map of mesh networks. + network: "" + + # Configure the certificate provider for control plane communication. + # Currently, two providers are supported: "kubernetes" and "istiod". + # As some platforms may not have kubernetes signing APIs, + # Istiod is the default + pilotCertProvider: istiod + + sds: + # The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3. + # When a CSR is sent from Istio Agent to the CA (e.g. Istiod), this aud is to make sure the + # JWT is intended for the CA. + token: + aud: istio-ca + + sts: + # The service port used by Security Token Service (STS) server to handle token exchange requests. + # Setting this port to a non-zero value enables STS server. + servicePort: 0 + + # Configuration for each of the supported tracers + tracer: + # Configuration for envoy to send trace data to LightStep. + # Disabled by default. + # address: the : of the satellite pool + # accessToken: required for sending data to the pool + # + datadog: + # Host:Port for submitting traces to the Datadog agent. + address: "$(HOST_IP):8126" + lightstep: + address: "" # example: lightstep-satellite:443 + accessToken: "" # example: abcdefg1234567 + stackdriver: + # enables trace output to stdout. + debug: false + # The global default max number of message events per span. + maxNumberOfMessageEvents: 200 + # The global default max number of annotation events per span. + maxNumberOfAnnotations: 200 + # The global default max number of attributes per span. + maxNumberOfAttributes: 200 + zipkin: + # Host:Port for reporting trace data in zipkin format. If not specified, will default to + # zipkin service (port 9411) in the same namespace as the other istio components. + address: "" + + # Use the Mesh Control Protocol (MCP) for configuring Istiod. Requires an MCP source. + useMCP: false + + # The name of the CA for workload certificates. + # For example, when caName=GkeWorkloadCertificate, GKE workload certificates + # will be used as the certificates for workloads. + # The default value is "" and when caName="", the CA will be configured by other + # mechanisms (e.g., environmental variable CA_PROVIDER). + caName: "" + + # whether to use autoscaling/v2 template for HPA settings + # for internal usage only, not to be configured by users. + autoscalingv2API: true + + base: + # For istioctl usage to disable istio config crds in base + enableIstioConfigCRDs: true + + # If enabled, gateway-api types will be validated using the standard upstream validation logic. + # This is an alternative to deploying the standalone validation server the project provides. + # This is disabled by default, as the cluster may already have a validation server; while technically + # it works to have multiple redundant validations, this adds complexity and operational risks. + # Users should consider enabling this if they want full gateway-api validation but don't have other validation servers. + validateGateway: false \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/istio/lets-wildcard-cert.yaml.tpl b/terraform/foundation-install/generate-files/templates/istio/lets-wildcard-cert.yaml.tpl new file mode 100644 index 000000000..329d561f6 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/istio/lets-wildcard-cert.yaml.tpl @@ -0,0 +1,16 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: wildcard-cert-internal + namespace: default + annotations: + argocd.argoproj.io/sync-wave: "${wildcard_certificate_wave}" +spec: + secretName: ${default_ssl_certificate} + issuerRef: + name: letsencrypt + kind: ClusterIssuer + commonName: ${public_subdomain} + dnsNames: + - ${public_subdomain} + - "*.${public_subdomain}" \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/keycloak/app/keycloak-app.yaml.tpl b/terraform/foundation-install/generate-files/templates/keycloak/app/keycloak-app.yaml.tpl new file mode 100644 index 000000000..67ec60e30 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/keycloak/app/keycloak-app.yaml.tpl @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-8" + name: keycloak-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: apps/keycloak + repoURL: "${gitlab_project_url}" + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: ${keycloak_namespace} + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/keycloak/custom-resources/keycloak-cr.yaml.tpl b/terraform/foundation-install/generate-files/templates/keycloak/custom-resources/keycloak-cr.yaml.tpl new file mode 100644 index 000000000..73ecd076d --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/keycloak/custom-resources/keycloak-cr.yaml.tpl @@ -0,0 +1,19 @@ +apiVersion: k8s.keycloak.org/v2alpha1 +kind: Keycloak +metadata: + name: example-kc +spec: + instances: 1 + db: + vendor: mysql + host: postgres-db + usernameSecret: + name: keycloak-db-secret + key: username + passwordSecret: + name: keycloak-db-secret + key: password + http: + tlsSecret: example-tls-secret + hostname: + hostname: test.keycloak.org \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloakrealmimports.k8s.keycloak.org-v1.yaml b/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloakrealmimports.k8s.keycloak.org-v1.yaml new file mode 100644 index 000000000..3a8582be5 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloakrealmimports.k8s.keycloak.org-v1.yaml @@ -0,0 +1,2248 @@ +# Generated by Fabric8 CRDGenerator, manual edits might get overwritten! +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: keycloakrealmimports.k8s.keycloak.org +spec: + group: k8s.keycloak.org + names: + kind: KeycloakRealmImport + plural: keycloakrealmimports + singular: keycloakrealmimport + scope: Namespaced + versions: + - name: v2alpha1 + schema: + openAPIV3Schema: + properties: + spec: + properties: + keycloakCRName: + description: "The name of the Keycloak CR to reference, in the same\ + \ namespace." + type: string + realm: + description: The RealmRepresentation to import into Keycloak. + properties: + webAuthnPolicyAvoidSameAuthenticatorRegister: + type: boolean + federatedUsers: + items: + properties: + id: + type: string + clientConsents: + items: + properties: + grantedClientScopes: + items: + type: string + type: array + grantedRealmRoles: + items: + type: string + type: array + lastUpdatedDate: + type: integer + createdDate: + type: integer + clientId: + type: string + type: object + type: array + clientRoles: + additionalProperties: + items: + type: string + type: array + type: object + requiredActions: + items: + type: string + type: array + enabled: + type: boolean + realmRoles: + items: + type: string + type: array + createdTimestamp: + type: integer + emailVerified: + type: boolean + disableableCredentialTypes: + items: + type: string + type: array + socialLinks: + items: + properties: + socialUserId: + type: string + socialProvider: + type: string + socialUsername: + type: string + type: object + type: array + username: + type: string + federationLink: + type: string + access: + additionalProperties: + type: boolean + type: object + totp: + type: boolean + serviceAccountClientId: + type: string + attributes: + additionalProperties: + items: + type: string + type: array + type: object + federatedIdentities: + items: + properties: + userId: + type: string + identityProvider: + type: string + userName: + type: string + type: object + type: array + firstName: + type: string + self: + type: string + notBefore: + type: integer + groups: + items: + type: string + type: array + credentials: + items: + properties: + id: + type: string + period: + type: integer + counter: + type: integer + value: + type: string + hashIterations: + type: integer + algorithm: + type: string + hashedSaltedValue: + type: string + type: + type: string + priority: + type: integer + device: + type: string + temporary: + type: boolean + userLabel: + type: string + createdDate: + type: integer + secretData: + type: string + config: + additionalProperties: + items: + type: string + type: array + type: object + credentialData: + type: string + salt: + type: string + digits: + type: integer + type: object + type: array + applicationRoles: + additionalProperties: + items: + type: string + type: array + type: object + lastName: + type: string + email: + type: string + origin: + type: string + type: object + type: array + adminEventsEnabled: + type: boolean + registrationEmailAsUsername: + type: boolean + keycloakVersion: + type: string + oauth2DeviceCodeLifespan: + type: integer + sslRequired: + type: string + realm: + type: string + defaultGroups: + items: + type: string + type: array + enabled: + type: boolean + webAuthnPolicySignatureAlgorithms: + items: + type: string + type: array + ssoSessionMaxLifespanRememberMe: + type: integer + webAuthnPolicyRpId: + type: string + webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister: + type: boolean + users: + items: + properties: + id: + type: string + clientConsents: + items: + properties: + grantedClientScopes: + items: + type: string + type: array + grantedRealmRoles: + items: + type: string + type: array + lastUpdatedDate: + type: integer + createdDate: + type: integer + clientId: + type: string + type: object + type: array + clientRoles: + additionalProperties: + items: + type: string + type: array + type: object + requiredActions: + items: + type: string + type: array + enabled: + type: boolean + realmRoles: + items: + type: string + type: array + createdTimestamp: + type: integer + emailVerified: + type: boolean + disableableCredentialTypes: + items: + type: string + type: array + socialLinks: + items: + properties: + socialUserId: + type: string + socialProvider: + type: string + socialUsername: + type: string + type: object + type: array + username: + type: string + federationLink: + type: string + access: + additionalProperties: + type: boolean + type: object + totp: + type: boolean + serviceAccountClientId: + type: string + attributes: + additionalProperties: + items: + type: string + type: array + type: object + federatedIdentities: + items: + properties: + userId: + type: string + identityProvider: + type: string + userName: + type: string + type: object + type: array + firstName: + type: string + self: + type: string + notBefore: + type: integer + groups: + items: + type: string + type: array + credentials: + items: + properties: + id: + type: string + period: + type: integer + counter: + type: integer + value: + type: string + hashIterations: + type: integer + algorithm: + type: string + hashedSaltedValue: + type: string + type: + type: string + priority: + type: integer + device: + type: string + temporary: + type: boolean + userLabel: + type: string + createdDate: + type: integer + secretData: + type: string + config: + additionalProperties: + items: + type: string + type: array + type: object + credentialData: + type: string + salt: + type: string + digits: + type: integer + type: object + type: array + applicationRoles: + additionalProperties: + items: + type: string + type: array + type: object + lastName: + type: string + email: + type: string + origin: + type: string + type: object + type: array + clientTemplates: + items: + properties: + protocol: + type: string + id: + type: string + fullScopeAllowed: + type: boolean + frontchannelLogout: + type: boolean + serviceAccountsEnabled: + type: boolean + standardFlowEnabled: + type: boolean + description: + type: string + publicClient: + type: boolean + consentRequired: + type: boolean + bearerOnly: + type: boolean + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + name: + type: string + directAccessGrantsEnabled: + type: boolean + implicitFlowEnabled: + type: boolean + attributes: + additionalProperties: + type: string + type: object + type: object + type: array + webAuthnPolicyPasswordlessUserVerificationRequirement: + type: string + registrationFlow: + type: string + publicKey: + type: string + webAuthnPolicyPasswordlessCreateTimeout: + type: integer + authenticationFlows: + items: + properties: + id: + type: string + providerId: + type: string + authenticationExecutions: + items: + properties: + userSetupAllowed: + type: boolean + flowAlias: + type: string + autheticatorFlow: + type: boolean + authenticatorConfig: + type: string + authenticator: + type: string + priority: + type: integer + requirement: + type: string + authenticatorFlow: + type: boolean + type: object + type: array + topLevel: + type: boolean + alias: + type: string + builtIn: + type: boolean + description: + type: string + type: object + type: array + applicationScopeMappings: + additionalProperties: + items: + properties: + clientTemplate: + type: string + self: + type: string + clientScope: + type: string + client: + type: string + roles: + items: + type: string + type: array + type: object + type: array + type: object + offlineSessionMaxLifespan: + type: integer + codeSecret: + type: string + offlineSessionIdleTimeout: + type: integer + quickLoginCheckMilliSeconds: + type: integer + privateKey: + type: string + webAuthnPolicyRpEntityName: + type: string + emailTheme: + type: string + accessCodeLifespanLogin: + type: integer + passwordPolicy: + type: string + ssoSessionIdleTimeoutRememberMe: + type: integer + resetPasswordAllowed: + type: boolean + failureFactor: + type: integer + otpPolicyAlgorithm: + type: string + requiredActions: + items: + properties: + providerId: + type: string + alias: + type: string + defaultAction: + type: boolean + priority: + type: integer + name: + type: string + enabled: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + actionTokenGeneratedByUserLifespan: + type: integer + clientAuthenticationFlow: + type: string + webAuthnPolicyAuthenticatorAttachment: + type: string + actionTokenGeneratedByAdminLifespan: + type: integer + id: + type: string + clientPolicies: + type: object + x-kubernetes-preserve-unknown-fields: true + webAuthnPolicyUserVerificationRequirement: + type: string + loginTheme: + type: string + requiredCredentials: + items: + type: string + type: array + webAuthnPolicyPasswordlessAttestationConveyancePreference: + type: string + directGrantFlow: + type: string + identityProviderMappers: + items: + properties: + id: + type: string + name: + type: string + identityProviderMapper: + type: string + identityProviderAlias: + type: string + config: + additionalProperties: + type: string + type: object + type: object + type: array + dockerAuthenticationFlow: + type: string + browserFlow: + type: string + bruteForceProtected: + type: boolean + displayNameHtml: + type: string + ssoSessionIdleTimeout: + type: integer + browserSecurityHeaders: + additionalProperties: + type: string + type: object + eventsListeners: + items: + type: string + type: array + accessTokenLifespan: + type: integer + applications: + items: + properties: + name: + type: string + claims: + properties: + picture: + type: boolean + gender: + type: boolean + phone: + type: boolean + website: + type: boolean + email: + type: boolean + profile: + type: boolean + address: + type: boolean + name: + type: boolean + username: + type: boolean + locale: + type: boolean + type: object + id: + type: string + frontchannelLogout: + type: boolean + useTemplateConfig: + type: boolean + registrationAccessToken: + type: string + baseUrl: + type: string + serviceAccountsEnabled: + type: boolean + registeredNodes: + additionalProperties: + type: integer + type: object + useTemplateMappers: + type: boolean + description: + type: string + publicClient: + type: boolean + useTemplateScope: + type: boolean + authorizationSettings: + properties: + id: + type: string + resources: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + name: + type: string + policyEnforcementMode: + enum: + - stableIndex + - PERMISSIVE + - ENFORCING + - DISABLED + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + policies: + items: + properties: + config: + additionalProperties: + type: string + type: object + id: + type: string + owner: + type: string + resources: + items: + type: string + type: array + policies: + items: + type: string + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + logic: + enum: + - stableIndex + - POSITIVE + - NEGATIVE + type: string + resourcesData: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + name: + type: string + type: + type: string + scopesData: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + description: + type: string + scopes: + items: + type: string + type: array + type: object + type: array + clientId: + type: string + allowRemoteResourceManagement: + type: boolean + type: object + clientId: + type: string + enabled: + type: boolean + clientAuthenticatorType: + type: string + surrogateAuthRequired: + type: boolean + webOrigins: + items: + type: string + type: array + authorizationServicesEnabled: + type: boolean + secret: + type: string + protocol: + type: string + fullScopeAllowed: + type: boolean + nodeReRegistrationTimeout: + type: integer + clientTemplate: + type: string + access: + additionalProperties: + type: boolean + type: object + alwaysDisplayInConsole: + type: boolean + rootUrl: + type: string + oauth2DeviceAuthorizationGrantEnabled: + type: boolean + standardFlowEnabled: + type: boolean + optionalClientScopes: + items: + type: string + type: array + consentRequired: + type: boolean + authenticationFlowBindingOverrides: + additionalProperties: + type: string + type: object + bearerOnly: + type: boolean + defaultClientScopes: + items: + type: string + type: array + adminUrl: + type: string + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + notBefore: + type: integer + directGrantsOnly: + type: boolean + defaultRoles: + items: + type: string + type: array + directAccessGrantsEnabled: + type: boolean + implicitFlowEnabled: + type: boolean + origin: + type: string + attributes: + additionalProperties: + type: string + type: object + redirectUris: + items: + type: string + type: array + type: object + type: array + otpPolicyCodeReusable: + type: boolean + clientProfiles: + type: object + x-kubernetes-preserve-unknown-fields: true + userFederationMappers: + items: + properties: + id: + type: string + federationProviderDisplayName: + type: string + federationMapperType: + type: string + name: + type: string + config: + additionalProperties: + type: string + type: object + type: object + type: array + enabledEventTypes: + items: + type: string + type: array + otpPolicyLookAheadWindow: + type: integer + displayName: + type: string + eventsEnabled: + type: boolean + clientSessionMaxLifespan: + type: integer + roles: + properties: + application: + additionalProperties: + items: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + clientRole: + type: boolean + name: + type: string + description: + type: string + scopeParamRequired: + type: boolean + composites: + properties: + realm: + items: + type: string + type: array + application: + additionalProperties: + items: + type: string + type: array + type: object + client: + additionalProperties: + items: + type: string + type: array + type: object + type: object + containerId: + type: string + composite: + type: boolean + type: object + type: array + type: object + client: + additionalProperties: + items: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + clientRole: + type: boolean + name: + type: string + description: + type: string + scopeParamRequired: + type: boolean + composites: + properties: + realm: + items: + type: string + type: array + application: + additionalProperties: + items: + type: string + type: array + type: object + client: + additionalProperties: + items: + type: string + type: array + type: object + type: object + containerId: + type: string + composite: + type: boolean + type: object + type: array + type: object + realm: + items: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + clientRole: + type: boolean + name: + type: string + description: + type: string + scopeParamRequired: + type: boolean + composites: + properties: + realm: + items: + type: string + type: array + application: + additionalProperties: + items: + type: string + type: array + type: object + client: + additionalProperties: + items: + type: string + type: array + type: object + type: object + containerId: + type: string + composite: + type: boolean + type: object + type: array + type: object + groups: + items: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + access: + additionalProperties: + type: boolean + type: object + realmRoles: + items: + type: string + type: array + path: + type: string + clientRoles: + additionalProperties: + items: + type: string + type: array + type: object + name: + type: string + subGroups: + items: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + access: + additionalProperties: + type: boolean + type: object + realmRoles: + items: + type: string + type: array + path: + type: string + clientRoles: + additionalProperties: + items: + type: string + type: array + type: object + name: + type: string + type: object + type: array + type: object + type: array + webAuthnPolicyCreateTimeout: + type: integer + webAuthnPolicyAttestationConveyancePreference: + type: string + clientOfflineSessionIdleTimeout: + type: integer + notBefore: + type: integer + webAuthnPolicyPasswordlessRpEntityName: + type: string + verifyEmail: + type: boolean + clientScopeMappings: + additionalProperties: + items: + properties: + clientTemplate: + type: string + self: + type: string + clientScope: + type: string + client: + type: string + roles: + items: + type: string + type: array + type: object + type: array + type: object + identityProviders: + items: + properties: + storeToken: + type: boolean + trustEmail: + type: boolean + updateProfileFirstLoginMode: + type: string + authenticateByDefault: + type: boolean + displayName: + type: string + providerId: + type: string + linkOnly: + type: boolean + postBrokerLoginFlowAlias: + type: string + alias: + type: string + enabled: + type: boolean + firstBrokerLoginFlowAlias: + type: string + internalId: + type: string + addReadTokenRoleOnCreate: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + resetCredentialsFlow: + type: string + duplicateEmailsAllowed: + type: boolean + maxDeltaTimeSeconds: + type: integer + offlineSessionMaxLifespanEnabled: + type: boolean + realmCacheEnabled: + type: boolean + attributes: + additionalProperties: + type: string + type: object + adminTheme: + type: string + loginWithEmailAllowed: + type: boolean + otpSupportedApplications: + items: + type: string + type: array + clientOfflineSessionMaxLifespan: + type: integer + userFederationProviders: + items: + properties: + id: + type: string + providerName: + type: string + displayName: + type: string + priority: + type: integer + fullSyncPeriod: + type: integer + lastSync: + type: integer + changedSyncPeriod: + type: integer + config: + additionalProperties: + type: string + type: object + type: object + type: array + internationalizationEnabled: + type: boolean + permanentLockout: + type: boolean + userManagedAccessAllowed: + type: boolean + smtpServer: + additionalProperties: + type: string + type: object + otpPolicyDigits: + type: integer + webAuthnPolicyPasswordlessSignatureAlgorithms: + items: + type: string + type: array + socialProviders: + additionalProperties: + type: string + type: object + otpPolicyInitialCounter: + type: integer + defaultSignatureAlgorithm: + type: string + refreshTokenMaxReuse: + type: integer + revokeRefreshToken: + type: boolean + accountTheme: + type: string + webAuthnPolicyPasswordlessAcceptableAaguids: + items: + type: string + type: array + webAuthnPolicyPasswordlessAuthenticatorAttachment: + type: string + supportedLocales: + items: + type: string + type: array + defaultDefaultClientScopes: + items: + type: string + type: array + authenticatorConfig: + items: + properties: + id: + type: string + alias: + type: string + config: + additionalProperties: + type: string + type: object + type: object + type: array + webAuthnPolicyPasswordlessRpId: + type: string + scopeMappings: + items: + properties: + clientTemplate: + type: string + self: + type: string + clientScope: + type: string + client: + type: string + roles: + items: + type: string + type: array + type: object + type: array + clientScopes: + items: + properties: + protocol: + type: string + id: + type: string + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + name: + type: string + description: + type: string + attributes: + additionalProperties: + type: string + type: object + type: object + type: array + oauth2DevicePollingInterval: + type: integer + eventsExpiration: + type: integer + certificate: + type: string + defaultRole: + properties: + attributes: + additionalProperties: + items: + type: string + type: array + type: object + id: + type: string + clientRole: + type: boolean + name: + type: string + description: + type: string + scopeParamRequired: + type: boolean + composites: + properties: + realm: + items: + type: string + type: array + application: + additionalProperties: + items: + type: string + type: array + type: object + client: + additionalProperties: + items: + type: string + type: array + type: object + type: object + containerId: + type: string + composite: + type: boolean + type: object + defaultOptionalClientScopes: + items: + type: string + type: array + editUsernameAllowed: + type: boolean + defaultLocale: + type: string + webAuthnPolicyRequireResidentKey: + type: string + oauthClients: + items: + properties: + name: + type: string + claims: + properties: + picture: + type: boolean + gender: + type: boolean + phone: + type: boolean + website: + type: boolean + email: + type: boolean + profile: + type: boolean + address: + type: boolean + name: + type: boolean + username: + type: boolean + locale: + type: boolean + type: object + id: + type: string + frontchannelLogout: + type: boolean + useTemplateConfig: + type: boolean + registrationAccessToken: + type: string + baseUrl: + type: string + serviceAccountsEnabled: + type: boolean + registeredNodes: + additionalProperties: + type: integer + type: object + useTemplateMappers: + type: boolean + description: + type: string + publicClient: + type: boolean + useTemplateScope: + type: boolean + authorizationSettings: + properties: + id: + type: string + resources: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + name: + type: string + policyEnforcementMode: + enum: + - stableIndex + - PERMISSIVE + - ENFORCING + - DISABLED + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + policies: + items: + properties: + config: + additionalProperties: + type: string + type: object + id: + type: string + owner: + type: string + resources: + items: + type: string + type: array + policies: + items: + type: string + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + logic: + enum: + - stableIndex + - POSITIVE + - NEGATIVE + type: string + resourcesData: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + name: + type: string + type: + type: string + scopesData: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + description: + type: string + scopes: + items: + type: string + type: array + type: object + type: array + clientId: + type: string + allowRemoteResourceManagement: + type: boolean + type: object + clientId: + type: string + enabled: + type: boolean + clientAuthenticatorType: + type: string + surrogateAuthRequired: + type: boolean + webOrigins: + items: + type: string + type: array + authorizationServicesEnabled: + type: boolean + secret: + type: string + protocol: + type: string + fullScopeAllowed: + type: boolean + nodeReRegistrationTimeout: + type: integer + clientTemplate: + type: string + access: + additionalProperties: + type: boolean + type: object + alwaysDisplayInConsole: + type: boolean + rootUrl: + type: string + oauth2DeviceAuthorizationGrantEnabled: + type: boolean + standardFlowEnabled: + type: boolean + optionalClientScopes: + items: + type: string + type: array + consentRequired: + type: boolean + authenticationFlowBindingOverrides: + additionalProperties: + type: string + type: object + bearerOnly: + type: boolean + defaultClientScopes: + items: + type: string + type: array + adminUrl: + type: string + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + notBefore: + type: integer + directGrantsOnly: + type: boolean + defaultRoles: + items: + type: string + type: array + directAccessGrantsEnabled: + type: boolean + implicitFlowEnabled: + type: boolean + origin: + type: string + attributes: + additionalProperties: + type: string + type: object + redirectUris: + items: + type: string + type: array + type: object + type: array + adminEventsDetailsEnabled: + type: boolean + ssoSessionMaxLifespan: + type: integer + accessCodeLifespanUserAction: + type: integer + registrationAllowed: + type: boolean + social: + type: boolean + accessTokenLifespanForImplicitFlow: + type: integer + rememberMe: + type: boolean + maxFailureWaitSeconds: + type: integer + defaultRoles: + items: + type: string + type: array + otpPolicyType: + type: string + otpPolicyPeriod: + type: integer + accessCodeLifespan: + type: integer + minimumQuickLoginWaitSeconds: + type: integer + webAuthnPolicyAcceptableAaguids: + items: + type: string + type: array + updateProfileOnInitialSocialLogin: + type: boolean + clientSessionIdleTimeout: + type: integer + webAuthnPolicyPasswordlessRequireResidentKey: + type: string + waitIncrementSeconds: + type: integer + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + clients: + items: + properties: + id: + type: string + frontchannelLogout: + type: boolean + useTemplateConfig: + type: boolean + registrationAccessToken: + type: string + baseUrl: + type: string + serviceAccountsEnabled: + type: boolean + registeredNodes: + additionalProperties: + type: integer + type: object + useTemplateMappers: + type: boolean + description: + type: string + publicClient: + type: boolean + useTemplateScope: + type: boolean + authorizationSettings: + properties: + id: + type: string + resources: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + name: + type: string + policyEnforcementMode: + enum: + - stableIndex + - PERMISSIVE + - ENFORCING + - DISABLED + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + policies: + items: + properties: + config: + additionalProperties: + type: string + type: object + id: + type: string + owner: + type: string + resources: + items: + type: string + type: array + policies: + items: + type: string + type: array + decisionStrategy: + enum: + - AFFIRMATIVE + - stableIndex + - CONSENSUS + - UNANIMOUS + type: string + logic: + enum: + - stableIndex + - POSITIVE + - NEGATIVE + type: string + resourcesData: + items: + properties: + _id: + type: string + uris: + items: + type: string + type: array + attributes: + additionalProperties: + items: + type: string + type: array + type: object + displayName: + type: string + scopes: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + owner: + properties: + id: + type: string + name: + type: string + type: object + name: + type: string + type: + type: string + icon_uri: + type: string + ownerManagedAccess: + type: boolean + type: object + type: array + name: + type: string + type: + type: string + scopesData: + items: + properties: + id: + type: string + displayName: + type: string + name: + type: string + iconUri: + type: string + type: object + type: array + description: + type: string + scopes: + items: + type: string + type: array + type: object + type: array + clientId: + type: string + allowRemoteResourceManagement: + type: boolean + type: object + clientId: + type: string + enabled: + type: boolean + clientAuthenticatorType: + type: string + name: + type: string + surrogateAuthRequired: + type: boolean + webOrigins: + items: + type: string + type: array + authorizationServicesEnabled: + type: boolean + secret: + type: string + protocol: + type: string + fullScopeAllowed: + type: boolean + nodeReRegistrationTimeout: + type: integer + clientTemplate: + type: string + access: + additionalProperties: + type: boolean + type: object + alwaysDisplayInConsole: + type: boolean + rootUrl: + type: string + oauth2DeviceAuthorizationGrantEnabled: + type: boolean + standardFlowEnabled: + type: boolean + optionalClientScopes: + items: + type: string + type: array + consentRequired: + type: boolean + authenticationFlowBindingOverrides: + additionalProperties: + type: string + type: object + bearerOnly: + type: boolean + defaultClientScopes: + items: + type: string + type: array + adminUrl: + type: string + protocolMappers: + items: + properties: + protocol: + type: string + id: + type: string + name: + type: string + protocolMapper: + type: string + consentText: + type: string + consentRequired: + type: boolean + config: + additionalProperties: + type: string + type: object + type: object + type: array + notBefore: + type: integer + directGrantsOnly: + type: boolean + defaultRoles: + items: + type: string + type: array + directAccessGrantsEnabled: + type: boolean + implicitFlowEnabled: + type: boolean + origin: + type: string + attributes: + additionalProperties: + type: string + type: object + redirectUris: + items: + type: string + type: array + type: object + type: array + components: + additionalProperties: + items: + properties: + id: + type: string + providerId: + type: string + subType: + type: string + subComponents: + additionalProperties: + items: + properties: + id: + type: string + providerId: + type: string + subType: + type: string + name: + type: string + config: + additionalProperties: + items: + type: string + type: array + type: object + type: object + type: array + type: object + name: + type: string + config: + additionalProperties: + items: + type: string + type: array + type: object + type: object + type: array + type: object + passwordCredentialGrantAllowed: + type: boolean + userCacheEnabled: + type: boolean + type: object + required: + - keycloakCRName + - realm + type: object + status: + properties: + conditions: + items: + properties: + status: + type: boolean + type: + type: string + message: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloaks.k8s.keycloak.org-v1.yaml b/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloaks.k8s.keycloak.org-v1.yaml new file mode 100644 index 000000000..dec6d975b --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/keycloak/operator/keycloaks.k8s.keycloak.org-v1.yaml @@ -0,0 +1,2917 @@ +# Generated by Fabric8 CRDGenerator, manual edits might get overwritten! +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: keycloaks.k8s.keycloak.org +spec: + group: k8s.keycloak.org + names: + kind: Keycloak + plural: keycloaks + shortNames: + - kc + singular: keycloak + scope: Namespaced + versions: + - name: v2alpha1 + schema: + openAPIV3Schema: + properties: + spec: + properties: + instances: + description: Number of Keycloak instances in HA mode. Default is 1. + type: integer + transaction: + description: In this section you can find all properties related to + the settings of transaction behavior. + properties: + xaEnabled: + description: Determine whether Keycloak should use a non-XA datasource + in case the database does not support XA transactions. + type: boolean + type: object + http: + description: In this section you can configure Keycloak features related + to HTTP and HTTPS + properties: + httpPort: + description: The used HTTP port. + type: integer + tlsSecret: + description: "A secret containing the TLS configuration for HTTPS.\ + \ Reference: https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets." + type: string + httpsPort: + description: The used HTTPS port. + type: integer + httpEnabled: + description: Enables the HTTP listener. + type: boolean + type: object + hostname: + description: In this section you can configure Keycloak hostname and + related properties. + properties: + hostname: + description: Hostname for the Keycloak server. + type: string + strict: + description: Disables dynamically resolving the hostname from + request headers. + type: boolean + strictBackchannel: + description: By default backchannel URLs are dynamically resolved + from request headers to allow internal and external applications. + type: boolean + admin: + description: The hostname for accessing the administration console. + type: string + adminUrl: + description: "Set the base URL for accessing the administration\ + \ console, including scheme, host, port and path" + type: string + type: object + unsupported: + description: |- + In this section you can configure podTemplate advanced features, not production-ready, and not supported settings. + Use at your own risk and open an issue with your use-case if you don't find an alternative way. + properties: + podTemplate: + description: |- + You can configure that will be merged with the one configured by default by the operator. + Use at your own risk, we reserve the possibility to remove/change the way any field gets merged in future releases without notice. + Reference: https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + properties: + metadata: + properties: + generateName: + type: string + deletionGracePeriodSeconds: + type: integer + deletionTimestamp: + type: string + clusterName: + type: string + resourceVersion: + type: string + annotations: + additionalProperties: + type: string + type: object + selfLink: + type: string + creationTimestamp: + type: string + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + ownerReferences: + items: + properties: + blockOwnerDeletion: + type: boolean + uid: + type: string + apiVersion: + type: string + name: + type: string + kind: + type: string + controller: + type: boolean + type: object + type: array + uid: + type: string + generation: + type: integer + name: + type: string + managedFields: + items: + properties: + time: + type: string + apiVersion: + type: string + fieldsV1: + type: object + fieldsType: + type: string + manager: + type: string + operation: + type: string + subresource: + type: string + type: object + type: array + namespace: + type: string + type: object + spec: + properties: + volumes: + items: + properties: + hostPath: + properties: + path: + type: string + type: + type: string + type: object + flexVolume: + properties: + readOnly: + type: boolean + options: + additionalProperties: + type: string + type: object + secretRef: + properties: + name: + type: string + type: object + fsType: + type: string + driver: + type: string + type: object + gcePersistentDisk: + properties: + readOnly: + type: boolean + pdName: + type: string + partition: + type: integer + fsType: + type: string + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + generateName: + type: string + deletionGracePeriodSeconds: + type: integer + deletionTimestamp: + type: string + clusterName: + type: string + resourceVersion: + type: string + annotations: + additionalProperties: + type: string + type: object + selfLink: + type: string + creationTimestamp: + type: string + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + ownerReferences: + items: + properties: + blockOwnerDeletion: + type: boolean + uid: + type: string + apiVersion: + type: string + name: + type: string + kind: + type: string + controller: + type: boolean + type: object + type: array + uid: + type: string + generation: + type: integer + name: + type: string + managedFields: + items: + properties: + time: + type: string + apiVersion: + type: string + fieldsV1: + type: object + fieldsType: + type: string + manager: + type: string + operation: + type: string + subresource: + type: string + type: object + type: array + namespace: + type: string + type: object + spec: + properties: + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + dataSource: + properties: + name: + type: string + kind: + type: string + apiGroup: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + dataSourceRef: + properties: + name: + type: string + kind: + type: string + apiGroup: + type: string + type: object + accessModes: + items: + type: string + type: array + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + type: object + scaleIO: + properties: + readOnly: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + gateway: + type: string + secretRef: + properties: + name: + type: string + type: object + fsType: + type: string + sslEnabled: + type: boolean + volumeName: + type: string + protectionDomain: + type: string + type: object + csi: + properties: + nodePublishSecretRef: + properties: + name: + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + fsType: + type: string + driver: + type: string + type: object + secret: + properties: + optional: + type: boolean + secretName: + type: string + items: + items: + properties: + path: + type: string + key: + type: string + mode: + type: integer + type: object + type: array + defaultMode: + type: integer + type: object + name: + type: string + vsphereVolume: + properties: + storagePolicyName: + type: string + storagePolicyID: + type: string + volumePath: + type: string + fsType: + type: string + type: object + gitRepo: + properties: + revision: + type: string + repository: + type: string + directory: + type: string + type: object + glusterfs: + properties: + path: + type: string + readOnly: + type: boolean + endpoints: + type: string + type: object + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + type: object + cinder: + properties: + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + fsType: + type: string + volumeID: + type: string + type: object + flocker: + properties: + datasetUUID: + type: string + datasetName: + type: string + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + volume: + type: string + user: + type: string + registry: + type: string + tenant: + type: string + type: object + photonPersistentDisk: + properties: + pdID: + type: string + fsType: + type: string + type: object + persistentVolumeClaim: + properties: + readOnly: + type: boolean + claimName: + type: string + type: object + awsElasticBlockStore: + properties: + readOnly: + type: boolean + partition: + type: integer + fsType: + type: string + volumeID: + type: string + type: object + configMap: + properties: + optional: + type: boolean + items: + items: + properties: + path: + type: string + key: + type: string + mode: + type: integer + type: object + type: array + defaultMode: + type: integer + name: + type: string + type: object + storageos: + properties: + readOnly: + type: boolean + volumeNamespace: + type: string + secretRef: + properties: + name: + type: string + type: object + fsType: + type: string + volumeName: + type: string + type: object + portworxVolume: + properties: + readOnly: + type: boolean + fsType: + type: string + volumeID: + type: string + type: object + iscsi: + properties: + readOnly: + type: boolean + chapAuthSession: + type: boolean + lun: + type: integer + targetPortal: + type: string + iscsiInterface: + type: string + portals: + items: + type: string + type: array + initiatorName: + type: string + secretRef: + properties: + name: + type: string + type: object + fsType: + type: string + iqn: + type: string + chapAuthDiscovery: + type: boolean + type: object + rbd: + properties: + readOnly: + type: boolean + pool: + type: string + keyring: + type: string + image: + type: string + secretRef: + properties: + name: + type: string + type: object + monitors: + items: + type: string + type: array + fsType: + type: string + user: + type: string + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + path: + type: string + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + mode: + type: integer + type: object + type: array + defaultMode: + type: integer + type: object + projected: + properties: + defaultMode: + type: integer + sources: + items: + properties: + secret: + properties: + optional: + type: boolean + items: + items: + properties: + path: + type: string + key: + type: string + mode: + type: integer + type: object + type: array + name: + type: string + type: object + configMap: + properties: + optional: + type: boolean + items: + items: + properties: + path: + type: string + key: + type: string + mode: + type: integer + type: object + type: array + name: + type: string + type: object + serviceAccountToken: + properties: + path: + type: string + audience: + type: string + expirationSeconds: + type: integer + type: object + downwardAPI: + properties: + items: + items: + properties: + path: + type: string + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + mode: + type: integer + type: object + type: array + type: object + type: object + type: array + type: object + azureDisk: + properties: + readOnly: + type: boolean + diskName: + type: string + cachingMode: + type: string + fsType: + type: string + kind: + type: string + diskURI: + type: string + type: object + cephfs: + properties: + path: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + monitors: + items: + type: string + type: array + secretFile: + type: string + user: + type: string + type: object + emptyDir: + properties: + sizeLimit: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + medium: + type: string + type: object + fc: + properties: + readOnly: + type: boolean + lun: + type: integer + wwids: + items: + type: string + type: array + targetWWNs: + items: + type: string + type: array + fsType: + type: string + type: object + type: object + type: array + restartPolicy: + type: string + terminationGracePeriodSeconds: + type: integer + setHostnameAsFQDN: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + searches: + items: + type: string + type: array + options: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + type: object + securityContext: + properties: + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + windowsOptions: + properties: + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + gmsaCredentialSpec: + type: string + runAsUserName: + type: string + type: object + sysctls: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + fsGroupChangePolicy: + type: string + seLinuxOptions: + properties: + role: + type: string + type: + type: string + user: + type: string + level: + type: string + type: object + fsGroup: + type: integer + supplementalGroups: + items: + type: integer + type: array + runAsUser: + type: integer + seccompProfile: + properties: + type: + type: string + localhostProfile: + type: string + type: object + type: object + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + subdomain: + type: string + serviceAccount: + type: string + activeDeadlineSeconds: + type: integer + priority: + type: integer + ephemeralContainers: + items: + properties: + lifecycle: + properties: + postStart: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + preStop: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + type: object + command: + items: + type: string + type: array + livenessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdin: + type: boolean + image: + type: string + targetContainerName: + type: string + terminationMessagePolicy: + type: string + readinessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + terminationMessagePath: + type: string + env: + items: + properties: + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + secretKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + type: object + name: + type: string + type: object + type: array + tty: + type: boolean + args: + items: + type: string + type: array + startupProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdinOnce: + type: boolean + ports: + items: + properties: + containerPort: + type: integer + hostPort: + type: integer + name: + type: string + protocol: + type: string + hostIP: + type: string + type: object + type: array + workingDir: + type: string + envFrom: + items: + properties: + prefix: + type: string + configMapRef: + properties: + optional: + type: boolean + name: + type: string + type: object + secretRef: + properties: + optional: + type: boolean + name: + type: string + type: object + type: object + type: array + volumeMounts: + items: + properties: + readOnly: + type: boolean + subPathExpr: + type: string + mountPath: + type: string + mountPropagation: + type: string + subPath: + type: string + name: + type: string + type: object + type: array + securityContext: + properties: + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + windowsOptions: + properties: + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + gmsaCredentialSpec: + type: string + runAsUserName: + type: string + type: object + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + seLinuxOptions: + properties: + role: + type: string + type: + type: string + user: + type: string + level: + type: string + type: object + readOnlyRootFilesystem: + type: boolean + privileged: + type: boolean + runAsUser: + type: integer + procMount: + type: string + seccompProfile: + properties: + type: + type: string + localhostProfile: + type: string + type: object + type: object + name: + type: string + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + imagePullPolicy: + type: string + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + type: object + type: array + type: object + type: array + automountServiceAccountToken: + type: boolean + containers: + items: + properties: + lifecycle: + properties: + postStart: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + preStop: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + type: object + command: + items: + type: string + type: array + livenessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdin: + type: boolean + image: + type: string + terminationMessagePolicy: + type: string + readinessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + terminationMessagePath: + type: string + env: + items: + properties: + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + secretKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + type: object + name: + type: string + type: object + type: array + tty: + type: boolean + args: + items: + type: string + type: array + startupProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdinOnce: + type: boolean + ports: + items: + properties: + containerPort: + type: integer + hostPort: + type: integer + name: + type: string + protocol: + type: string + hostIP: + type: string + type: object + type: array + workingDir: + type: string + envFrom: + items: + properties: + prefix: + type: string + configMapRef: + properties: + optional: + type: boolean + name: + type: string + type: object + secretRef: + properties: + optional: + type: boolean + name: + type: string + type: object + type: object + type: array + volumeMounts: + items: + properties: + readOnly: + type: boolean + subPathExpr: + type: string + mountPath: + type: string + mountPropagation: + type: string + subPath: + type: string + name: + type: string + type: object + type: array + securityContext: + properties: + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + windowsOptions: + properties: + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + gmsaCredentialSpec: + type: string + runAsUserName: + type: string + type: object + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + seLinuxOptions: + properties: + role: + type: string + type: + type: string + user: + type: string + level: + type: string + type: object + readOnlyRootFilesystem: + type: boolean + privileged: + type: boolean + runAsUser: + type: integer + procMount: + type: string + seccompProfile: + properties: + type: + type: string + localhostProfile: + type: string + type: object + type: object + name: + type: string + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + imagePullPolicy: + type: string + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + type: object + type: array + type: object + type: array + initContainers: + items: + properties: + lifecycle: + properties: + postStart: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + preStop: + properties: + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + type: object + command: + items: + type: string + type: array + livenessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdin: + type: boolean + image: + type: string + terminationMessagePolicy: + type: string + readinessProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + terminationMessagePath: + type: string + env: + items: + properties: + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + secretKeyRef: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + type: object + name: + type: string + type: object + type: array + tty: + type: boolean + args: + items: + type: string + type: array + startupProbe: + properties: + periodSeconds: + type: integer + failureThreshold: + type: integer + initialDelaySeconds: + type: integer + grpc: + properties: + port: + type: integer + service: + type: string + type: object + successThreshold: + type: integer + terminationGracePeriodSeconds: + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + timeoutSeconds: + type: integer + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + path: + type: string + scheme: + type: string + host: + type: string + httpHeaders: + items: + properties: + value: + type: string + name: + type: string + type: object + type: array + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + stdinOnce: + type: boolean + ports: + items: + properties: + containerPort: + type: integer + hostPort: + type: integer + name: + type: string + protocol: + type: string + hostIP: + type: string + type: object + type: array + workingDir: + type: string + envFrom: + items: + properties: + prefix: + type: string + configMapRef: + properties: + optional: + type: boolean + name: + type: string + type: object + secretRef: + properties: + optional: + type: boolean + name: + type: string + type: object + type: object + type: array + volumeMounts: + items: + properties: + readOnly: + type: boolean + subPathExpr: + type: string + mountPath: + type: string + mountPropagation: + type: string + subPath: + type: string + name: + type: string + type: object + type: array + securityContext: + properties: + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + windowsOptions: + properties: + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + gmsaCredentialSpec: + type: string + runAsUserName: + type: string + type: object + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + seLinuxOptions: + properties: + role: + type: string + type: + type: string + user: + type: string + level: + type: string + type: object + readOnlyRootFilesystem: + type: boolean + privileged: + type: boolean + runAsUser: + type: integer + procMount: + type: string + seccompProfile: + properties: + type: + type: string + localhostProfile: + type: string + type: object + type: object + name: + type: string + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + type: object + imagePullPolicy: + type: string + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + type: object + type: array + type: object + type: array + priorityClassName: + type: string + tolerations: + items: + properties: + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + effect: + type: string + type: object + type: array + hostPID: + type: boolean + os: + properties: + name: + type: string + type: object + serviceAccountName: + type: string + shareProcessNamespace: + type: boolean + hostNetwork: + type: boolean + hostname: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + enableServiceLinks: + type: boolean + affinity: + properties: + podAntiAffinity: + properties: + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + namespaces: + items: + type: string + type: array + topologyKey: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + namespaces: + items: + type: string + type: array + topologyKey: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + weight: + type: integer + type: object + type: array + type: object + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + weight: + type: integer + preference: + properties: + matchFields: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + type: object + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchFields: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + type: object + type: array + type: object + type: object + podAffinity: + properties: + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + namespaces: + items: + type: string + type: array + topologyKey: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + namespaces: + items: + type: string + type: array + topologyKey: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + weight: + type: integer + type: object + type: array + type: object + type: object + readinessGates: + items: + properties: + conditionType: + type: string + type: object + type: array + dnsPolicy: + type: string + hostIPC: + type: boolean + topologySpreadConstraints: + items: + properties: + topologyKey: + type: string + maxSkew: + type: integer + whenUnsatisfiable: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + values: + items: + type: string + type: array + operator: + type: string + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + schedulerName: + type: string + nodeName: + type: string + preemptionPolicy: + type: string + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + ip: + type: string + type: object + type: array + runtimeClassName: + type: string + type: object + type: object + type: object + ingress: + description: |- + The deployment is, by default, exposed through a basic ingress. + You can change this behaviour by setting the enabled property to false. + properties: + enabled: + type: boolean + type: object + image: + description: Custom Keycloak image to be used. + type: string + imagePullSecrets: + description: Secret(s) that might be used when pulling an image from + a private container image registry or repository. + items: + properties: + name: + type: string + type: object + type: array + additionalOptions: + description: |- + Configuration of the Keycloak server. + expressed as a keys (reference: https://www.keycloak.org/server/all-config) and values that can be either direct values or references to secrets. + items: + properties: + secret: + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + value: + type: string + name: + type: string + type: object + type: array + db: + description: In this section you can find all properties related to + connect to a database. + properties: + passwordSecret: + description: The reference to a secret holding the password of + the database user. + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + usernameSecret: + description: The reference to a secret holding the username of + the database user. + properties: + optional: + type: boolean + key: + type: string + name: + type: string + type: object + port: + description: "Sets the port of the default JDBC URL of the chosen\ + \ vendor. If the `url` option is set, this option is ignored." + type: integer + schema: + description: The database schema to be used. + type: string + host: + description: "Sets the hostname of the default JDBC URL of the\ + \ chosen vendor. If the `url` option is set, this option is\ + \ ignored." + type: string + url: + description: "The full database JDBC URL. If not provided, a default\ + \ URL is set based on the selected database vendor. For instance,\ + \ if using 'postgres', the default JDBC URL would be 'jdbc:postgresql://localhost/keycloak'. " + type: string + poolInitialSize: + description: The initial size of the connection pool. + type: integer + poolMaxSize: + description: The maximum size of the connection pool. + type: integer + vendor: + description: The database vendor. + type: string + database: + description: "Sets the database name of the default JDBC URL of\ + \ the chosen vendor. If the `url` option is set, this option\ + \ is ignored." + type: string + poolMinSize: + description: The minimal size of the connection pool. + type: integer + type: object + features: + description: "In this section you can configure Keycloak features,\ + \ which should be enabled/disabled." + properties: + disabled: + description: Disabled Keycloak features + items: + type: string + type: array + enabled: + description: Enabled Keycloak features + items: + type: string + type: array + type: object + type: object + status: + properties: + conditions: + items: + properties: + status: + type: boolean + type: + type: string + message: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/keycloak/operator/kubernetes.yaml b/terraform/foundation-install/generate-files/templates/keycloak/operator/kubernetes.yaml new file mode 100644 index 000000000..5ffd97f5e --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/keycloak/operator/kubernetes.yaml @@ -0,0 +1,235 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + app.quarkus.io/build-timestamp: 2023-03-30 - 11:19:25 +0000 + labels: + app.kubernetes.io/version: 21.0.2 + app.kubernetes.io/name: keycloak-operator + name: keycloak-operator +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + app.quarkus.io/build-timestamp: 2023-03-30 - 11:19:25 +0000 + labels: + app.kubernetes.io/name: keycloak-operator + app.kubernetes.io/version: 21.0.2 + name: keycloak-operator +spec: + ports: + - name: http + port: 80 + targetPort: 8080 + selector: + app.kubernetes.io/name: keycloak-operator + app.kubernetes.io/version: 21.0.2 + type: ClusterIP +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: keycloak-operator-role +rules: + - apiGroups: + - apps + - extensions + resources: + - statefulsets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "" + resources: + - secrets + - services + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - batch + resources: + - jobs + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch + - create + - delete + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: keycloak-operator + name: keycloak-operator-role-binding +roleRef: + kind: Role + apiGroup: rbac.authorization.k8s.io + name: keycloak-operator-role +subjects: + - kind: ServiceAccount + name: keycloak-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: keycloak-operator-view +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: view +subjects: + - kind: ServiceAccount + name: keycloak-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: keycloakcontroller-role-binding +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: keycloakcontroller-cluster-role +subjects: + - kind: ServiceAccount + name: keycloak-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: keycloakrealmimportcontroller-role-binding +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: keycloakrealmimportcontroller-cluster-role +subjects: + - kind: ServiceAccount + name: keycloak-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: keycloakcontroller-cluster-role +rules: + - apiGroups: + - k8s.keycloak.org + resources: + - keycloaks + - keycloaks/status + - keycloaks/finalizers + verbs: + - get + - list + - watch + - create + - delete + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: keycloakrealmimportcontroller-cluster-role +rules: + - apiGroups: + - k8s.keycloak.org + resources: + - keycloakrealmimports + - keycloakrealmimports/status + - keycloakrealmimports/finalizers + verbs: + - get + - list + - watch + - create + - delete + - patch + - update +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + app.quarkus.io/build-timestamp: 2023-03-30 - 11:19:25 +0000 + labels: + app.kubernetes.io/version: 21.0.2 + app.kubernetes.io/name: keycloak-operator + name: keycloak-operator +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/version: 21.0.2 + app.kubernetes.io/name: keycloak-operator + template: + metadata: + annotations: + app.quarkus.io/build-timestamp: 2023-03-30 - 11:19:25 +0000 + labels: + app.kubernetes.io/version: 21.0.2 + app.kubernetes.io/name: keycloak-operator + spec: + containers: + - env: + - name: KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: OPERATOR_KEYCLOAK_IMAGE + value: quay.io/keycloak/keycloak:21.0.2 + image: quay.io/keycloak/keycloak-operator:21.0.2 + imagePullPolicy: Always + livenessProbe: + failureThreshold: 3 + httpGet: + path: /q/health/live + port: 8080 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + name: keycloak-operator + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /q/health/ready + port: 8080 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + serviceAccountName: keycloak-operator \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/app/stateful-resources-app.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/app/stateful-resources-app.yaml.tpl new file mode 100644 index 000000000..cced104cb --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/app/stateful-resources-app.yaml.tpl @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-4" + name: stateful-resources-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: apps/stateful-resources + repoURL: "${gitlab_project_url}" + targetRevision: HEAD + destination: + namespace: ${stateful_resources_namespace} + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/external-name-services.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/external-name-services.yaml.tpl new file mode 100644 index 000000000..45bd6406d --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/external-name-services.yaml.tpl @@ -0,0 +1,10 @@ +%{ for logical_service_name, external_name in config ~} +--- +apiVersion: v1 +kind: Service +metadata: + name: ${logical_service_name} +spec: + type: ExternalName + externalName: ${external_name} +%{ endfor ~} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/stateful-resources-kustomization.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/stateful-resources-kustomization.yaml.tpl new file mode 100644 index 000000000..f83fefe61 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/stateful-resources-kustomization.yaml.tpl @@ -0,0 +1,18 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: ${stateful_resources_namespace} +resources: +- external-name-services.yaml +%{ for stateful_resource in stateful_resources ~} +- vault-crs-${stateful_resource.local_resource.resource_helm_chart}-${stateful_resource.resource_name}.yaml +%{ endfor ~} +helmCharts: +%{ for stateful_resource in stateful_resources ~} +- name: ${stateful_resource.local_resource.resource_helm_chart} + namespace: ${stateful_resource.resource_namespace} + releaseName: ${stateful_resource.local_resource.resource_helm_chart}-${stateful_resource.resource_name} + version: ${stateful_resource.local_resource.resource_helm_chart_version} + repo: ${stateful_resource.local_resource.resource_helm_repo} + valuesFile: values-${stateful_resource.local_resource.resource_helm_chart}-${stateful_resource.resource_name}.yaml +%{ endfor ~} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/values-kafka.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/values-kafka.yaml.tpl new file mode 100644 index 000000000..5a75bcc03 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/values-kafka.yaml.tpl @@ -0,0 +1,111 @@ +## Installation +# https://bitnami.com/stack/kafka/helm +# https://github.com/bitnami/charts/blob/master/bitnami/kafka +# helm repo add bitnami https://charts.bitnami.com/bitnami +# helm install kafka bitnami/kafka -f ./bitnami-kafka-charts.IGNORE.yaml + +## @section Global parameters +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.storageClass Global StorageClass for Persistent Volume(s) +## +global: + storageClass: ${resource.local_resource.kafka_data.storage_class_name} + +## @section Common parameters + +fullnameOverride: ${resource.resource_name} + + + +## @param listeners The address(es) the socket server listens on. Auto-calculated it's set to an empty array +## When it's set to an empty array, the listeners will be configured +## based on the authentication protocols (auth.clientProtocol and auth.interBrokerProtocol parameters) +## +listeners: [] +## @param advertisedListeners The address(es) (hostname:port) the broker will advertise to producers and consumers. Auto-calculated it's set to an empty array +## When it's set to an empty array, the advertised listeners will be configured +## based on the authentication protocols (auth.clientProtocol and auth.interBrokerProtocol parameters) +## +advertisedListeners: [] + +service: + ports: + client: ${resource.local_resource.kafka_data.service_port} + +## Persistence parameters +## +persistence: + ## @param persistence.enabled Enable Kafka data persistence using PVC, note that Zookeeper persistence is unaffected + ## + enabled: true + ## @param persistence.existingClaim Provide an existing `PersistentVolumeClaim`, the value is evaluated as a template + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template + ## + existingClaim: "" + ## @param persistence.storageClass PVC Storage Class for Kafka data volume + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. + ## + storageClass: ${resource.local_resource.kafka_data.storage_class_name} + ## @param persistence.accessModes PV Access Mode + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC Storage Request for Kafka data volume + ## + size: ${resource.local_resource.kafka_data.storage_size} + ## @param persistence.annotations Annotations for the PVC + ## + annotations: {} + ## @param persistence.selector Selector to match an existing Persistent Volume for Kafka's data PVC. If set, the PVC can't have a PV dynamically provisioned for it + ## selector: + ## matchLabels: + ## app: my-app + selector: {} + ## @param persistence.mountPath Mount path of the Kafka data volume + ## + mountPath: /bitnami/kafka + +## @section Zookeeper chart parameters + +## Zookeeper chart configuration +## https://github.com/bitnami/charts/blob/master/bitnami/zookeeper/values.yaml +## +zookeeper: + ## @param zookeeper.enabled Switch to enable or disable the Zookeeper helm chart + ## + enabled: true + persistence: + ## @param persistence.existingClaim Provide an existing `PersistentVolumeClaim` + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template + ## + existingClaim: "" + ## @param persistence.enabled Enable Zookeeper data persistence using PVC + ## + enabled: true + auth: + ## @param zookeeper.auth.enabled Enable Zookeeper auth + ## + enabled: false + ## @param zookeeper.auth.clientUser User that will use Zookeeper clients to auth + ## + clientUser: "" + ## @param zookeeper.auth.clientPassword Password that will use Zookeeper clients to auth + ## + clientPassword: "" + ## @param zookeeper.auth.serverUsers Comma, semicolon or whitespace separated list of user to be created. Specify them as a string, for example: "user1,user2,admin" + ## + serverUsers: "" + ## @param zookeeper.auth.serverPasswords Comma, semicolon or whitespace separated list of passwords to assign to users when created. Specify them as a string, for example: "pass4user1, pass4user2, pass4admin" + ## + serverPasswords: "" + diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/values-mongodb.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/values-mongodb.yaml.tpl new file mode 100644 index 000000000..4caf6d017 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/values-mongodb.yaml.tpl @@ -0,0 +1,71 @@ +## @section Global parameters +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass +## + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.storageClass Global StorageClass for Persistent Volume(s) +## @param global.namespaceOverride Override the namespace for resource deployed by the chart, but can itself be overridden by the local namespaceOverride +## +global: + storageClass: ${resource.local_resource.mongodb_data.storage_class_name} + + +## @section Common parameters +## + +## @param nameOverride String to partially override mongodb.fullname template (will maintain the release name) +## +nameOverride: ${resource.resource_name} +## @param fullnameOverride String to fully override mongodb.fullname template +## +fullnameOverride: "" + +## @param architecture MongoDB(®) architecture (`standalone` or `replicaset`) +## +architecture: standalone +## @param useStatefulSet Set to true to use a StatefulSet instead of a Deployment (only when `architecture=standalone`) +## +useStatefulSet: false +## MongoDB(®) Authentication parameters +## +auth: + ## @param auth.enabled Enable authentication + ## ref: https://docs.mongodb.com/manual/tutorial/enable-authentication/ + ## + enabled: true + ## @param auth.rootUser MongoDB(®) root user + ## + rootUser: root + ## MongoDB(®) custom users and databases + ## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#creating-users-and-databases-on-first-run + ## @param auth.usernames List of custom users to be created during the initialization + ## @param auth.passwords List of passwords for the custom users set at `auth.usernames` + ## @param auth.databases List of custom databases to be created during the initialization + ## + usernames: [] + passwords: [] + databases: [] + ## @param auth.username DEPRECATED: use `auth.usernames` instead + ## @param auth.password DEPRECATED: use `auth.passwords` instead + ## @param auth.database DEPRECATED: use `auth.databases` instead + database: ${resource.local_resource.mongodb_data.database_name} + username: ${resource.local_resource.mongodb_data.user} + ## @param auth.replicaSetKey Key used for authentication in the replicaset (only when `architecture=replicaset`) + ## + replicaSetKey: "" + ## @param auth.existingSecret Existing secret with MongoDB(®) credentials (keys: `mongodb-password`, `mongodb-root-password`, ` mongodb-replica-set-key`) + ## NOTE: When it's set the previous parameters are ignored. + ## + existingSecret: ${resource.local_resource.mongodb_data.existing_secret} + +persistence: + ## @param persistence.enabled Enable MongoDB(®) data persistence using PVC + ## + enabled: true + size: ${resource.local_resource.mongodb_data.storage_size} +service: + ports: + mongodb: ${resource.local_resource.mongodb_data.service_port} diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/values-mysql.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/values-mysql.yaml.tpl new file mode 100644 index 000000000..e52f3c141 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/values-mysql.yaml.tpl @@ -0,0 +1,318 @@ +## Installation +# https://bitnami.com/stack/mysql/helm +# https://github.com/bitnami/charts/tree/master/bitnami/mysql +# $ helm repo add bitnami https://charts.bitnami.com/bitnami +# $ helm install my-release bitnami/mysql -f ./bitnami-kafka-charts.IGNORE.yaml + +## @section Common parameters + +## @param fullnameOverride String to fully override common.names.fullname template +## +nameOverride: ${resource.resource_name} + +## @param architecture MySQL architecture (`standalone` or `replication`) +## +# architecture: standalone +architecture: ${resource.local_resource.mysql_data.architecture} + +auth: + ## @param auth.database Name for a custom database to create + ## ref: https://github.com/bitnami/bitnami-docker-mysql/blob/master/README.md#creating-a-database-on-first-run + ## + database: ${resource.local_resource.mysql_data.database_name} + ## @param auth.username Name for a custom user to create + ## ref: https://github.com/bitnami/bitnami-docker-mysql/blob/master/README.md#creating-a-database-user-on-first-run + ## + username: ${resource.local_resource.mysql_data.user} + ## @param auth.replicationUser MySQL replication user + ## ref: https://github.com/bitnami/bitnami-docker-mysql#setting-up-a-replication-cluster + ## + ## @param auth.replicationUser MySQL replication user + ## ref: https://github.com/bitnami/bitnami-docker-mysql#setting-up-a-replication-cluster + ## + replicationUser: replicator + ## @param auth.existingSecret Use existing secret for password details. The secret has to contain the keys `mysql-root-password`, `mysql-replication-password` and `mysql-password` + ## NOTE: When it's set the auth.rootPassword, auth.password, auth.replicationPassword are ignored. + ## + existingSecret: ${resource.local_resource.mysql_data.existing_secret} + +## @section MySQL Primary parameters + +primary: + ## @param primary.configuration [string] Configure MySQL Primary with a custom my.cnf file + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + default_authentication_plugin=mysql_native_password + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mysql + plugin_dir=/opt/bitnami/mysql/lib/plugin + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + datadir=/bitnami/mysql/data + tmpdir=/opt/bitnami/mysql/tmp + max_allowed_packet=16M + bind-address=0.0.0.0 + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + log-error=/opt/bitnami/mysql/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + + [client] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + default-character-set=UTF8 + plugin_dir=/opt/bitnami/mysql/lib/plugin + + [manager] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + + ## @param primary.affinity [object] Affinity for MySQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set + ## + # affinity: {} + affinity: + podAntiAffinity: + ### Select either the Hard or Soft podAntiAffinity policy + ## Hard podAntiAffinity policy + # requiredDuringSchedulingIgnoredDuringExecution: + # - podAffinityTerm: + # labelSelector: + # matchExpressions: + # - key: app.kubernetes.io/instance + # operator: In + # values: + # - db + # topologyKey: topology.kubernetes.io/zone + + ## Soft podAntiAffinity policy + ## Note: weight is set to ensure that the anti-affinity is more important for the scheduler than the node-load policy, e.g. k8s will prefer AZ spreading over equally-loading of the nodes and other factors. + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/instance + operator: In + values: + - ${resource.resource_name} + topologyKey: topology.kubernetes.io/zone + weight: 100 + ## MySQL primary Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param primary.pdb.enabled Enable/disable a Pod Disruption Budget creation for MySQL primary pods + ## + enabled: true + ## @param primary.pdb.minAvailable Minimum number/percentage of MySQL primary pods that should remain scheduled + ## + minAvailable: 1 + ## @param primary.pdb.maxUnavailable Maximum number/percentage of MySQL primary pods that may be made unavailable + ## + maxUnavailable: "" + ## MySQL primary container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + ## @param primary.resources.limits [object] The resources limits for MySQL primary containers + ## @param primary.resources.requests [object] The requested resources for MySQL primary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 250m + ## memory: 256Mi + limits: {} + ## Examples: + ## requests: + ## cpu: 250m + ## memory: 256Mi + requests: {} + + persistence: + ## @param primary.persistence.enabled Enable persistence on MySQL primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir + ## + enabled: true + ## @param primary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL primary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param primary.persistence.storageClass MySQL primary persistent volume storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: ${resource.local_resource.mysql_data.storage_class_name} + ## @param primary.persistence.annotations [object] MySQL primary persistent volume claim annotations + ## + annotations: {} + ## @param primary.persistence.accessModes MySQL primary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param primary.persistence.size MySQL primary persistent volume size + ## + size: ${resource.local_resource.mysql_data.storage_size} + ## @param primary.persistence.selector [object] Selector to match an existing Persistent Volume + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + service: + ports: + mysql: ${resource.local_resource.mysql_data.service_port} +## @section MySQL Secondary parameters + +secondary: + ## @param secondary.replicaCount Number of MySQL secondary replicas + ## + replicaCount: ${resource.local_resource.mysql_data.replica_count} + + ## @param secondary.configuration [string] Configure MySQL Secondary with a custom my.cnf file + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + default_authentication_plugin=mysql_native_password + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mysql + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + datadir=/bitnami/mysql/data + tmpdir=/opt/bitnami/mysql/tmp + max_allowed_packet=16M + bind-address=0.0.0.0 + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + log-error=/opt/bitnami/mysql/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + + [client] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + default-character-set=UTF8 + + [manager] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + + ## @param secondary.affinity [object] Affinity for MySQL secondary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set + ## + # affinity: {} + affinity: + podAntiAffinity: + ### Select either the Hard or Soft podAntiAffinity policy + ## Hard podAntiAffinity policy + # requiredDuringSchedulingIgnoredDuringExecution: + # - podAffinityTerm: + # labelSelector: + # matchExpressions: + # - key: app.kubernetes.io/instance + # operator: In + # values: + # - db + # topologyKey: topology.kubernetes.io/zone + + ## Soft podAntiAffinity policy + ## Note: weight is set to ensure that the anti-affinity is more important for the scheduler than the node-load policy, e.g. k8s will prefer AZ spreading over equally-loading of the nodes and other factors. + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/instance + operator: In + values: + - ${resource.resource_name} + topologyKey: topology.kubernetes.io/zone + weight: 100 + ## MySQL secondary Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param secondary.pdb.enabled Enable/disable a Pod Disruption Budget creation for MySQL secondary pods + ## + enabled: true + ## @param secondary.pdb.minAvailable Minimum number/percentage of MySQL secondary pods that should remain scheduled + ## + minAvailable: 1 + ## @param secondary.pdb.maxUnavailable Maximum number/percentage of MySQL secondary pods that may be made unavailable + ## + maxUnavailable: "" + ## MySQL secondary container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + ## @param secondary.resources.limits [object] The resources limits for MySQL secondary containers + ## @param secondary.resources.requests [object] The requested resources for MySQL secondary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 250m + ## memory: 256Mi + limits: {} + ## Examples: + ## requests: + ## cpu: 250m + ## memory: 256Mi + requests: {} + + persistence: + ## @param secondary.persistence.enabled Enable persistence on MySQL secondary replicas using a `PersistentVolumeClaim`. If false, use emptyDir + ## + enabled: true + ## @param secondary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL primary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param secondary.persistence.storageClass MySQL secondary persistent volume storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: ${resource.local_resource.mysql_data.storage_class_name} + ## @param secondary.persistence.annotations [object] MySQL secondary persistent volume claim annotations + ## + annotations: {} + ## @param secondary.persistence.accessModes MySQL secondary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param secondary.persistence.size MySQL secondary persistent volume size + ## + size: ${resource.local_resource.mysql_data.storage_size} + ## @param secondary.persistence.selector [object] Selector to match an existing Persistent Volume + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + +initdbScripts: + # This script enables legacy authentication for MySQL v8. NodeJS MySQL Client currently does not support authentication plugins, reference: https://github.com/mysqljs/mysql/pull/2233 + enableLegacyAuth.sh: | + #!/bin/bash + set -e + DB_USER=${resource.local_resource.mysql_data.user} + echo "******* ALTER USER '$DB_USER' *******" + mysql -u root -p$MYSQL_ROOT_PASSWORD -e \ + "ALTER USER '$DB_USER'@'%' IDENTIFIED WITH mysql_native_password BY '$MYSQL_PASSWORD'; + echo "******* ALTER USER '$DB_USER' complete *******" \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/values-redis.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/values-redis.yaml.tpl new file mode 100644 index 000000000..ad616e06f --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/values-redis.yaml.tpl @@ -0,0 +1,1662 @@ +## @section Global parameters +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass +## + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.storageClass Global StorageClass for Persistent Volume(s) +## @param global.redis.password Global Redis® password (overrides `auth.password`) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: ${resource.local_resource.redis_data.storage_class_name} + +## @section Common parameters +## + +## @param kubeVersion Override Kubernetes version +## +kubeVersion: "" +## @param nameOverride String to partially override common.names.fullname +## +nameOverride: ${resource.resource_name} +## @param fullnameOverride String to fully override common.names.fullname +## +fullnameOverride: "" +## @param commonLabels Labels to add to all deployed objects +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param secretAnnotations Annotations to add to secret +## +secretAnnotations: {} +## @param clusterDomain Kubernetes cluster domain name +## +clusterDomain: cluster.local +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] + +## Enable diagnostic mode in the deployment +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers in the deployment + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers in the deployment + ## + args: + - infinity + +## @section Redis® Image parameters +## + +## Bitnami Redis® image +## ref: https://hub.docker.com/r/bitnami/redis/tags/ +## @param image.registry Redis® image registry +## @param image.repository Redis® image repository +## @param image.tag Redis® image tag (immutable tags are recommended) +## @param image.digest Redis® image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy Redis® image pull policy +## @param image.pullSecrets Redis® image pull secrets +## @param image.debug Enable image debug mode +## +image: + registry: docker.io + repository: bitnami/redis + tag: 7.0.5-debian-11-r7 + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Enable debug mode + ## + debug: false + +## @section Redis® common configuration parameters +## https://github.com/bitnami/containers/tree/main/bitnami/redis#configuration +## + +## @param architecture Redis® architecture. Allowed values: `standalone` or `replication` +## +architecture: ${resource.local_resource.redis_data.architecture} +## Redis® Authentication parameters +## ref: https://github.com/bitnami/containers/tree/main/bitnami/redis#setting-the-server-password-on-first-run +## +auth: + ## @param auth.enabled Enable password authentication + ## set to false until 3rd party supports auth + enabled: false + ## @param auth.sentinel Enable password authentication on sentinels too + ## + sentinel: true + + ## @param auth.existingSecret The name of an existing secret with Redis® credentials + ## NOTE: When it's set, the previous `auth.password` parameter is ignored + ## + existingSecret: ${resource.local_resource.redis_data.existing_secret} + ## @param auth.existingSecretPasswordKey Password key to be retrieved from existing secret + ## NOTE: ignored unless `auth.existingSecret` parameter is set + ## + existingSecretPasswordKey: ${resource.local_resource.redis_data.existing_secret_key} + ## @param auth.usePasswordFiles Mount credentials as files instead of using an environment variable + ## + usePasswordFiles: false + +## @param commonConfiguration [string] Common configuration to be added into the ConfigMap +## ref: https://redis.io/topics/config +## +commonConfiguration: |- + # Enable AOF https://redis.io/topics/persistence#append-only-file + appendonly yes + # Disable RDB persistence, AOF persistence already enabled. + save "" +## @param existingConfigmap The name of an existing ConfigMap with your custom configuration for Redis® nodes +## +existingConfigmap: "" + +## @section Redis® master configuration parameters +## + +master: + ## @param master.count Number of Redis® master instances to deploy (experimental, requires additional configuration) + ## + count: 1 + ## @param master.configuration Configuration for Redis® master nodes + ## ref: https://redis.io/topics/config + ## + configuration: "" + ## @param master.disableCommands Array with Redis® commands to disable on master nodes + ## Commands will be completely disabled by renaming each to an empty string. + ## ref: https://redis.io/topics/security#disabling-of-specific-commands + ## + disableCommands: + - FLUSHDB + - FLUSHALL + ## @param master.command Override default container command (useful when using custom images) + ## + command: [] + ## @param master.args Override default container args (useful when using custom images) + ## + args: [] + ## @param master.preExecCmds Additional commands to run prior to starting Redis® master + ## + preExecCmds: [] + ## @param master.extraFlags Array with additional command line flags for Redis® master + ## e.g: + ## extraFlags: + ## - "--maxmemory-policy volatile-ttl" + ## - "--repl-backlog-size 1024mb" + ## + extraFlags: [] + ## @param master.extraEnvVars Array with extra environment variables to add to Redis® master nodes + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param master.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® master nodes + ## + extraEnvVarsCM: "" + ## @param master.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® master nodes + ## + extraEnvVarsSecret: "" + ## @param master.containerPorts.redis Container port to open on Redis® master nodes + ## + containerPorts: + redis: 6379 + ## Configure extra options for Redis® containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param master.startupProbe.enabled Enable startupProbe on Redis® master nodes + ## @param master.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param master.startupProbe.periodSeconds Period seconds for startupProbe + ## @param master.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param master.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param master.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + ## @param master.livenessProbe.enabled Enable livenessProbe on Redis® master nodes + ## @param master.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param master.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param master.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param master.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param master.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + ## @param master.readinessProbe.enabled Enable readinessProbe on Redis® master nodes + ## @param master.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param master.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param master.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param master.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param master.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + ## @param master.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## @param master.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param master.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## Redis® master resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param master.resources.limits The resources limits for the Redis® master containers + ## @param master.resources.requests The requested resources for the Redis® master containers + ## + resources: + limits: {} + requests: {} + ## Configure Pods Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param master.podSecurityContext.enabled Enabled Redis® master pods' Security Context + ## @param master.podSecurityContext.fsGroup Set Redis® master pod's Security Context fsGroup + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param master.containerSecurityContext.enabled Enabled Redis® master containers' Security Context + ## @param master.containerSecurityContext.runAsUser Set Redis® master containers' Security Context runAsUser + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + ## @param master.kind Use either Deployment or StatefulSet (default) + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ + ## + kind: StatefulSet + ## @param master.schedulerName Alternate scheduler for Redis® master pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param master.updateStrategy.type Redis® master statefulset strategy type + ## @skip master.updateStrategy.rollingUpdate + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + rollingUpdate: {} + ## @param master.priorityClassName Redis® master pods' priorityClassName + ## + priorityClassName: "" + ## @param master.hostAliases Redis® master pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param master.podLabels Extra labels for Redis® master pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param master.podAnnotations Annotations for Redis® master pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param master.shareProcessNamespace Share a single process namespace between all of the containers in Redis® master pods + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/ + ## + shareProcessNamespace: false + ## @param master.podAffinityPreset Pod affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param master.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Node master.affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param master.nodeAffinityPreset.type Node affinity preset type. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param master.nodeAffinityPreset.key Node label key to match. Ignored if `master.affinity` is set + ## + key: "" + ## @param master.nodeAffinityPreset.values Node label values to match. Ignored if `master.affinity` is set + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param master.affinity Affinity for Redis® master pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## NOTE: `master.podAffinityPreset`, `master.podAntiAffinityPreset`, and `master.nodeAffinityPreset` will be ignored when it's set + ## + affinity: {} + ## @param master.nodeSelector Node labels for Redis® master pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param master.tolerations Tolerations for Redis® master pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param master.topologySpreadConstraints Spread Constraints for Redis® master pod assignment + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## E.g. + ## topologySpreadConstraints: + ## - maxSkew: 1 + ## topologyKey: node + ## whenUnsatisfiable: DoNotSchedule + ## + topologySpreadConstraints: [] + ## @param master.dnsPolicy DNS Policy for Redis® master pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ + ## E.g. + ## dnsPolicy: ClusterFirst + dnsPolicy: "" + ## @param master.dnsConfig DNS Configuration for Redis® master pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ + ## E.g. + ## dnsConfig: + ## options: + ## - name: ndots + ## value: "4" + ## - name: single-request-reopen + dnsConfig: {} + ## @param master.lifecycleHooks for the Redis® master container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param master.extraVolumes Optionally specify extra list of additional volumes for the Redis® master pod(s) + ## + extraVolumes: [] + ## @param master.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® master container(s) + ## + extraVolumeMounts: [] + ## @param master.sidecars Add additional sidecar containers to the Redis® master pod(s) + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param master.initContainers Add additional init containers to the Redis® master pod(s) + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## command: ['sh', '-c', 'echo "hello world"'] + ## + initContainers: [] + ## Persistence parameters + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param master.persistence.enabled Enable persistence on Redis® master nodes using Persistent Volume Claims + ## + enabled: true + ## @param master.persistence.medium Provide a medium for `emptyDir` volumes. + ## + medium: "" + ## @param master.persistence.sizeLimit Set this to enable a size limit for `emptyDir` volumes. + ## + sizeLimit: "" + ## @param master.persistence.path The path the volume will be mounted at on Redis® master containers + ## NOTE: Useful when using different Redis® images + ## + path: /data + ## @param master.persistence.subPath The subdirectory of the volume to mount on Redis® master containers + ## NOTE: Useful in dev environments + ## + subPath: "" + ## @param master.persistence.storageClass Persistent Volume storage class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner + ## + storageClass: "" + ## @param master.persistence.accessModes Persistent Volume access modes + ## + accessModes: + - ReadWriteOnce + ## @param master.persistence.size Persistent Volume size + ## + size: ${resource.local_resource.redis_data.storage_size} + ## @param master.persistence.annotations Additional custom annotations for the PVC + ## + annotations: {} + ## @param master.persistence.selector Additional labels to match for the PVC + ## e.g: + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param master.persistence.dataSource Custom PVC data source + ## + dataSource: {} + ## @param master.persistence.existingClaim Use a existing PVC which must be created manually before bound + ## NOTE: requires master.persistence.enabled: true + ## + existingClaim: "" + ## Redis® master service parameters + ## + service: + ## @param master.service.type Redis® master service type + ## + type: ClusterIP + ## @param master.service.ports.redis Redis® master service port + ## + ports: + redis: ${resource.local_resource.redis_data.service_port} + ## @param master.service.nodePorts.redis Node port for Redis® master + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## NOTE: choose port between <30000-32767> + ## + nodePorts: + redis: "" + ## @param master.service.externalTrafficPolicy Redis® master service external traffic policy + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param master.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param master.service.internalTrafficPolicy Redis® master service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) + ## ref: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/ + ## + internalTrafficPolicy: Cluster + ## @param master.service.clusterIP Redis® master service Cluster IP + ## + clusterIP: "" + ## @param master.service.loadBalancerIP Redis® master service Load Balancer IP + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param master.service.loadBalancerSourceRanges Redis® master service Load Balancer sources + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## e.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param master.service.annotations Additional custom annotations for Redis® master service + ## + annotations: {} + ## @param master.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param master.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param master.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-master pods + ## + terminationGracePeriodSeconds: 30 + ## ServiceAccount configuration + ## + serviceAccount: + ## @param master.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: false + ## @param master.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param master.serviceAccount.automountServiceAccountToken Whether to auto mount the service account token + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server + ## + automountServiceAccountToken: true + ## @param master.serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} + +## @section Redis® replicas configuration parameters +## + +replica: + ## @param replica.replicaCount Number of Redis® replicas to deploy + ## + replicaCount: ${resource.local_resource.redis_data.replica_count} + ## @param replica.configuration Configuration for Redis® replicas nodes + ## ref: https://redis.io/topics/config + ## + configuration: "" + ## @param replica.disableCommands Array with Redis® commands to disable on replicas nodes + ## Commands will be completely disabled by renaming each to an empty string. + ## ref: https://redis.io/topics/security#disabling-of-specific-commands + ## + disableCommands: + - FLUSHDB + - FLUSHALL + ## @param replica.command Override default container command (useful when using custom images) + ## + command: [] + ## @param replica.args Override default container args (useful when using custom images) + ## + args: [] + ## @param replica.preExecCmds Additional commands to run prior to starting Redis® replicas + ## + preExecCmds: [] + ## @param replica.extraFlags Array with additional command line flags for Redis® replicas + ## e.g: + ## extraFlags: + ## - "--maxmemory-policy volatile-ttl" + ## - "--repl-backlog-size 1024mb" + ## + extraFlags: [] + ## @param replica.extraEnvVars Array with extra environment variables to add to Redis® replicas nodes + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param replica.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® replicas nodes + ## + extraEnvVarsCM: "" + ## @param replica.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® replicas nodes + ## + extraEnvVarsSecret: "" + ## @param replica.externalMaster.enabled Use external master for bootstrapping + ## @param replica.externalMaster.host External master host to bootstrap from + ## @param replica.externalMaster.port Port for Redis service external master host + ## + externalMaster: + enabled: false + host: "" + port: 6379 + ## @param replica.containerPorts.redis Container port to open on Redis® replicas nodes + ## + containerPorts: + redis: 6379 + ## Configure extra options for Redis® containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param replica.startupProbe.enabled Enable startupProbe on Redis® replicas nodes + ## @param replica.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param replica.startupProbe.periodSeconds Period seconds for startupProbe + ## @param replica.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param replica.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param replica.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 22 + ## @param replica.livenessProbe.enabled Enable livenessProbe on Redis® replicas nodes + ## @param replica.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param replica.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param replica.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param replica.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param replica.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + ## @param replica.readinessProbe.enabled Enable readinessProbe on Redis® replicas nodes + ## @param replica.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param replica.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param replica.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param replica.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param replica.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + ## @param replica.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## @param replica.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param replica.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## Redis® replicas resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param replica.resources.limits The resources limits for the Redis® replicas containers + ## @param replica.resources.requests The requested resources for the Redis® replicas containers + ## + resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: {} + # cpu: 250m + # memory: 256Mi + requests: {} + # cpu: 250m + # memory: 256Mi + ## Configure Pods Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param replica.podSecurityContext.enabled Enabled Redis® replicas pods' Security Context + ## @param replica.podSecurityContext.fsGroup Set Redis® replicas pod's Security Context fsGroup + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param replica.containerSecurityContext.enabled Enabled Redis® replicas containers' Security Context + ## @param replica.containerSecurityContext.runAsUser Set Redis® replicas containers' Security Context runAsUser + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + ## @param replica.schedulerName Alternate scheduler for Redis® replicas pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param replica.updateStrategy.type Redis® replicas statefulset strategy type + ## @skip replica.updateStrategy.rollingUpdate + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + rollingUpdate: {} + ## @param replica.priorityClassName Redis® replicas pods' priorityClassName + ## + priorityClassName: "" + ## @param replica.podManagementPolicy podManagementPolicy to manage scaling operation of %%MAIN_CONTAINER_NAME%% pods + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: "" + ## @param replica.hostAliases Redis® replicas pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param replica.podLabels Extra labels for Redis® replicas pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param replica.podAnnotations Annotations for Redis® replicas pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param replica.shareProcessNamespace Share a single process namespace between all of the containers in Redis® replicas pods + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/ + ## + shareProcessNamespace: false + ## @param replica.podAffinityPreset Pod affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param replica.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param replica.nodeAffinityPreset.type Node affinity preset type. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param replica.nodeAffinityPreset.key Node label key to match. Ignored if `replica.affinity` is set + ## + key: "" + ## @param replica.nodeAffinityPreset.values Node label values to match. Ignored if `replica.affinity` is set + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param replica.affinity Affinity for Redis® replicas pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## NOTE: `replica.podAffinityPreset`, `replica.podAntiAffinityPreset`, and `replica.nodeAffinityPreset` will be ignored when it's set + ## + affinity: {} + ## @param replica.nodeSelector Node labels for Redis® replicas pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param replica.tolerations Tolerations for Redis® replicas pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param replica.topologySpreadConstraints Spread Constraints for Redis® replicas pod assignment + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## E.g. + ## topologySpreadConstraints: + ## - maxSkew: 1 + ## topologyKey: node + ## whenUnsatisfiable: DoNotSchedule + ## + topologySpreadConstraints: [] + ## @param replica.dnsPolicy DNS Policy for Redis® replica pods + ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ + ## E.g. + ## dnsPolicy: ClusterFirst + dnsPolicy: "" + ## @param replica.dnsConfig DNS Configuration for Redis® replica pods + ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ + ## E.g. + ## dnsConfig: + ## options: + ## - name: ndots + ## value: "4" + ## - name: single-request-reopen + dnsConfig: {} + ## @param replica.lifecycleHooks for the Redis® replica container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param replica.extraVolumes Optionally specify extra list of additional volumes for the Redis® replicas pod(s) + ## + extraVolumes: [] + ## @param replica.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® replicas container(s) + ## + extraVolumeMounts: [] + ## @param replica.sidecars Add additional sidecar containers to the Redis® replicas pod(s) + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param replica.initContainers Add additional init containers to the Redis® replicas pod(s) + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## command: ['sh', '-c', 'echo "hello world"'] + ## + initContainers: [] + ## Persistence Parameters + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param replica.persistence.enabled Enable persistence on Redis® replicas nodes using Persistent Volume Claims + ## + enabled: true + ## @param replica.persistence.medium Provide a medium for `emptyDir` volumes. + ## + medium: "" + ## @param replica.persistence.sizeLimit Set this to enable a size limit for `emptyDir` volumes. + ## + sizeLimit: "" + ## @param replica.persistence.path The path the volume will be mounted at on Redis® replicas containers + ## NOTE: Useful when using different Redis® images + ## + path: /data + ## @param replica.persistence.subPath The subdirectory of the volume to mount on Redis® replicas containers + ## NOTE: Useful in dev environments + ## + subPath: "" + ## @param replica.persistence.storageClass Persistent Volume storage class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner + ## + storageClass: "" + ## @param replica.persistence.accessModes Persistent Volume access modes + ## + accessModes: + - ReadWriteOnce + ## @param replica.persistence.size Persistent Volume size + ## + size: 8Gi + ## @param replica.persistence.annotations Additional custom annotations for the PVC + ## + annotations: {} + ## @param replica.persistence.selector Additional labels to match for the PVC + ## e.g: + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param replica.persistence.dataSource Custom PVC data source + ## + dataSource: {} + ## @param replica.persistence.existingClaim Use a existing PVC which must be created manually before bound + ## NOTE: requires replica.persistence.enabled: true + ## + existingClaim: "" + ## Redis® replicas service parameters + ## + service: + ## @param replica.service.type Redis® replicas service type + ## + type: ClusterIP + ## @param replica.service.ports.redis Redis® replicas service port + ## + ports: + redis: 6379 + ## @param replica.service.nodePorts.redis Node port for Redis® replicas + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## NOTE: choose port between <30000-32767> + ## + nodePorts: + redis: "" + ## @param replica.service.externalTrafficPolicy Redis® replicas service external traffic policy + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param replica.service.internalTrafficPolicy Redis® replicas service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) + ## ref: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/ + ## + internalTrafficPolicy: Cluster + ## @param replica.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param replica.service.clusterIP Redis® replicas service Cluster IP + ## + clusterIP: "" + ## @param replica.service.loadBalancerIP Redis® replicas service Load Balancer IP + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param replica.service.loadBalancerSourceRanges Redis® replicas service Load Balancer sources + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## e.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param replica.service.annotations Additional custom annotations for Redis® replicas service + ## + annotations: {} + ## @param replica.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param replica.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param replica.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-replicas pods + ## + terminationGracePeriodSeconds: 30 + ## Autoscaling configuration + ## + autoscaling: + ## @param replica.autoscaling.enabled Enable replica autoscaling settings + ## + enabled: false + ## @param replica.autoscaling.minReplicas Minimum replicas for the pod autoscaling + ## + minReplicas: 1 + ## @param replica.autoscaling.maxReplicas Maximum replicas for the pod autoscaling + ## + maxReplicas: 11 + ## @param replica.autoscaling.targetCPU Percentage of CPU to consider when autoscaling + ## + targetCPU: "" + ## @param replica.autoscaling.targetMemory Percentage of Memory to consider when autoscaling + ## + targetMemory: "" + ## ServiceAccount configuration + ## + serviceAccount: + ## @param replica.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: false + ## @param replica.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param replica.serviceAccount.automountServiceAccountToken Whether to auto mount the service account token + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server + ## + automountServiceAccountToken: true + ## @param replica.serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} +## @section Redis® Sentinel configuration parameters +## + +sentinel: + ## @param sentinel.enabled Use Redis® Sentinel on Redis® pods. + ## IMPORTANT: this will disable the master and replicas services and + ## create a single Redis® service exposing both the Redis and Sentinel ports + ## + enabled: false + ## Bitnami Redis® Sentinel image version + ## ref: https://hub.docker.com/r/bitnami/redis-sentinel/tags/ + ## @param sentinel.image.registry Redis® Sentinel image registry + ## @param sentinel.image.repository Redis® Sentinel image repository + ## @param sentinel.image.tag Redis® Sentinel image tag (immutable tags are recommended) + ## @param sentinel.image.digest Redis® Sentinel image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param sentinel.image.pullPolicy Redis® Sentinel image pull policy + ## @param sentinel.image.pullSecrets Redis® Sentinel image pull secrets + ## @param sentinel.image.debug Enable image debug mode + ## + image: + registry: docker.io + repository: bitnami/redis-sentinel + tag: 7.0.5-debian-11-r6 + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Enable debug mode + ## + debug: false + ## @param sentinel.masterSet Master set name + ## + masterSet: mymaster + ## @param sentinel.quorum Sentinel Quorum + ## + quorum: 2 + ## @param sentinel.getMasterTimeout Amount of time to allow before get_sentinel_master_info() times out. + ## NOTE: This is directly related to the startupProbes which are configured to run every 10 seconds for a total of 22 failures. If adjusting this value, also adjust the startupProbes. + getMasterTimeout: 220 + ## @param sentinel.automateClusterRecovery Automate cluster recovery in cases where the last replica is not considered a good replica and Sentinel won't automatically failover to it. + ## This also prevents any new replica from starting until the last remaining replica is elected as master to guarantee that it is the one to be elected by Sentinel, and not a newly started replica with no data. + ## NOTE: This feature requires a "downAfterMilliseconds" value less or equal to 2000. + ## + automateClusterRecovery: false + ## Sentinel timing restrictions + ## @param sentinel.downAfterMilliseconds Timeout for detecting a Redis® node is down + ## @param sentinel.failoverTimeout Timeout for performing a election failover + ## + downAfterMilliseconds: 60000 + failoverTimeout: 180000 + ## @param sentinel.parallelSyncs Number of replicas that can be reconfigured in parallel to use the new master after a failover + ## + parallelSyncs: 1 + ## @param sentinel.configuration Configuration for Redis® Sentinel nodes + ## ref: https://redis.io/topics/sentinel + ## + configuration: "" + ## @param sentinel.command Override default container command (useful when using custom images) + ## + command: [] + ## @param sentinel.args Override default container args (useful when using custom images) + ## + args: [] + ## @param sentinel.preExecCmds Additional commands to run prior to starting Redis® Sentinel + ## + preExecCmds: [] + ## @param sentinel.extraEnvVars Array with extra environment variables to add to Redis® Sentinel nodes + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param sentinel.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® Sentinel nodes + ## + extraEnvVarsCM: "" + ## @param sentinel.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® Sentinel nodes + ## + extraEnvVarsSecret: "" + ## @param sentinel.externalMaster.enabled Use external master for bootstrapping + ## @param sentinel.externalMaster.host External master host to bootstrap from + ## @param sentinel.externalMaster.port Port for Redis service external master host + ## + externalMaster: + enabled: false + host: "" + port: 6379 + ## @param sentinel.containerPorts.sentinel Container port to open on Redis® Sentinel nodes + ## + containerPorts: + sentinel: 26379 + ## Configure extra options for Redis® containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param sentinel.startupProbe.enabled Enable startupProbe on Redis® Sentinel nodes + ## @param sentinel.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param sentinel.startupProbe.periodSeconds Period seconds for startupProbe + ## @param sentinel.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param sentinel.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param sentinel.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 22 + ## @param sentinel.livenessProbe.enabled Enable livenessProbe on Redis® Sentinel nodes + ## @param sentinel.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param sentinel.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param sentinel.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param sentinel.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param sentinel.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + ## @param sentinel.readinessProbe.enabled Enable readinessProbe on Redis® Sentinel nodes + ## @param sentinel.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param sentinel.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param sentinel.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param sentinel.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param sentinel.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + ## @param sentinel.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## @param sentinel.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param sentinel.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## Persistence parameters + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param sentinel.persistence.enabled Enable persistence on Redis® sentinel nodes using Persistent Volume Claims (Experimental) + ## + enabled: false + ## @param sentinel.persistence.storageClass Persistent Volume storage class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner + ## + storageClass: "" + ## @param sentinel.persistence.accessModes Persistent Volume access modes + ## + accessModes: + - ReadWriteOnce + ## @param sentinel.persistence.size Persistent Volume size + ## + size: 100Mi + ## @param sentinel.persistence.annotations Additional custom annotations for the PVC + ## + annotations: {} + ## @param sentinel.persistence.selector Additional labels to match for the PVC + ## e.g: + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param sentinel.persistence.dataSource Custom PVC data source + ## + dataSource: {} + ## @param sentinel.persistence.medium Provide a medium for `emptyDir` volumes. + ## + medium: "" + ## Redis® Sentinel resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param sentinel.resources.limits The resources limits for the Redis® Sentinel containers + ## @param sentinel.resources.requests The requested resources for the Redis® Sentinel containers + ## + resources: + limits: {} + requests: {} + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param sentinel.containerSecurityContext.enabled Enabled Redis® Sentinel containers' Security Context + ## @param sentinel.containerSecurityContext.runAsUser Set Redis® Sentinel containers' Security Context runAsUser + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + ## @param sentinel.lifecycleHooks for the Redis® sentinel container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param sentinel.extraVolumes Optionally specify extra list of additional volumes for the Redis® Sentinel + ## + extraVolumes: [] + ## @param sentinel.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® Sentinel container(s) + ## + extraVolumeMounts: [] + ## Redis® Sentinel service parameters + ## + service: + ## @param sentinel.service.type Redis® Sentinel service type + ## + type: ClusterIP + ## @param sentinel.service.ports.redis Redis® service port for Redis® + ## @param sentinel.service.ports.sentinel Redis® service port for Redis® Sentinel + ## + ports: + redis: 6379 + sentinel: 26379 + ## @param sentinel.service.nodePorts.redis Node port for Redis® + ## @param sentinel.service.nodePorts.sentinel Node port for Sentinel + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## NOTE: choose port between <30000-32767> + ## NOTE: By leaving these values blank, they will be generated by ports-configmap + ## If setting manually, please leave at least replica.replicaCount + 1 in between sentinel.service.nodePorts.redis and sentinel.service.nodePorts.sentinel to take into account the ports that will be created while incrementing that base port + ## + nodePorts: + redis: "" + sentinel: "" + ## @param sentinel.service.externalTrafficPolicy Redis® Sentinel service external traffic policy + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param sentinel.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param sentinel.service.clusterIP Redis® Sentinel service Cluster IP + ## + clusterIP: "" + ## @param sentinel.service.loadBalancerIP Redis® Sentinel service Load Balancer IP + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param sentinel.service.loadBalancerSourceRanges Redis® Sentinel service Load Balancer sources + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## e.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param sentinel.service.annotations Additional custom annotations for Redis® Sentinel service + ## + annotations: {} + ## @param sentinel.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param sentinel.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param sentinel.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-node pods + ## + terminationGracePeriodSeconds: 30 + +## @section Other Parameters +## + +## Network Policy configuration +## ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +## +networkPolicy: + ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources + ## + enabled: false + ## @param networkPolicy.allowExternal Don't require client label for connections + ## When set to false, only pods with the correct client label will have network access to the ports + ## Redis® is listening on. When true, Redis® will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## e.g: + ## extraIngress: + ## - ports: + ## - port: 1234 + ## from: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + ## + extraIngress: [] + ## @param networkPolicy.extraEgress Add extra egress rules to the NetworkPolicy + ## e.g: + ## extraEgress: + ## - ports: + ## - port: 1234 + ## to: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + ## + extraEgress: [] + ## @param networkPolicy.ingressNSMatchLabels Labels to match to allow traffic from other namespaces + ## @param networkPolicy.ingressNSPodMatchLabels Pod labels to match to allow traffic from other namespaces + ## + ingressNSMatchLabels: {} + ingressNSPodMatchLabels: {} +## PodSecurityPolicy configuration +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +podSecurityPolicy: + ## @param podSecurityPolicy.create Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later + ## + create: false + ## @param podSecurityPolicy.enabled Enable PodSecurityPolicy's RBAC rules + ## + enabled: false +## RBAC configuration +## +rbac: + ## @param rbac.create Specifies whether RBAC resources should be created + ## + create: false + ## @param rbac.rules Custom RBAC rules to set + ## e.g: + ## rules: + ## - apiGroups: + ## - "" + ## resources: + ## - pods + ## verbs: + ## - get + ## - list + ## + rules: [] +## ServiceAccount configuration +## +serviceAccount: + ## @param serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param serviceAccount.automountServiceAccountToken Whether to auto mount the service account token + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server + ## + automountServiceAccountToken: true + ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} +## Redis® Pod Disruption Budget configuration +## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +## +pdb: + ## @param pdb.create Specifies whether a PodDisruptionBudget should be created + ## + create: false + ## @param pdb.minAvailable Min number of pods that must still be available after the eviction + ## + minAvailable: 1 + ## @param pdb.maxUnavailable Max number of pods that can be unavailable after the eviction + ## + maxUnavailable: "" +## TLS configuration +## +tls: + ## @param tls.enabled Enable TLS traffic + ## + enabled: false + ## @param tls.authClients Require clients to authenticate + ## + authClients: true + ## @param tls.autoGenerated Enable autogenerated certificates + ## + autoGenerated: false + ## @param tls.existingSecret The name of the existing secret that contains the TLS certificates + ## + existingSecret: "" + ## @param tls.certificatesSecret DEPRECATED. Use existingSecret instead. + ## + certificatesSecret: "" + ## @param tls.certFilename Certificate filename + ## + certFilename: "" + ## @param tls.certKeyFilename Certificate Key filename + ## + certKeyFilename: "" + ## @param tls.certCAFilename CA Certificate filename + ## + certCAFilename: "" + ## @param tls.dhParamsFilename File containing DH params (in order to support DH based ciphers) + ## + dhParamsFilename: "" + +## @section Metrics Parameters +## + +metrics: + ## @param metrics.enabled Start a sidecar prometheus exporter to expose Redis® metrics + ## + enabled: false + ## Bitnami Redis® Exporter image + ## ref: https://hub.docker.com/r/bitnami/redis-exporter/tags/ + ## @param metrics.image.registry Redis® Exporter image registry + ## @param metrics.image.repository Redis® Exporter image repository + ## @param metrics.image.tag Redis® Exporter image tag (immutable tags are recommended) + ## @param metrics.image.digest Redis® Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.image.pullPolicy Redis® Exporter image pull policy + ## @param metrics.image.pullSecrets Redis® Exporter image pull secrets + ## + image: + registry: docker.io + repository: bitnami/redis-exporter + tag: 1.44.0-debian-11-r16 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param metrics.command Override default metrics container init command (useful when using custom images) + ## + command: [] + ## @param metrics.redisTargetHost A way to specify an alternative Redis® hostname + ## Useful for certificate CN/SAN matching + ## + redisTargetHost: "localhost" + ## @param metrics.extraArgs Extra arguments for Redis® exporter, for example: + ## e.g.: + ## extraArgs: + ## check-keys: myKey,myOtherKey + ## + extraArgs: {} + ## @param metrics.extraEnvVars Array with extra environment variables to add to Redis® exporter + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param metrics.containerSecurityContext.enabled Enabled Redis® exporter containers' Security Context + ## @param metrics.containerSecurityContext.runAsUser Set Redis® exporter containers' Security Context runAsUser + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + ## @param metrics.extraVolumes Optionally specify extra list of additional volumes for the Redis® metrics sidecar + ## + extraVolumes: [] + ## @param metrics.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® metrics sidecar + ## + extraVolumeMounts: [] + ## Redis® exporter resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param metrics.resources.limits The resources limits for the Redis® exporter container + ## @param metrics.resources.requests The requested resources for the Redis® exporter container + ## + resources: + limits: {} + requests: {} + ## @param metrics.podLabels Extra labels for Redis® exporter pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param metrics.podAnnotations [object] Annotations for Redis® exporter pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9121" + ## Redis® exporter service parameters + ## + service: + ## @param metrics.service.type Redis® exporter service type + ## + type: ClusterIP + ## @param metrics.service.port Redis® exporter service port + ## + port: 9121 + ## @param metrics.service.externalTrafficPolicy Redis® exporter service external traffic policy + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param metrics.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param metrics.service.loadBalancerIP Redis® exporter service Load Balancer IP + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param metrics.service.loadBalancerSourceRanges Redis® exporter service Load Balancer sources + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## e.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param metrics.service.annotations Additional custom annotations for Redis® exporter service + ## + annotations: {} + ## Prometheus Service Monitor + ## ref: https://github.com/coreos/prometheus-operator + ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator + ## + enabled: false + ## @param metrics.serviceMonitor.namespace The namespace in which the ServiceMonitor will be created + ## + namespace: "" + ## @param metrics.serviceMonitor.interval The interval at which metrics should be scraped + ## + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout The timeout after which the scrape is ended + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.relabellings Metrics RelabelConfigs to apply to samples before scraping. + ## + relabellings: [] + ## @param metrics.serviceMonitor.metricRelabelings Metrics RelabelConfigs to apply to samples before ingestion. + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint + ## + honorLabels: false + ## @param metrics.serviceMonitor.additionalLabels Additional labels that can be used so ServiceMonitor resource(s) can be discovered by Prometheus + ## + additionalLabels: {} + ## @param metrics.serviceMonitor.podTargetLabels Labels from the Kubernetes pod to be transferred to the created metrics + ## + podTargetLabels: [] + ## Custom PrometheusRule to be defined + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + ## @param metrics.prometheusRule.enabled Create a custom prometheusRule Resource for scraping metrics using PrometheusOperator + ## + enabled: false + ## @param metrics.prometheusRule.namespace The namespace in which the prometheusRule will be created + ## + namespace: "" + ## @param metrics.prometheusRule.additionalLabels Additional labels for the prometheusRule + ## + additionalLabels: {} + ## @param metrics.prometheusRule.rules Custom Prometheus rules + ## e.g: + ## rules: + ## - alert: RedisDown + ## expr: redis_up{service="{{ template "common.names.fullname" . }}-metrics"} == 0 + ## for: 2m + ## labels: + ## severity: error + ## annotations: + ## summary: Redis® instance {{ "{{ $labels.instance }}" }} down + ## description: Redis® instance {{ "{{ $labels.instance }}" }} is down + ## - alert: RedisMemoryHigh + ## expr: > + ## redis_memory_used_bytes{service="{{ template "common.names.fullname" . }}-metrics"} * 100 + ## / + ## redis_memory_max_bytes{service="{{ template "common.names.fullname" . }}-metrics"} + ## > 90 + ## for: 2m + ## labels: + ## severity: error + ## annotations: + ## summary: Redis® instance {{ "{{ $labels.instance }}" }} is using too much memory + ## description: | + ## Redis® instance {{ "{{ $labels.instance }}" }} is using {{ "{{ $value }}" }}% of its available memory. + ## - alert: RedisKeyEviction + ## expr: | + ## increase(redis_evicted_keys_total{service="{{ template "common.names.fullname" . }}-metrics"}[5m]) > 0 + ## for: 1s + ## labels: + ## severity: error + ## annotations: + ## summary: Redis® instance {{ "{{ $labels.instance }}" }} has evicted keys + ## description: | + ## Redis® instance {{ "{{ $labels.instance }}" }} has evicted {{ "{{ $value }}" }} keys in the last 5 minutes. + ## + rules: [] + +## @section Init Container Parameters +## + +## 'volumePermissions' init container parameters +## Changes the owner and group of the persistent volume mount point to runAsUser:fsGroup values +## based on the *podSecurityContext/*containerSecurityContext parameters +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` + ## + enabled: false + ## Bitnami Shell image + ## ref: https://hub.docker.com/r/bitnami/bitnami-shell/tags/ + ## @param volumePermissions.image.registry Bitnami Shell image registry + ## @param volumePermissions.image.repository Bitnami Shell image repository + ## @param volumePermissions.image.tag Bitnami Shell image tag (immutable tags are recommended) + ## @param volumePermissions.image.digest Bitnami Shell image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param volumePermissions.image.pullPolicy Bitnami Shell image pull policy + ## @param volumePermissions.image.pullSecrets Bitnami Shell image pull secrets + ## + image: + registry: docker.io + repository: bitnami/bitnami-shell + tag: 11-debian-11-r40 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Init container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param volumePermissions.resources.limits The resources limits for the init container + ## @param volumePermissions.resources.requests The requested resources for the init container + ## + resources: + limits: {} + requests: {} + ## Init container Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param volumePermissions.containerSecurityContext.runAsUser Set init container's Security Context runAsUser + ## NOTE: when runAsUser is set to special value "auto", init container will try to chown the + ## data folder to auto-determined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic user ids (and 0 is not allowed) + ## + containerSecurityContext: + runAsUser: 0 + +## init-sysctl container parameters +## used to perform sysctl operation to modify Kernel settings (needed sometimes to avoid warnings) +## +sysctl: + ## @param sysctl.enabled Enable init container to modify Kernel settings + ## + enabled: false + ## Bitnami Shell image + ## ref: https://hub.docker.com/r/bitnami/bitnami-shell/tags/ + ## @param sysctl.image.registry Bitnami Shell image registry + ## @param sysctl.image.repository Bitnami Shell image repository + ## @param sysctl.image.tag Bitnami Shell image tag (immutable tags are recommended) + ## @param sysctl.image.digest Bitnami Shell image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param sysctl.image.pullPolicy Bitnami Shell image pull policy + ## @param sysctl.image.pullSecrets Bitnami Shell image pull secrets + ## + image: + registry: docker.io + repository: bitnami/bitnami-shell + tag: 11-debian-11-r40 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param sysctl.command Override default init-sysctl container command (useful when using custom images) + ## + command: [] + ## @param sysctl.mountHostSys Mount the host `/sys` folder to `/host-sys` + ## + mountHostSys: false + ## Init container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param sysctl.resources.limits The resources limits for the init container + ## @param sysctl.resources.requests The requested resources for the init container + ## + resources: + limits: {} + requests: {} + +## @section useExternalDNS Parameters +## +## @param useExternalDNS.enabled Enable various syntax that would enable external-dns to work. Note this requires a working installation of `external-dns` to be usable. +## @param useExternalDNS.additionalAnnotations Extra annotations to be utilized when `external-dns` is enabled. +## @param useExternalDNS.annotationKey The annotation key utilized when `external-dns` is enabled. Setting this to `false` will disable annotations. +## @param useExternalDNS.suffix The DNS suffix utilized when `external-dns` is enabled. Note that we prepend the suffix with the full name of the release. +## +useExternalDNS: + enabled: false + suffix: "" + annotationKey: external-dns.alpha.kubernetes.io/ + additionalAnnotations: {} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/stateful-resources/vault-crs.yaml.tpl b/terraform/foundation-install/generate-files/templates/stateful-resources/vault-crs.yaml.tpl new file mode 100644 index 000000000..3e30cb3f3 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/stateful-resources/vault-crs.yaml.tpl @@ -0,0 +1,75 @@ +%{ if resource.generate_secret_name != null ~} +apiVersion: redhatcop.redhat.io/v1alpha1 +kind: PasswordPolicy +metadata: + name: ${resource.resource_type}-policy + namespace: ${resource.resource_namespace} +spec: + # Add fields here + authentication: + path: kubernetes + role: policy-admin + serviceAccount: + name: default + passwordPolicy: | + length = 20 + rule "charset" { + charset = "abcdefghijklmnopqrstuvwxyz" + min-chars = 1 + } + rule "charset" { + charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + min-chars = 1 + } + rule "charset" { + charset = "0123456789" + min-chars = 1 + } + rule "charset" { + charset = "!@#$%^&*" + min-chars = 1 + } +--- +%{ for key in resource.generate_secret_keys ~} +apiVersion: redhatcop.redhat.io/v1alpha1 +kind: RandomSecret +metadata: + name: ${resource.generate_secret_name}-${key} + namespace: ${resource.resource_namespace} +spec: + authentication: + path: kubernetes + role: policy-admin + serviceAccount: + name: default + isKVSecretsEngineV2: false + path: ${resource.generate_secret_vault_base_path}/${resource.resource_name} + secretKey: ${key} + secretFormat: + passwordPolicyName: ${resource.resource_type}-policy + refreshPeriod: 1h +--- +%{ endfor ~} +apiVersion: redhatcop.redhat.io/v1alpha1 +kind: VaultSecret +metadata: + name: ${resource.generate_secret_name} + namespace: ${resource.resource_namespace} +spec: + refreshThreshold: 85 # after 85% of the lease_duration of the dynamic secret has elapsed, refresh the secret + vaultSecretDefinitions: + - authentication: + path: kubernetes + role: policy-admin + serviceAccount: + name: default + name: dynamicsecret + path: ${resource.generate_secret_vault_base_path}/${resource.resource_name} + output: + name: ${resource.generate_secret_name} + stringData: +%{ for key in resource.generate_secret_keys ~} + ${key}: '{{ .dynamicsecret.${key} }}' +%{ endfor ~} + type: Opaque +%{ endif ~} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/storage/app/storage-app.yaml.tpl b/terraform/foundation-install/generate-files/templates/storage/app/storage-app.yaml.tpl new file mode 100644 index 000000000..653048bb8 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/storage/app/storage-app.yaml.tpl @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-10" + name: storage-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: apps/storage + repoURL: "${gitlab_project_url}" + targetRevision: HEAD + plugin: + name: argocd-lovely-plugin + destination: + namespace: ${longhorn_namespace} + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/storage/chart/Chart.yaml.tpl b/terraform/foundation-install/generate-files/templates/storage/chart/Chart.yaml.tpl new file mode 100644 index 000000000..1799faef4 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/storage/chart/Chart.yaml.tpl @@ -0,0 +1,7 @@ +apiVersion: v2 +version: 1.0.0 +name: longhorn +dependencies: +- name: longhorn + version: ${longhorn_chart_version} + repository: ${longhorn_chart_repo} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/storage/chart/values.yaml.tpl b/terraform/foundation-install/generate-files/templates/storage/chart/values.yaml.tpl new file mode 100644 index 000000000..e97f9afbc --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/storage/chart/values.yaml.tpl @@ -0,0 +1,21 @@ +longhorn: + persistence: + defaultClass: true + # Set the number of replicas based on how many nodes are deployed; https://longhorn.io/docs/0.8.1/references/settings/#default-replica-count + defaultClassReplicaCount: ${replica_count} + reclaimPolicy: ${reclaim_policy} + + defaultSettings: + backupTarget: "s3://${longhorn_backups_bucket_name}@${cloud_region}/" + backupTargetCredentialSecret: ${longhorn_credentials_secret} + nodeDownPodDeletionPolicy: delete-both-statefulset-and-deployment-pod + defaultDataLocality: disabled + replicaAutoBalance: disabled + autoDeletePodWhenVolumeDetachedUnexpectedly: true + replicaReplenishmentWaitInterval: 360 + + enablePSP: false + %{ if k8s_cluster_type == "microk8s" ~} + csi: + kubeletRootDir: /var/snap/microk8s/common/var/lib/kubelet + %{ endif ~} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/storage/custom-resources/longhorn-job.yaml.tpl b/terraform/foundation-install/generate-files/templates/storage/custom-resources/longhorn-job.yaml.tpl new file mode 100644 index 000000000..3e402c45b --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/storage/custom-resources/longhorn-job.yaml.tpl @@ -0,0 +1,13 @@ +apiVersion: longhorn.io/v1beta1 +kind: RecurringJob +metadata: + name: backup-1 + annotations: + argocd.argoproj.io/sync-wave: "${longhorn_job_sync_wave}" +spec: + cron: "0 * * * *" + task: "backup" + groups: + - default + retain: 2 + concurrency: 2 \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/storage/external-secrets/longhorn-extsecret.yaml.tpl b/terraform/foundation-install/generate-files/templates/storage/external-secrets/longhorn-extsecret.yaml.tpl new file mode 100644 index 000000000..029bdf85a --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/storage/external-secrets/longhorn-extsecret.yaml.tpl @@ -0,0 +1,24 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "${external_secret_sync_wave}" + name: ${longhorn_credentials_secret} +spec: + refreshInterval: 1h + + secretStoreRef: + kind: ClusterSecretStore + name: gitlab-secret-store + + target: + name: ${longhorn_credentials_secret} # Name for the secret to be created on the cluster + creationPolicy: Owner + + data: + - secretKey: AWS_SECRET_ACCESS_KEY # Key given to the secret to be created on the cluster + remoteRef: + key: ${gitlab_key_longhorn_backups_secret_key} + - secretKey: AWS_ACCESS_KEY_ID # Key given to the secret to be created on the cluster + remoteRef: + key: ${gitlab_key_longhorn_backups_access_key} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/app/vault-app.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/app/vault-app.yaml.tpl new file mode 100644 index 000000000..0fa83a959 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/app/vault-app.yaml.tpl @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-5" + name: vault-app + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + source: + path: apps/vault + repoURL: "${gitlab_project_url}" + targetRevision: HEAD + destination: + namespace: ${vault_namespace} + server: https://kubernetes.default.svc + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: true + retry: + limit: 5 + backoff: + duration: 5s + maxDuration: 3m0s + factor: 2 + syncOptions: + - CreateNamespace=true + - PrunePropagationPolicy=background + - PruneLast=true \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/Chart.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/Chart.yaml.tpl new file mode 100644 index 000000000..18a59a4c0 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/Chart.yaml.tpl @@ -0,0 +1,7 @@ +apiVersion: v2 +version: 1.0.0 +name: vault-config-operator +dependencies: +- name: vault-config-operator + version: ${vault_config_operator_helm_chart_version} + repository: ${vault_config_operator_helm_chart_repo} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/values.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/values.yaml.tpl new file mode 100644 index 000000000..9f2ac9c5e --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/charts/vault-config-operator/values.yaml.tpl @@ -0,0 +1,50 @@ +vault-config-operator: + # Default values for helm-try. + # This is a YAML-formatted file. + # Declare variables to be passed into your templates. + + replicaCount: 1 + + image: + repository: quay.io/redhat-cop/vault-config-operator + pullPolicy: IfNotPresent + + + imagePullSecrets: [] + nameOverride: "" + fullnameOverride: "" + env: + - name: VAULT_ADDR + value: http://vault.${vault_namespace}.svc.cluster.local:8200 + - name: VAULT_SKIP_VERIFY + value: "true" + args: [] + volumes: [] + volumeMounts: [] + podAnnotations: {} + + resources: + requests: + cpu: 100m + memory: 250Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + + kube_rbac_proxy: + image: + repository: quay.io/redhat-cop/kube-rbac-proxy + pullPolicy: IfNotPresent + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + + enableMonitoring: false + enableCertManager: true \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/charts/vault/Chart.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/charts/vault/Chart.yaml.tpl new file mode 100644 index 000000000..68afeb4b8 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/charts/vault/Chart.yaml.tpl @@ -0,0 +1,7 @@ +apiVersion: v2 +version: 1.0.0 +name: vault +dependencies: +- name: vault + version: ${vault_chart_version} + repository: ${vault_chart_repo} \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/charts/vault/values.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/charts/vault/values.yaml.tpl new file mode 100644 index 000000000..6f56a2f7c --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/charts/vault/values.yaml.tpl @@ -0,0 +1,89 @@ +vault: + server: + enabled: true + dev: + enabled: false + extraVolumes: + - type: configMap + name: post-config + readinessProbe: + path: "/v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204" + extraSecretEnvironmentVars: + - envName: AWS_ACCESS_KEY_ID + secretName: ${vault_seal_credentials_secret} + secretKey: AWS_ACCESS_KEY_ID + - envName: AWS_SECRET_ACCESS_KEY + secretName: ${vault_seal_credentials_secret} + secretKey: AWS_SECRET_ACCESS_KEY + ha: + enabled: true + config: | + ui = true + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + } + storage "consul" { + path = "vault" + address = "consul-server.${consul_namespace}.svc.cluster.local:8500" + } + service_registration "kubernetes" {} + + seal "awskms" { + region = "${cloud_region}" + kms_key_id = "${vault_kms_seal_kms_key_id}" + } + + extraContainers: + - name: statsd-exporter + image: prom/statsd-exporter:latest + - name: init-sidecar + image: ghcr.io/mojaloop/vault-utils:0.0.4 + command: ["sh","-c","cp /etc/vault/bootstrap.sh /tmp; chmod +x /tmp/bootstrap.sh; while true; do /tmp/bootstrap.sh; sleep 300; done"] + volumeMounts: + - name: userconfig-post-config + mountPath: /etc/vault/ + env: + - name: GITLAB_URL + value: ${gitlab_variables_api_url} + - name: GITLAB_TOKEN + valueFrom: + secretKeyRef: + name: ${vault_gitlab_credentials_secret} + key: GITLAB_TOKEN + + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: class + operator: NotIn + values: + - vault + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app: vault + ingress: + enabled: true + ingressClassName: ${ingress_class} + hosts: + - host: vault.${public_subdomain} + tls: + - hosts: + - "*.${public_subdomain}" + + ui: + enabled: true + injector: + enabled: true + authPath: ${vault_k8s_auth_path} + csi: + enabled: false \ No newline at end of file diff --git a/terraform/foundation-install/generate-files/templates/vault/post-config.yaml.tpl b/terraform/foundation-install/generate-files/templates/vault/post-config.yaml.tpl new file mode 100644 index 000000000..662bc15c1 --- /dev/null +++ b/terraform/foundation-install/generate-files/templates/vault/post-config.yaml.tpl @@ -0,0 +1,100 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: post-config + annotations: + argocd.argoproj.io/sync-wave: "${vault_cm_sync_wave}" +data: + bootstrap.sh: | + #!/bin/bash + set -e + export VAULT_ADDR=http://127.0.0.1:8200 + export VAULT_SKIP_VERIFY=true + export NUM_KEYS=5 + if [ $(vault status -format=json | jq .initialized) == "false" ] + then + vault operator init -format=json > /tmp/output.json + export VAULT_ROOT_TOKEN=$(cat /tmp/output.json | jq .root_token | tr -d '"') + if [ $VAULT_ROOT_TOKEN != "" ] + then + export VAULT_ROOT_TOKEN_FOUND=$(curl -sw '%%{http_code}' --request GET "$${GITLAB_URL}/VAULT_ROOT_TOKEN" --header "Authorization: Bearer $GITLAB_TOKEN" -o /dev/null) + if [ $VAULT_ROOT_TOKEN_FOUND == "404" ] + then + curl -s --request POST "$GITLAB_URL" --header "Authorization: Bearer $GITLAB_TOKEN" --form "key=VAULT_ROOT_TOKEN" --form "value=$VAULT_ROOT_TOKEN" --form "raw=true" --form "masked=true" -o /dev/null + else + echo "vault root token already present, updating code" + curl -s --request PUT "$${GITLAB_URL}/VAULT_ROOT_TOKEN" --header "Authorization: Bearer $GITLAB_TOKEN" --form "value=$VAULT_ROOT_TOKEN" -o /dev/null + fi + else + echo "VAULT_ROOT_TOKEN not parsed correctly, exiting" + exit 1 + fi + for ((i=0; i<=NUM_KEYS; i++)) + do + export RECOVERY_KEY=$(cat /tmp/output.json | jq .recovery_keys_b64[$i] | tr -d '"') + export RECOVERY_CODE_FOUND=$(curl -sw '%%{http_code}' --request GET "$${GITLAB_URL}/RECOVERY_KEY_$i" --header "Authorization: Bearer $GITLAB_TOKEN" -o /dev/null) + if [ $RECOVERY_CODE_FOUND == "404" ] + then + curl -s --request POST "$GITLAB_URL" --header "Authorization: Bearer $GITLAB_TOKEN" --form "key=RECOVERY_KEY_$i" --form "value=$RECOVERY_KEY" --form "raw=true" --form "masked=true" -o /dev/null + else + echo "recovery code already present, updating code" + curl -s --request PUT "$${GITLAB_URL}/RECOVERY_KEY_$i" --header "Authorization: Bearer $GITLAB_TOKEN" --form "value=$RECOVERY_KEY" -o /dev/null + fi + done + if [ $VAULT_ROOT_TOKEN != "" ] + then + vault login -no-print $VAULT_ROOT_TOKEN + cat </tmp/vault-admin-policy.hcl + path "/*" { + capabilities = ["create", "read", "update", "delete", "list", "sudo"] + } + EOT + cat </tmp/vault-read-secrets-policy.hcl + path "secret/*" { + capabilities = ["read", "list"] + } + EOT + vault policy write vault-admin /tmp/vault-admin-policy.hcl + vault policy write read-secrets /tmp/vault-read-secrets-policy.hcl + vault auth enable kubernetes + vault write auth/kubernetes/config kubernetes_host=https://kubernetes.default.svc:443 + vault write auth/kubernetes/role/policy-admin bound_service_account_names=controller-manager,default bound_service_account_namespaces=vault-config-operator,default policies=vault-admin ttl=600s + vault secrets enable --path=secret kv + vault secrets tune -default-lease-ttl=2m secret/ + %{ if enable_vault_oidc ~} + vault auth enable oidc + vault write auth/oidc/config \ + oidc_discovery_url="${gitlab_server_url}" \ + oidc_client_id="${vault_oauth_client_id}" \ + oidc_client_secret="${vault_oauth_client_secret}" \ + default_role="techops-admin" + vault write auth/oidc/role/techops-admin -< stateful_resource if stateful_resource.local_resource != null } + + content = templatefile("${local.stateful_resources_template_path}/${each.value.local_resource.resource_helm_values_ref}", { + resource = each.value + }) + filename = "${local.stateful_resources_output_path}/values-${each.value.local_resource.resource_helm_chart}-${each.value.resource_name}.yaml" +} + +resource "local_file" "vault_crs" { + for_each = { for stateful_resource in local.enabled_stateful_resources : stateful_resource.resource_name => stateful_resource if stateful_resource.local_resource != null } + + content = templatefile("${local.stateful_resources_template_path}/vault-crs.yaml.tpl", { + resource = each.value + }) + filename = "${local.stateful_resources_output_path}/vault-crs-${each.value.local_resource.resource_helm_chart}-${each.value.resource_name}.yaml" +} + +resource "local_file" "external_name_services" { + content = templatefile("${local.stateful_resources_template_path}/external-name-services.yaml.tpl", { config = local.local_external_name_map }) + filename = "${local.stateful_resources_output_path}/external-name-services.yaml" +} + +resource "local_file" "kustomization" { + content = templatefile("${local.stateful_resources_template_path}/stateful-resources-kustomization.yaml.tpl", + { stateful_resources = local.enabled_stateful_resources + stateful_resources_namespace = var.stateful_resources_namespace + }) + filename = "${local.stateful_resources_output_path}/kustomization.yaml" +} + +resource "local_file" "stateful-resources-app-file" { + content = templatefile("${local.stateful_resources_template_path}/app/${local.stateful_resources_app_file}.tpl", local.stateful_resources_vars) + filename = "${local.app_stateful_resources_output_path}/${local.stateful_resources_app_file}" +} + +locals { + stateful_resources_template_path = "${path.module}/generate-files/templates/stateful-resources" + stateful_resources_output_path = "${var.output_dir}/stateful-resources" + stateful_resources_app_file = "stateful-resources-app.yaml" + app_stateful_resources_output_path = "${var.output_dir}/app-yamls" + stateful_resources = jsondecode(file(var.stateful_resources_config_file)) + enabled_stateful_resources = { for stateful_resource in local.stateful_resources : stateful_resource.resource_name => stateful_resource if stateful_resource.enabled } + local_external_name_map = { for stateful_resource in local.enabled_stateful_resources : stateful_resource.logical_service_name => stateful_resource.local_resource != null ? (stateful_resource.local_resource.override_service_name != null ? "${stateful_resource.local_resource.override_service_name}.${stateful_resource.resource_namespace}.svc.cluster.local" : "${stateful_resource.resource_name}.${stateful_resource.resource_namespace}.svc.cluster.local") : stateful_resource.external_service.external_endpoint } + stateful_resources_vars = { + stateful_resources_namespace = var.stateful_resources_namespace + gitops_project_path_prefix = var.gitops_project_path_prefix + gitlab_project_url = var.gitlab_project_url + } +} diff --git a/terraform/foundation-install/storage-config.tf b/terraform/foundation-install/storage-config.tf new file mode 100644 index 000000000..4e595823a --- /dev/null +++ b/terraform/foundation-install/storage-config.tf @@ -0,0 +1,25 @@ +module "generate_storage_files" { + source = "./generate-files" + var_map = { + longhorn_chart_repo = var.longhorn_chart_repo + longhorn_chart_version = var.longhorn_chart_version + longhorn_credentials_secret = var.longhorn_credentials_secret + cloud_region = local.cloud_region + longhorn_backups_bucket_name = var.longhorn_backups_bucket_name + k8s_cluster_type = local.k8s_cluster_type + reclaim_policy = var.longhorn_reclaim_policy + replica_count = var.longhorn_replica_count + gitlab_key_longhorn_backups_access_key = var.gitlab_key_longhorn_backups_access_key + gitlab_key_longhorn_backups_secret_key = var.gitlab_key_longhorn_backups_secret_key + gitops_project_path_prefix = var.gitops_project_path_prefix + gitlab_project_url = var.gitlab_project_url + longhorn_namespace = var.longhorn_namespace + external_secret_sync_wave = var.external_secret_sync_wave + longhorn_job_sync_wave = var.longhorn_job_sync_wave + } + file_list = ["chart/Chart.yaml", "chart/values.yaml", "external-secrets/longhorn-extsecret.yaml", "custom-resources/longhorn-job.yaml"] + template_path = "${path.module}/generate-files/templates/storage" + output_path = "${var.output_dir}/storage" + app_file = "storage-app.yaml" + app_output_path = "${var.output_dir}/app-yamls" +} diff --git a/terraform/foundation-install/variables.tf b/terraform/foundation-install/variables.tf new file mode 100644 index 000000000..7799834d2 --- /dev/null +++ b/terraform/foundation-install/variables.tf @@ -0,0 +1,457 @@ +variable "cluster_name" { + description = "Cluster name, lower case and without spaces. This will be used to set tags and name resources" + type = string +} + +variable "output_dir" { + default = "../apps" + type = string + description = "where to output files" +} + +variable "gitlab_server_url" { + type = string + description = "gitlab_server_url" +} + +variable "vault_oauth_client_id" { + type = string + default = "" + description = "vault_oauth_client_id" +} + +variable "vault_oauth_client_secret" { + type = string + default = "" + description = "vault_oauth_client_secret" + sensitive = true +} + +variable "gitlab_project_url" { + type = string + description = "gitlab_project_url" +} + +variable "stateful_resources_config_file" { + default = "../config/stateful-resources.json" + type = string + description = "where to pull stateful resources config" +} + +variable "stateful_resources_namespace" { + type = string + description = "stateful_resources_namespace" + default = "stateful_resources" +} + +variable "nat_public_ips" { + type = string + description = "nat_public_ips" +} +variable "internal_load_balancer_dns" { + type = string + description = "internal_load_balancer_dns" +} +variable "external_load_balancer_dns" { + type = string + description = "external_load_balancer_dns" +} +variable "private_subdomain" { + type = string + description = "private_subdomain" +} +variable "public_subdomain" { + type = string + description = "public_subdomain" +} + +variable "current_gitlab_project_id" { + type = string + description = "current_gitlab_project_id" +} + +variable "gitlab_group_name" { + type = string + description = "gitlab_group_name" +} + +variable "gitlab_api_url" { + type = string + description = "gitlab_api_url" +} + +variable "gitops_project_path_prefix" { + type = string + description = "gitops_project_path_prefix" + default = "infra" +} + +## certmanager + +variable "cert_manager_chart_repo" { + type = string + description = "cert_manager_chart_repo" + default = "https://charts.jetstack.io" +} +variable "cert_manager_chart_version" { + type = string + description = "1.11.0" +} + +variable "cert_manager_namespace" { + type = string + description = "cert_manager_namespace" + default = "certmanager" +} + +variable "cert_manager_credentials_secret" { + type = string + description = "cert_manager_credentials_secret" + default = "route53-cert-man-credentials" +} + +variable "cert_manager_issuer_sync_wave" { + type = string + description = "cert_manager_issuer_sync_wave" + default = "-7" +} + +variable "letsencrypt_server" { + type = string + description = "letsencrypt_server" + default = "https://acme-v02.api.letsencrypt.org/directory" +} + +variable "letsencrypt_email" { + type = string + description = "letsencrypt_email" + default = "cicd@example.com" +} + +## external secrets +variable "external_secret_sync_wave" { + type = string + description = "external_secret_sync_wave" + default = "-11" +} + +##consul + +variable "consul_chart_repo" { + type = string + description = "consul_chart_repo" + default = "https://helm.releases.hashicorp.com" +} + +variable "consul_chart_version" { + type = string + description = "consul_chart_version" + default = "1.0.3" +} + +variable "consul_replicas" { + type = string + description = "consul_replicas" + default = "1" +} + +variable "consul_storage_size" { + type = string + description = "storage_size" + default = "3Gi" +} + +variable "consul_namespace" { + type = string + description = "consul_namespace" + default = "consul" +} + +##longhorn/storage + +variable "longhorn_chart_repo" { + type = string + description = "longhorn_chart_repo" + default = "https://charts.longhorn.io" +} + +variable "longhorn_chart_version" { + type = string + description = "longhorn_chart_version" + default = "1.4.0" +} + +variable "longhorn_credentials_secret" { + type = string + description = "longhorn_credentials_secret" + default = "longhorn-s3-credentials" +} + +variable "longhorn_backups_bucket_name" { + type = string + description = "longhorn_backups_bucket_name" +} + +variable "longhorn_reclaim_policy" { + type = string + description = "longhorn_reclaim_policy" + default = "Retain" +} + +variable "longhorn_replica_count" { + type = string + description = "longhorn_replica_count" + default = "1" +} + +variable "longhorn_namespace" { + type = string + description = "longhorn_namespace" + default = "longhorn-system" +} + +variable "gitlab_key_longhorn_backups_access_key" { + type = string + description = "gitlab_key_longhorn_backups_access_key" +} + +variable "gitlab_key_longhorn_backups_secret_key" { + type = string + description = "gitlab_key_longhorn_backups_secret_key" +} + +variable "longhorn_job_sync_wave" { + type = string + description = "longhorn_job_sync_wave" + default = "-9" +} + +variable "storage_class_name" { + type = string + description = "storage_class_name" + default = "longhorn" +} + + +## external-dns + +variable "external_dns_credentials_secret" { + type = string + description = "external_dns_credentials_secret" + default = "route53-external-dns-credentials" +} + +variable "gitlab_key_route53_external_dns_access_key" { + type = string + description = "gitlab_key_route53_external_dns_access_key" +} + +variable "gitlab_key_route53_external_dns_secret_key" { + type = string + description = "gitlab_key_route53_external_dns_secret_key" +} + +variable "external_dns_chart_repo" { + type = string + description = "external_dns_chart_repo" + default = "https://charts.bitnami.com/bitnami" +} + +variable "external_dns_chart_version" { + type = string + description = "external_dns_chart_version" + default = "6.7.2" +} + +variable "external_dns_namespace" { + type = string + description = "external_dns_namespace" + default = "external-dns" +} + +variable "dns_cloud_region" { + type = string + description = "cloud region for ext dns" +} +## vault + +variable "vault_sync_wave" { + type = string + description = "vault_sync_wave" + default = "-5" +} + +variable "vault_namespace" { + type = string + description = "vault_namespace" + default = "vault" +} + +variable "vault_config_operator_namespace" { + type = string + description = "vault_config_operator_namespace" + default = "vault-config" +} + +variable "vault_config_operator_sync_wave" { + type = string + description = "vault_sync_wave" + default = "-5" +} + +variable "vault_cm_sync_wave" { + type = string + description = "vault_sync_wave" + default = "-6" +} + +variable "vault_chart_repo" { + type = string + description = "vault_chart_repo" + default = "https://helm.releases.hashicorp.com" +} +variable "vault_chart_version" { + type = string + description = "vault_chart_version" + default = "0.23.0" +} +variable "vault_config_operator_helm_chart_repo" { + type = string + description = "vault_config_operator_helm_chart_repo" + default = "https://redhat-cop.github.io/vault-config-operator" +} +variable "vault_config_operator_helm_chart_version" { + type = string + description = "vault_config_operator_helm_chart_version" + default = "0.8.9" +} +variable "gitlab_key_vault_iam_user_access_key" { + type = string + description = "gitlab_key_vault_iam_user_access_key" +} +variable "gitlab_key_vault_iam_user_secret_key" { + type = string + description = "gitlab_key_vault_iam_user_secret_key" +} +variable "vault_kms_seal_kms_key_id" { + type = string + description = "vault_kms_seal_kms_key_id" +} + +variable "vault_gitlab_credentials_secret" { + type = string + description = "vault_gitlab_credentials_secret" + default = "vault-gitlab-credentials-secret" +} + +variable "vault_seal_credentials_secret" { + type = string + description = "vault_seal_credentials_secret" + default = "vault-seal-credentials-secret" +} + +variable "vault_ingress_internal_lb" { + type = bool + description = "vault_ingress_class" + default = true +} +variable "vault_k8s_auth_path" { + type = string + description = "vault_k8s_auth_path" + default = "auth/kubernetes" +} + +variable "enable_vault_oidc" { + type = bool + default = false +} + +variable "gitlab_readonly_group_name" { + type = string + description = "gitlab_readonly_group_name" +} + +variable "gitlab_admin_group_name" { + type = string + description = "gitlab_admin_group_name" +} + +## nginx + + +variable "nginx_helm_chart_repo" { + type = string + description = "nginx_helm_chart_repo" + default = "https://kubernetes.github.io/ingress-nginx" +} +variable "nginx_helm_chart_version" { + type = string + description = "nginx_helm_chart_version" + default = "4.3.0" +} +variable "nginx_external_namespace" { + type = string + description = "nginx_external_namespace" + default = "nginx-ext" +} +variable "nginx_internal_namespace" { + type = string + description = "nginx_internal_namespace" + default = "nginx-int" +} +variable "ingress_sync_wave" { + type = string + description = "nginx_internal_namespace" + default = "nginx-int" +} +variable "default_ssl_certificate" { + type = string + description = "nginx_internal_namespace" + default = "nginx-int" +} +variable "wildcare_certificate_wave" { + type = string + description = "nginx_internal_namespace" + default = "nginx-int" +} +variable "internal_ingress_class_name" { + type = string + description = "nginx_internal_namespace" + default = "nginx-int" +} +variable "external_ingress_class_name" { + type = string + description = "external_ingress_class_name" + default = "nginx-ext" +} +variable "internal_ingress_https_port" { + type = number + description = "internal_ingress_https_port" + default = 31443 +} +variable "internal_ingress_http_port" { + type = number + description = "internal_ingress_http_port" + default = 31080 +} +variable "external_ingress_https_port" { + type = number + description = "external_ingress_https_port" + default = 32443 +} +variable "external_ingress_http_port" { + type = number + description = "external_ingress_http_port" + default = 32080 +} + +variable "gitlab_key_gitlab_ci_pat" { + type = string + description = "gitlab_key_gitlab_ci_pat" +} + +locals { + cloud_region = data.gitlab_project_variable.cloud_region.value + k8s_cluster_type = data.gitlab_project_variable.k8s_cluster_type.value + cloud_platform = data.gitlab_project_variable.cloud_platform.value +} diff --git a/terraform/foundation-install/vault.tf b/terraform/foundation-install/vault.tf new file mode 100644 index 000000000..8caa86239 --- /dev/null +++ b/terraform/foundation-install/vault.tf @@ -0,0 +1,43 @@ +module "generate_vault_files" { + source = "./generate-files" + var_map = { + gitops_project_path_prefix = var.gitops_project_path_prefix + vault_chart_repo = var.vault_chart_repo + vault_namespace = var.vault_namespace + vault_config_operator_namespace = var.vault_config_operator_namespace + vault_chart_version = var.vault_chart_version + vault_sync_wave = var.vault_sync_wave + vault_cm_sync_wave = var.vault_cm_sync_wave + vault_config_operator_sync_wave = var.vault_config_operator_sync_wave + external_secret_sync_wave = var.external_secret_sync_wave + vault_config_operator_helm_chart_repo = var.vault_config_operator_helm_chart_repo + vault_config_operator_helm_chart_version = var.vault_config_operator_helm_chart_version + gitlab_variables_api_url = "${var.gitlab_api_url}/projects/${var.current_gitlab_project_id}/variables" + gitlab_project_url = var.gitlab_project_url + vault_kms_seal_kms_key_id = var.vault_kms_seal_kms_key_id + gitlab_key_vault_iam_user_secret_key = var.gitlab_key_vault_iam_user_secret_key + gitlab_key_vault_iam_user_access_key = var.gitlab_key_vault_iam_user_access_key + vault_seal_credentials_secret = var.vault_seal_credentials_secret + vault_gitlab_credentials_secret = var.vault_gitlab_credentials_secret + cloud_region = local.cloud_region + vault_k8s_auth_path = var.vault_k8s_auth_path + public_subdomain = var.public_subdomain + ingress_class = var.vault_ingress_internal_lb ? var.internal_ingress_class_name : var.external_ingress_class_name + consul_namespace = var.consul_namespace + gitlab_key_gitlab_ci_pat = var.gitlab_key_gitlab_ci_pat + gitlab_server_url = var.gitlab_server_url + gitlab_admin_group_name = var.gitlab_admin_group_name + gitlab_readonly_group_name = var.gitlab_readonly_group_name + vault_oauth_client_secret = var.vault_oauth_client_secret + vault_oauth_client_id = var.vault_oauth_client_id + enable_vault_oidc = var.enable_vault_oidc + } + + file_list = ["charts/vault/Chart.yaml", "charts/vault/values.yaml", + "charts/vault-config-operator/Chart.yaml", "charts/vault-config-operator/values.yaml", + "post-config.yaml", "vault-config-operator.yaml", "vault-extsecret.yaml", "vault-helm.yaml"] + template_path = "${path.module}/generate-files/templates/vault" + output_path = "${var.output_dir}/vault" + app_file = "vault-app.yaml" + app_output_path = "${var.output_dir}/app-yamls" +} \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/bootstrap/.gitlab-ci.yml b/terraform/gitlab/ci-templates/bootstrap/.gitlab-ci.yml new file mode 100644 index 000000000..b07e27358 --- /dev/null +++ b/terraform/gitlab/ci-templates/bootstrap/.gitlab-ci.yml @@ -0,0 +1,149 @@ +include: + - template: Terraform/Base.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml +workflow: + rules: + - if: $CI_MERGE_REQUEST_IID + changes: + - .gitlab/ci/Dockerfile + variables: + IMAGE_TAG: ${CI_COMMIT_REF_SLUG} + - when: always + # Apparently including the merged workflow rules in addition to the custom rule above doesn't work. + # This comes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml + - if: $CI_MERGE_REQUEST_IID + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +stages: + - prepare + - lint + - init + - validate + - build + - deploy + - deploy-env-templates + - cleanup + +variables: + IMAGE_TAG: latest + TF_STATE_BASE_ADDRESS: $CI_API_V4_URL/projects/$CI_PROJECT_ID/terraform/state + TEMPLATE_REPO_URL: https://github.com/mojaloop/iac-modules.git + CI_TEMPLATE_PATH: terraform/gitlab/ci-templates/k8s-cluster + K8S_TEMPLATE_PATH: terraform/k8s + TMP_TEMPLATES_DIR: /tmp/iac-templates + ANSIBLE_BASE_OUTPUT_DIR: $TF_ROOT/ansible + +image: ${CI_REGISTRY_IMAGE}:${IMAGE_TAG} + +cache: + key: "${TF_ROOT}" + paths: + - ${TF_ROOT}/**/.terraform + - ${TF_ROOT}/**/.terraform.lock.hcl + - ${TF_ROOT}/**/.terragrunt-cache + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/inventory + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/sshkey + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/keylist.json + +.source: + script: + - source $(which gitlab-terraform) + - source setcivars.sh + - yq eval '.' environment.yaml -o=json > environment.json + - for var in $(jq -r 'to_entries[] | "\(.key)=\(.value)\n"' ./environment.json); do export $var; done + - echo "https://${PRIVATE_REPO_USER}:${PRIVATE_REPO_TOKEN}@github.com" > ~/.gitcredentials.store + - git config --global credential.helper 'store --file ~/.gitcredentials.store' + - git config --global advice.detachedHead false + - set + - git clone ${TEMPLATE_REPO_URL} template-repo + - cd template-repo && git checkout ${IAC_TEMPLATES_TAG} + - mkdir -p $TMP_TEMPLATES_DIR + - cp -r ${CI_TEMPLATE_PATH}/. ${K8S_TEMPLATE_PATH}/. $TMP_TEMPLATES_DIR + - ls -la ${TMP_TEMPLATES_DIR}/ && cd - && rm -rf template-repo + +prepare:image: + needs: [] + stage: prepare + image: + name: gcr.io/kaniko-project/executor:v1.9.0-debug + entrypoint: [""] + rules: + # Tag with the commit SHA if we're in an MR + - if: $CI_MERGE_REQUEST_IID + changes: + - .gitlab/ci/Dockerfile + variables: + DOCKER_TAG: $CI_COMMIT_REF_SLUG + # If we're on our main branch, tag with "latest" + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + changes: + - .gitlab/ci/Dockerfile + variables: + DOCKER_TAG: latest + before_script: + # Authenticate to the docker registry and dependency proxy + - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"},\"ghcr.io\":{\"auth\":\"$(printf "%s:%s" "${PRIVATE_REPO_USER}" "${PRIVATE_REPO_TOKEN}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json + script: + - /kaniko/executor + --context "${CI_PROJECT_DIR}/.gitlab/ci" + --cache=true + --dockerfile "${CI_PROJECT_DIR}/.gitlab/ci/Dockerfile" + --destination "${CI_REGISTRY_IMAGE}:${DOCKER_TAG}" + +fmt: + extends: .terraform:fmt + stage: lint + script: + - !reference [.source, script] + - terragrunt hclfmt -check -diff + - terragrunt run-all fmt -check -diff -recursive || true + when: manual + +init: + stage: init + script: + - !reference [.source, script] + # We need to reconfigure the initialized cache + - terragrunt run-all init -input=false -reconfigure + +validate: + extends: .terraform:validate + script: + - !reference [.source, script] + - terragrunt run-all validate-inputs + - terragrunt run-all validate + when: manual + +build: + extends: .terraform:build + script: + - !reference [.source, script] + when: manual + +deploy: + extends: .terraform:deploy + script: + - !reference [.source, script] + - terragrunt run-all apply --terragrunt-non-interactive -input=false + artifacts: + paths: + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/sshkey + when: always + when: manual + +deploy-env-templates: + stage: deploy-env-templates + script: + - !reference [.source, script] + - for var in $(echo $envs | yq eval '.[].env' -); do .gitlab/scripts/seedenvproject.sh $var $TMP_TEMPLATES_DIR $GITLAB_CI_PAT; done + when: manual + + +#do nothing for now +destroy: + extends: .terraform:destroy + script: + - !reference [.source, script] + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + when: manual \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/bootstrap/.gitlab/ci/Dockerfile b/terraform/gitlab/ci-templates/bootstrap/.gitlab/ci/Dockerfile new file mode 100644 index 000000000..74d1de7bb --- /dev/null +++ b/terraform/gitlab/ci-templates/bootstrap/.gitlab/ci/Dockerfile @@ -0,0 +1,4 @@ +FROM ghcr.io/mojaloop/control-center-util:3.3.3 +ARG GITLAB_TF_REPO_VERSION=1.0.0 +RUN curl -sL https://gitlab.com/gitlab-org/terraform-images/-/raw/v${GITLAB_TF_REPO_VERSION}/src/bin/gitlab-terraform.sh -o /usr/bin/gitlab-terraform \ + && chmod +x /usr/bin/gitlab-terraform \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/bootstrap/.gitlab/scripts/seedenvproject.sh b/terraform/gitlab/ci-templates/bootstrap/.gitlab/scripts/seedenvproject.sh new file mode 100755 index 000000000..a61a778af --- /dev/null +++ b/terraform/gitlab/ci-templates/bootstrap/.gitlab/scripts/seedenvproject.sh @@ -0,0 +1,16 @@ +ENV_NAME=$1 +TMP_TEMPLATE_DIR=$2 +ROOT_TOKEN=$3 +WORKING_DIR=$PWD +TMP_REPO_DIR=/tmp/gitclone${ENV_NAME} +BASE_GITLAB_URL=https://root:${ROOT_TOKEN}@${CI_SERVER_HOST}/iac +git clone ${BASE_GITLAB_URL}/${ENV_NAME} $TMP_REPO_DIR +cd $TMP_REPO_DIR +cp -r $TMP_TEMPLATE_DIR/. . +cp $WORKING_DIR/environment.yaml . +git config --global user.email "root@${gitlab_hostname}" +git config --global user.name "root" +git add . +git commit -m "seeding templates to project" +git push +rm -rf $TMP_REPO_DIR \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/bootstrap/setcivars.sh b/terraform/gitlab/ci-templates/bootstrap/setcivars.sh new file mode 100644 index 000000000..547ea4790 --- /dev/null +++ b/terraform/gitlab/ci-templates/bootstrap/setcivars.sh @@ -0,0 +1,4 @@ +export PRIVATE_REPO_TOKEN=$PRIVATE_REPO_TOKEN +export PRIVATE_REPO_USER=$PRIVATE_REPO_USER +export IAC_TEMPLATES_TAG=$IAC_TEMPLATES_TAG +export IAC_TERRAFORM_MODULES_TAG=$IAC_TERRAFORM_MODULES_TAG \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/k8s-cluster/.gitlab-ci.yml b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab-ci.yml new file mode 100644 index 000000000..9da07a6dd --- /dev/null +++ b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab-ci.yml @@ -0,0 +1,135 @@ +include: + - template: Terraform/Base.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml +workflow: + rules: + - if: $CI_MERGE_REQUEST_IID + changes: + - .gitlab/ci/Dockerfile + variables: + IMAGE_TAG: ${CI_COMMIT_REF_SLUG} + - when: always + # Apparently including the merged workflow rules in addition to the custom rule above doesn't work. + # This comes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml + - if: $CI_MERGE_REQUEST_IID + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +stages: + - prepare + - lint + - init + - validate + - build + - deploy + - deploy-cluster + - cleanup + +variables: + IMAGE_TAG: latest + TF_STATE_BASE_ADDRESS: $CI_API_V4_URL/projects/$CI_PROJECT_ID/terraform/state + SAST_DISABLED: "true" + ANSIBLE_BASE_OUTPUT_DIR: $TF_ROOT/ansible + FOUNDATION_BUILD_OUTPUT_DIR: $TF_ROOT/foundation + +image: ${CI_REGISTRY_IMAGE}:${IMAGE_TAG} + +cache: + key: "${TF_ROOT}" + paths: + - ${TF_ROOT}/**/.terraform + - ${TF_ROOT}/**/.terraform.lock.hcl + - ${TF_ROOT}/**/.terragrunt-cache + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/inventory + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/sshkey + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/kubeconfig + +.source: + script: + - source $(which gitlab-terraform) + - source setcivars.sh + - yq eval '.' environment.yaml -o=json > environment.json + - for var in $(jq -r 'to_entries[] | "\(.key)=\(.value)\n"' ./environment.json); do export $var; done + - echo "https://${PRIVATE_REPO_USER}:${PRIVATE_REPO_TOKEN}@github.com" > ~/.gitcredentials.store + - git config --global credential.helper 'store --file ~/.gitcredentials.store' + - git config --global advice.detachedHead false + - set + +prepare:image: + needs: [] + stage: prepare + image: + name: gcr.io/kaniko-project/executor:v1.9.0-debug + entrypoint: [""] + rules: + # Tag with the commit SHA if we're in an MR + - if: $CI_MERGE_REQUEST_IID + changes: + - .gitlab/ci/Dockerfile + variables: + DOCKER_TAG: $CI_COMMIT_REF_SLUG + # If we're on our main branch, tag with "latest" + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + changes: + - .gitlab/ci/Dockerfile + variables: + DOCKER_TAG: latest + before_script: + # Authenticate to the docker registry and dependency proxy + - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"},\"ghcr.io\":{\"auth\":\"$(printf "%s:%s" "${PRIVATE_REPO_USER}" "${PRIVATE_REPO_TOKEN}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json + script: + - /kaniko/executor + --context "${CI_PROJECT_DIR}/.gitlab/ci" + --cache=true + --dockerfile "${CI_PROJECT_DIR}/.gitlab/ci/Dockerfile" + --destination "${CI_REGISTRY_IMAGE}:${DOCKER_TAG}" + +fmt: + extends: .terraform:fmt + stage: lint + script: + - !reference [.source, script] + - terragrunt hclfmt -check -diff + - terragrunt run-all fmt -check -diff -recursive || true + when: manual + +init: + stage: init + script: + - !reference [.source, script] + # We need to reconfigure the initialized cache + - terragrunt run-all init -input=false -reconfigure + +validate: + extends: .terraform:validate + script: + - !reference [.source, script] + - terragrunt run-all validate-inputs + - terragrunt run-all validate + when: manual + +build: + extends: .terraform:build + script: + - !reference [.source, script] + when: manual + +deploy-infra: + extends: .terraform:deploy + script: + - !reference [.source, script] + - terragrunt run-all apply --terragrunt-non-interactive -input=false + - .gitlab/scripts/pushtorepo.sh $CI_PROJECT_PATH $CI_SERVER_HOST $CI_COMMIT_REF_NAME $FOUNDATION_BUILD_OUTPUT_DIR $GITLAB_CI_PAT $ARGO_CD_ROOT_APP_PATH + artifacts: + paths: + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/kubeconfig + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/sshkey + - ${ANSIBLE_BASE_OUTPUT_DIR}/**/inventory + when: always + when: manual + +destroy: + extends: .terraform:destroy + script: + - !reference [.source, script] + - terragrunt run-all destroy --terragrunt-non-interactive -input=false + when: manual \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/ci/Dockerfile b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/ci/Dockerfile new file mode 100644 index 000000000..74d1de7bb --- /dev/null +++ b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/ci/Dockerfile @@ -0,0 +1,4 @@ +FROM ghcr.io/mojaloop/control-center-util:3.3.3 +ARG GITLAB_TF_REPO_VERSION=1.0.0 +RUN curl -sL https://gitlab.com/gitlab-org/terraform-images/-/raw/v${GITLAB_TF_REPO_VERSION}/src/bin/gitlab-terraform.sh -o /usr/bin/gitlab-terraform \ + && chmod +x /usr/bin/gitlab-terraform \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/scripts/pushtorepo.sh b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/scripts/pushtorepo.sh new file mode 100755 index 000000000..a6a90fe9f --- /dev/null +++ b/terraform/gitlab/ci-templates/k8s-cluster/.gitlab/scripts/pushtorepo.sh @@ -0,0 +1,18 @@ +CURRENT_PROJECT_FULL_PATH=$1 +GIT_HOST=$2 +BRANCH=$3 +SRC_DIR=$4 +ROOT_TOKEN=$5 +DEST_DIR_NAME=$6 +WORKING_DIR=$PWD +TMP_REPO_DIR=/tmp/gitclone +git clone https://root:${ROOT_TOKEN}@${GIT_HOST}/$CURRENT_PROJECT_FULL_PATH $TMP_REPO_DIR +cd $TMP_REPO_DIR +git checkout $BRANCH +cp -r $SRC_DIR/. $DEST_DIR_NAME/ +git config --global user.email "root@${gitlab_hostname}" +git config --global user.name "root" +git add $DEST_DIR_NAME/. +git commit -m "update generated configs to project" +git push +rm -rf $TMP_REPO_DIR \ No newline at end of file diff --git a/terraform/gitlab/ci-templates/k8s-cluster/setcivars.sh b/terraform/gitlab/ci-templates/k8s-cluster/setcivars.sh new file mode 100644 index 000000000..323679c27 --- /dev/null +++ b/terraform/gitlab/ci-templates/k8s-cluster/setcivars.sh @@ -0,0 +1,16 @@ +export GITLAB_CURRENT_PROJECT_ID=$CI_PROJECT_ID +export GITLAB_PROVIDER_TOKEN=$GITLAB_CI_PAT +export GITLAB_PROVIDER_URL=$CI_SERVER_URL +export TF_CONTROL_STATE_TOKEN=$GITLAB_CI_PAT +export TF_CONTROL_STATE_USER=gitlab-ci-token +export TF_CONTROL_STATE_ADDRESS=$CI_API_V4_URL/projects/$BOOTSTRAP_PROJECT_ID/terraform/state/control-center-deploy +export CLUSTER_NAME=$CI_PROJECT_NAME +export CLUSTER_DOMAIN=$DOMAIN +export GITLAB_PROJECT_URL=$CI_PROJECT_URL +export GITLAB_SERVER_URL=$CI_SERVER_URL +export GITLAB_TOKEN=$GITLAB_CI_PAT +export GITLAB_USERNAME=root +export GITLAB_KEY_GITLAB_CI_PAT=GITLAB_CI_PAT +export GITLAB_API_URL=$CI_API_V4_URL +export GITLAB_CURRENT_GROUP_NAME=$CI_PROJECT_NAMESPACE +export ARGO_CD_ROOT_APP_PATH=apps \ No newline at end of file diff --git a/terraform/gitlab/control-center-gitlab-config/gitlab.tf b/terraform/gitlab/control-center-gitlab-config/gitlab.tf new file mode 100644 index 000000000..08dcf0d68 --- /dev/null +++ b/terraform/gitlab/control-center-gitlab-config/gitlab.tf @@ -0,0 +1,131 @@ +resource "gitlab_group" "gitlab_admin_rbac_group" { + name = var.gitlab_admin_rbac_group + path = var.gitlab_admin_rbac_group + description = "${var.gitlab_admin_rbac_group} group" + require_two_factor_authentication = true + two_factor_grace_period = var.two_factor_grace_period +} + +resource "gitlab_group" "gitlab_readonly_rbac_group" { + name = var.gitlab_readonly_rbac_group + path = var.gitlab_readonly_rbac_group + description = "${var.gitlab_readonly_rbac_group} group" + require_two_factor_authentication = true + two_factor_grace_period = var.two_factor_grace_period +} + +resource "gitlab_group" "iac" { + name = "iac" + path = "iac" + description = "iac group" + require_two_factor_authentication = true + two_factor_grace_period = var.two_factor_grace_period +} + +resource "gitlab_project" "bootstrap" { + name = "bootstrap" + namespace_id = gitlab_group.iac.id + initialize_with_readme = true + shared_runners_enabled = true +} + +resource "gitlab_project_variable" "iam_user_key_id" { + project = gitlab_project.bootstrap.id + key = "AWS_ACCESS_KEY_ID" + value = var.iac_user_key_id + protected = true + masked = true +} + +resource "gitlab_project_variable" "iam_user_key_secret" { + project = gitlab_project.bootstrap.id + key = "AWS_SECRET_ACCESS_KEY" + value = var.iac_user_key_secret + protected = true + masked = true +} + +resource "gitlab_project_variable" "iac_templates_tag" { + project = gitlab_project.bootstrap.id + key = "IAC_TEMPLATES_TAG" + value = var.iac_templates_tag + protected = true + masked = false +} + +resource "gitlab_project_variable" "iac_terraform_modules_tag" { + project = gitlab_project.bootstrap.id + key = "IAC_TERRAFORM_MODULES_TAG" + value = var.iac_terraform_modules_tag + protected = true + masked = false +} + +resource "gitlab_project_variable" "control_center_cloud_provider" { + project = gitlab_project.bootstrap.id + key = "CONTROL_CENTER_CLOUD_PROVIDER" + value = var.control_center_cloud_provider + protected = true + masked = false +} + +resource "gitlab_group_variable" "private_repo_user" { + group = gitlab_group.iac.id + key = "PRIVATE_REPO_USER" + value = var.private_repo_user + protected = true + masked = false + environment_scope = "*" +} + +resource "gitlab_group_variable" "bootstrap_project_id" { + group = gitlab_group.iac.id + key = "BOOTSTRAP_PROJECT_ID" + value = gitlab_project.bootstrap.id + protected = true + masked = false + environment_scope = "*" +} + +resource "gitlab_group_variable" "private_repo_token" { + group = gitlab_group.iac.id + key = "PRIVATE_REPO_TOKEN" + value = var.private_repo_token + protected = true + masked = true + environment_scope = "*" +} + +resource "gitlab_application" "netmaker_oidc" { + count = var.enable_netmaker_oidc ? 1 : 0 + confidential = true + scopes = ["profile", "email", "openid"] + name = "netmaker_oidc" + redirect_url = var.netmaker_oidc_redirect_url +} + +resource "gitlab_group_access_token" "gitlab_ci_pat" { + group = gitlab_group.iac.id + name = "gitlab ci pat" + access_level = "owner" + scopes = ["api"] +} +resource "gitlab_group_variable" "gitlab_ci_pat" { + group = gitlab_group.iac.id + key = "GITLAB_CI_PAT" + value = gitlab_group_access_token.gitlab_ci_pat.token + protected = true + masked = true + environment_scope = "*" +} + +locals { + private_repo_docker_credentials = base64encode("${var.private_repo_user}:${var.private_repo_token}") + docker_auth_config = jsonencode({ + "auths" = { + "github.com" = { + "auth" = local.private_repo_docker_credentials + } + } + }) +} \ No newline at end of file diff --git a/terraform/gitlab/control-center-gitlab-config/outputs.tf b/terraform/gitlab/control-center-gitlab-config/outputs.tf new file mode 100644 index 000000000..e786c0309 --- /dev/null +++ b/terraform/gitlab/control-center-gitlab-config/outputs.tf @@ -0,0 +1,14 @@ +output "netmaker_hosts_var_maps" { + sensitive = true + value = { + netmaker_oidc_client_id = var.enable_netmaker_oidc ? gitlab_application.netmaker_oidc[0].application_id : "" + netmaker_oidc_client_secret = var.enable_netmaker_oidc ? gitlab_application.netmaker_oidc[0].secret : "" + } +} +output "bootstrap_project_id" { + value = gitlab_project.bootstrap.id +} + +output "iac_group_id" { + value = gitlab_group.iac.id +} \ No newline at end of file diff --git a/terraform/gitlab/control-center-gitlab-config/variables.tf b/terraform/gitlab/control-center-gitlab-config/variables.tf new file mode 100644 index 000000000..c6e54ed33 --- /dev/null +++ b/terraform/gitlab/control-center-gitlab-config/variables.tf @@ -0,0 +1,51 @@ + +variable "iac_user_key_secret" { + description = "iam user key secret" +} + +variable "iac_user_key_id" { + description = "iam user keyid" +} + +variable "gitlab_admin_rbac_group" { + type = string + description = "rbac group in gitlab for admin access via oidc" +} + +variable "gitlab_readonly_rbac_group" { + type = string + description = "rbac group in gitlab for readonly access via oidc" +} + +variable "two_factor_grace_period" { + description = "two_factor_grace_period in hours" + default = 0 +} + +variable "enable_netmaker_oidc" { + type = bool + default = true + description = "enable oidc config of netmaker" +} + +variable "netmaker_oidc_redirect_url" { + description = "netmaker_oidc_redirect_url" + default = "" +} + +variable "private_repo_user" { + default = "" +} + +variable "private_repo_token" { + default = "" +} +variable "iac_terraform_modules_tag" { + description = "tag for repo for modules" +} +variable "iac_templates_tag" { + description = "tag for repo for templates" +} +variable "control_center_cloud_provider" { + description = "control_center_cloud_provider" +} \ No newline at end of file diff --git a/terraform/gitlab/environment-gitlab-config/gitlab.tf b/terraform/gitlab/environment-gitlab-config/gitlab.tf new file mode 100644 index 000000000..f01c7bb61 --- /dev/null +++ b/terraform/gitlab/environment-gitlab-config/gitlab.tf @@ -0,0 +1,115 @@ + +resource "gitlab_project" "envs" { + for_each = var.env_map + name = each.key + namespace_id = var.iac_group_id + initialize_with_readme = true + shared_runners_enabled = true +} + +resource "gitlab_project_variable" "k8s_cluster_type" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "K8S_CLUSTER_TYPE" + value = each.value["k8s_cluster_type"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "domain" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "DOMAIN" + value = each.value["domain"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "cloud_platform" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "CLOUD_PLATFORM" + value = each.value["cloud_platform"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "cloud_region" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "CLOUD_REGION" + value = each.value["cloud_region"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "letsencrypt_email" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "LETSENCRYPT_EMAIL" + value = each.value["letsencrypt_email"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "iac_terraform_modules_tag" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "IAC_TERRAFORM_MODULES_TAG" + value = each.value["iac_terraform_modules_tag"] + protected = false + masked = false +} + +resource "gitlab_project_variable" "netmaker_token" { + for_each = var.env_map + project = gitlab_project.envs[each.key].id + key = "NETMAKER_TOKEN" + value = each.value["netmaker_token"] + protected = false + masked = true +} + + +resource "gitlab_project_variable" "vault_oauth_client_id" { + for_each = { + for key, env in var.env_map : key => env if env.enable-vault-oauth-to-gitlab + } + project = gitlab_project.envs[each.key].id + key = "VAULT_OAUTH_CLIENT_ID" + value = gitlab_application.vault_oidc[each.key].application_id + protected = false + masked = true +} + +resource "gitlab_project_variable" "vault_oauth_client_secret" { + for_each = { + for key, env in var.env_map : key => env if env.enable-vault-oauth-to-gitlab + } + project = gitlab_project.envs[each.key].id + key = "VAULT_OAUTH_CLIENT_SECRET" + value = gitlab_application.vault_oidc[each.key].secret + protected = false + masked = true +} + +resource "gitlab_project_variable" "enable_vault_oidc" { + for_each = { + for key, env in var.env_map : key => env if env.enable-vault-oauth-to-gitlab + } + project = gitlab_project.envs[each.key].id + key = "ENABLE_VAULT_OIDC" + value = "true" + protected = false + masked = false +} + +resource "gitlab_application" "vault_oidc" { + for_each = { + for key, env in var.env_map : key => env if env.enable-vault-oauth-to-gitlab + } + confidential = true + scopes = ["openid"] + name = "vault_oidc" + redirect_url = "https://vault.${each.key}.${each.value["domain"]}/ui/vault/auth/oidc/oidc/callback" +} \ No newline at end of file diff --git a/terraform/gitlab/environment-gitlab-config/variables.tf b/terraform/gitlab/environment-gitlab-config/variables.tf new file mode 100644 index 000000000..6e1c1160d --- /dev/null +++ b/terraform/gitlab/environment-gitlab-config/variables.tf @@ -0,0 +1,8 @@ +variable "env_map" { + type = map + description = "env repos to pre-create" +} + +variable "iac_group_id" { + description = "group to add env projects to" +} \ No newline at end of file diff --git a/terraform/k8s/ansible-k8s-deploy/terragrunt.hcl b/terraform/k8s/ansible-k8s-deploy/terragrunt.hcl new file mode 100644 index 000000000..2a38eb387 --- /dev/null +++ b/terraform/k8s/ansible-k8s-deploy/terragrunt.hcl @@ -0,0 +1,54 @@ +terraform { + source = "git::https://github.com/mojaloop/iac-modules.git//terraform/ansible/k8s-deploy?ref=${get_env("IAC_TERRAFORM_MODULES_TAG")}" +} + +dependency "k8s_deploy" { + config_path = "../k8s-deploy" + mock_outputs = { + master_hosts = {} + agent_hosts = {} + bastion_hosts = {} + bastion_hosts_var_maps = {} + agent_hosts_var_maps = {} + master_hosts_var_maps = {} + all_hosts_var_maps = {} + bastion_ssh_key = "key" + bastion_os_username = "null" + bastion_public_ip = "null" + } + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "show"] +} + + +inputs = { + master_hosts = dependency.k8s_deploy.outputs.master_hosts + agent_hosts = dependency.k8s_deploy.outputs.agent_hosts + bastion_hosts = dependency.k8s_deploy.outputs.bastion_hosts + bastion_hosts_var_maps = dependency.k8s_deploy.outputs.bastion_hosts_var_maps + agent_hosts_var_maps = dependency.k8s_deploy.outputs.agent_hosts_var_maps + master_hosts_var_maps = merge(dependency.k8s_deploy.outputs.master_hosts_var_maps, local.master_hosts_var_maps) + all_hosts_var_maps = dependency.k8s_deploy.outputs.all_hosts_var_maps + ansible_bastion_key = dependency.k8s_deploy.outputs.bastion_ssh_key + ansible_bastion_os_username = dependency.k8s_deploy.outputs.bastion_os_username + ansible_bastion_public_ip = dependency.k8s_deploy.outputs.bastion_public_ip + ansible_collection_tag = local.env_vars.ansible_collection_tag + ansible_base_output_dir = local.ANSIBLE_BASE_OUTPUT_DIR + ansible_playbook_name = "argo${local.K8S_CLUSTER_TYPE}_cluster_deploy" +} + +locals { + env_vars = yamldecode( + file("${find_in_parent_folders("environment.yaml")}")) + env_map = { for val in local.env_vars.envs : + val["env"] => val } + ANSIBLE_BASE_OUTPUT_DIR = get_env("ANSIBLE_BASE_OUTPUT_DIR") + K8S_CLUSTER_TYPE = get_env("K8S_CLUSTER_TYPE") + ARGO_CD_ROOT_APP_PATH = get_env("ARGO_CD_ROOT_APP_PATH") + master_hosts_var_maps = { + root_app_path = "${local.ARGO_CD_ROOT_APP_PATH}/app-yamls" + } +} + +include "root" { + path = find_in_parent_folders() +} diff --git a/terraform/k8s/aws-vars.yaml b/terraform/k8s/aws-vars.yaml new file mode 100644 index 000000000..e1decd73a --- /dev/null +++ b/terraform/k8s/aws-vars.yaml @@ -0,0 +1 @@ +aws_provider_version: "~> 3.7" \ No newline at end of file diff --git a/terraform/k8s/common-vars.yaml b/terraform/k8s/common-vars.yaml new file mode 100644 index 000000000..3c26cbba0 --- /dev/null +++ b/terraform/k8s/common-vars.yaml @@ -0,0 +1,10 @@ +tf_version: ">= 1.1" +local_provider_version: "~> 2.2" +gitlab_provider_version: "~> 15.11" +cert_manager_chart_version: 1.11.0 +consul_chart_version: 1.0.3 +longhorn_chart_version: 1.4.0 +external_dns_chart_version: 6.7.2 +vault_chart_version: 0.23.0 +vault_config_operator_helm_chart_version: 0.8.9 +nginx_helm_chart_version: 4.3.0 \ No newline at end of file diff --git a/terraform/k8s/foundation-build/terragrunt.hcl b/terraform/k8s/foundation-build/terragrunt.hcl new file mode 100644 index 000000000..c75d23ae9 --- /dev/null +++ b/terraform/k8s/foundation-build/terragrunt.hcl @@ -0,0 +1,99 @@ +terraform { + source = "git::https://github.com/mojaloop/iac-modules.git//terraform/foundation-install?ref=${get_env("IAC_TERRAFORM_MODULES_TAG")}" +} + + +include "root" { + path = find_in_parent_folders() +} + +dependency "k8s_deploy" { + config_path = "../k8s-deploy" + mock_outputs = { + nat_public_ips = "" + internal_load_balancer_dns = "" + external_load_balancer_dns = "" + private_subdomain = "" + public_subdomain = "" + longhorn_backups_bucket_name = "" + gitlab_key_route53_external_dns_access_key = "" + gitlab_key_route53_external_dns_secret_key = "" + gitlab_key_longhorn_backups_access_key = "" + gitlab_key_longhorn_backups_secret_key = "" + gitlab_key_vault_iam_user_access_key = "" + gitlab_key_vault_iam_user_secret_key = "" + vault_kms_seal_kms_key_id = "" + target_group_internal_https_port = 0 + target_group_internal_http_port = 0 + target_group_external_https_port = 0 + target_group_external_http_port = 0 + + } + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "show"] +} + +inputs = { + tags = local.tags + nat_public_ips = dependency.k8s_deploy.outputs.nat_public_ips + internal_load_balancer_dns = dependency.k8s_deploy.outputs.internal_load_balancer_dns + external_load_balancer_dns = dependency.k8s_deploy.outputs.external_load_balancer_dns + private_subdomain = dependency.k8s_deploy.outputs.private_subdomain + public_subdomain = dependency.k8s_deploy.outputs.public_subdomain + longhorn_backups_bucket_name = dependency.k8s_deploy.outputs.longhorn_backups_bucket_name + gitlab_key_route53_external_dns_access_key = dependency.k8s_deploy.outputs.gitlab_key_route53_external_dns_access_key + gitlab_key_route53_external_dns_secret_key = dependency.k8s_deploy.outputs.gitlab_key_route53_external_dns_secret_key + gitlab_key_longhorn_backups_access_key = dependency.k8s_deploy.outputs.gitlab_key_longhorn_backups_access_key + gitlab_key_longhorn_backups_secret_key = dependency.k8s_deploy.outputs.gitlab_key_longhorn_backups_secret_key + gitlab_key_vault_iam_user_access_key = dependency.k8s_deploy.outputs.gitlab_key_vault_iam_user_access_key + gitlab_key_vault_iam_user_secret_key = dependency.k8s_deploy.outputs.gitlab_key_vault_iam_user_secret_key + vault_kms_seal_kms_key_id = dependency.k8s_deploy.outputs.vault_kms_seal_kms_key_id + internal_ingress_https_port = dependency.k8s_deploy.outputs.target_group_internal_https_port + internal_ingress_http_port = dependency.k8s_deploy.outputs.target_group_internal_http_port + external_ingress_https_port = dependency.k8s_deploy.outputs.target_group_external_https_port + external_ingress_http_port = dependency.k8s_deploy.outputs.target_group_external_http_port + cert_manager_chart_version = local.common_vars.cert_manager_chart_version + consul_chart_version = local.common_vars.consul_chart_version + longhorn_chart_version = local.common_vars.longhorn_chart_version + external_dns_chart_version = local.common_vars.external_dns_chart_version + vault_chart_version = local.common_vars.vault_chart_version + vault_config_operator_helm_chart_version = local.common_vars.vault_config_operator_helm_chart_version + nginx_helm_chart_version = local.common_vars.nginx_helm_chart_version + output_dir = local.FOUNDATION_BUILD_OUTPUT_DIR + gitlab_project_url = local.GITLAB_PROJECT_URL + cluster_name = local.CLUSTER_NAME + stateful_resources_config_file = find_in_parent_folders("stateful-resources.json") + current_gitlab_project_id = local.GITLAB_CURRENT_PROJECT_ID + gitlab_group_name = local.GITLAB_CURRENT_GROUP_NAME + gitlab_api_url = local.GITLAB_API_URL + gitlab_server_url = local.GITLAB_SERVER_URL + gitlab_key_gitlab_ci_pat = local.GITLAB_KEY_GITLAB_CI_PAT + dns_cloud_region = local.CLOUD_REGION + gitlab_readonly_group_name = local.gitlab_readonly_rbac_group + gitlab_admin_group_name = local.gitlab_admin_rbac_group + enable_vault_oidc = local.ENABLE_VAULT_OIDC + vault_oauth_client_secret = local.VAULT_OAUTH_CLIENT_SECRET + vault_oauth_client_id = local.VAULT_OAUTH_CLIENT_ID + letsencrypt_email = local.LETSENCRYPT_EMAIL +} + +locals { + env_vars = yamldecode(file("${find_in_parent_folders("environment.yaml")}")) + tags = local.env_vars.tags + gitlab_readonly_rbac_group = local.env_vars.gitlab_readonly_rbac_group + gitlab_admin_rbac_group = local.env_vars.gitlab_admin_rbac_group + common_vars = yamldecode(file("${find_in_parent_folders("common-vars.yaml")}")) + GITLAB_SERVER_URL = get_env("GITLAB_SERVER_URL") + FOUNDATION_BUILD_OUTPUT_DIR = get_env("FOUNDATION_BUILD_OUTPUT_DIR") + CLUSTER_NAME = get_env("CLUSTER_NAME") + CLUSTER_DOMAIN = get_env("CLUSTER_DOMAIN") + GITLAB_PROJECT_URL = get_env("GITLAB_PROJECT_URL") + GITLAB_CURRENT_PROJECT_ID = get_env("GITLAB_CURRENT_PROJECT_ID") + GITLAB_CURRENT_GROUP_NAME = get_env("GITLAB_CURRENT_GROUP_NAME") + GITLAB_API_URL = get_env("GITLAB_API_URL") + GITLAB_KEY_GITLAB_CI_PAT = get_env("GITLAB_KEY_GITLAB_CI_PAT") + CLOUD_REGION = get_env("CLOUD_REGION") + ENABLE_VAULT_OIDC = get_env("ENABLE_VAULT_OIDC") + VAULT_OAUTH_CLIENT_SECRET = get_env("ENABLE_VAULT_OIDC") ? get_env("VAULT_OAUTH_CLIENT_SECRET") : null + VAULT_OAUTH_CLIENT_ID = get_env("ENABLE_VAULT_OIDC") ? get_env("VAULT_OAUTH_CLIENT_ID") : null + LETSENCRYPT_EMAIL = get_env("LETSENCRYPT_EMAIL") +} diff --git a/terraform/k8s/k8s-deploy/terragrunt.hcl b/terraform/k8s/k8s-deploy/terragrunt.hcl new file mode 100644 index 000000000..4a306242b --- /dev/null +++ b/terraform/k8s/k8s-deploy/terragrunt.hcl @@ -0,0 +1,64 @@ +terraform { + source = "git::https://github.com/mojaloop/iac-modules.git//terraform/${get_env("CLOUD_PLATFORM")}/base-k8s?ref=${get_env("IAC_TERRAFORM_MODULES_TAG")}" +} + + +include "root" { + path = find_in_parent_folders() +} + + +inputs = { + tags = local.tags + cluster_name = local.CLUSTER_NAME + domain = local.CLUSTER_DOMAIN + gitlab_project_url = local.GITLAB_PROJECT_URL + gitlab_server_url = local.GITLAB_SERVER_URL + current_gitlab_project_id = local.GITLAB_CURRENT_PROJECT_ID + gitlab_token = local.GITLAB_TOKEN + gitlab_username = local.GITLAB_USERNAME + route53_zone_force_destroy = true + longhorn_backup_s3_destroy = true +} + +locals { + env_vars = yamldecode( + file("${find_in_parent_folders("environment.yaml")}") + ) + cloud_platform_vars = yamldecode( + file("${find_in_parent_folders("${get_env("CLOUD_PLATFORM")}-vars.yaml")}") + ) + tags = local.env_vars.tags + CLUSTER_NAME = get_env("CLUSTER_NAME") + CLUSTER_DOMAIN = get_env("CLUSTER_DOMAIN") + GITLAB_PROJECT_URL = get_env("GITLAB_PROJECT_URL") + GITLAB_SERVER_URL = get_env("CI_SERVER_URL") + GITLAB_CURRENT_PROJECT_ID = get_env("GITLAB_CURRENT_PROJECT_ID") + GITLAB_TOKEN = get_env("GITLAB_TOKEN") + GITLAB_USERNAME = get_env("GITLAB_USERNAME") + K8S_CLUSTER_TYPE = get_env("K8S_CLUSTER_TYPE") + CLOUD_REGION = get_env("CLOUD_REGION") + ANSIBLE_BASE_OUTPUT_DIR = get_env("ANSIBLE_BASE_OUTPUT_DIR") +} + +generate "required_providers_override" { + path = "required_providers_override.tf" + + if_exists = "overwrite_terragrunt" + + contents = <