Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/terraform-validate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: terraform-validate
on:
push:
branches:
- main
- dev
Comment on lines +2 to +6
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validation is not wired for PRs

This runs only on pushes. Add a pull_request trigger so Terraform validation gates changes before merge.

Suggested workflow trigger update
 on:
   push:
     branches:
       - main
       - dev
+  pull_request:
+    branches:
+      - main
+      - dev
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
push:
branches:
- main
- dev
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev

jobs:
validate:
name: Terraform Validate
runs-on: ubuntu-24.04
defaults:
run:
working-directory: ./terraform
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

- name: Set up Terraform
uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85
with:
terraform_version: "1.14.7"

- name: Initialize Terraform project
run: terraform init -backend=false

- name: Run Terraform Validate
run: terraform validate
Empty file added Makefile
Empty file.
63 changes: 63 additions & 0 deletions helm/gitlab/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
global:
edition: ce

hosts:
domain: ${domain}
https: true
gitlab:
name: ${gitlab_host}.${domain}
registry:
name: ${registry_host}.${domain}

psql:
host: ${postgres_host}
port: ${postgres_port}
database: ${postgres_database}
username: ${postgres_username}
password:
secret: gitlab-postgres-secret
key: password

redis:
host: ${redis_host}
port: ${redis_port}
auth:
enabled: true
secret: gitlab-redis-secret
key: password

appConfig:
object_store:
enabled: true
proxy_download: true
connection:
secret: gitlab-s3-main-secret
key: connection

artifacts:
bucket: ${buckets["artifacts"]}
connection: {}
uploads:
bucket: ${buckets["uploads"]}
connection: {}
packages:
bucket: ${buckets["packages"]}
connection: {}
lfs:
bucket: ${buckets["lfs"]}
connection: {}
backups:
bucket: ${buckets["backups"]}
tmpBucket: ${buckets["backups"]}

Comment on lines +29 to +52
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In the official GitLab Helm chart documentation for the chart version used here, how should external S3/Spaces credentials be configured for the container registry and for backups? Do those components inherit global.appConfig.object_store.connection, or do they require their own secret references?

💡 Result:

In the official GitLab Helm chart documentation, external S3/Spaces credentials for the container registry and backups do not inherit from global.appConfig.object_store.connection. They require their own dedicated secret references. For the container registry: Credentials are configured via a dedicated secret referenced by registry.storage.secret and registry.storage.key (typically a secret containing a config key with S3 details like s3: bucket: ...). The bucket is also set via global.registry.bucket. Examples include registry.s3.yaml, registry.gcs.yaml. This is separate from Rails object storage. For backups: Credentials are configured via the Toolbox pod's settings: gitlab.toolbox.backups.objectStorage.config.secret and gitlab.toolbox.backups.objectStorage.config.key (typically a secret with a .s3cfg file for S3, or equivalent for GCS/Azure). Buckets are global.appConfig.backups.bucket and global.appConfig.backups.tmpBucket. The backend is set via gitlab.toolbox.backups.objectStorage.backend (s3/gcs/azure). Backups do not use the Rails consolidated object_store connection. global.appConfig.object_store.connection is for Rails consolidated object storage (LFS, artifacts, uploads, etc.), not registry or backups. These components use independent configurations to allow different backends/buckets/credentials if needed.

Citations:


🏁 Script executed:

# First, let's see the size of the values.yaml file
wc -l helm/gitlab/values.yaml

# Then search for registry and backup credential/secret configurations
echo "=== Searching for registry storage configuration ==="
rg -n "registry\." helm/gitlab/values.yaml | head -30

echo "=== Searching for backup object storage configuration ==="
rg -n "backups?" helm/gitlab/values.yaml -i | head -30

echo "=== Searching for toolbox backup configuration ==="
rg -n "toolbox" helm/gitlab/values.yaml -i | head -20

Repository: clofour/gitlab-kubernetes

Length of output: 354


🏁 Script executed:

cat -n helm/gitlab/values.yaml

Repository: clofour/gitlab-kubernetes

Length of output: 1651


🏁 Script executed:

# Check the terraform file to confirm registry and backup secrets exist
cat -n terraform/kubernetes.tf | sed -n '55,92p'

Repository: clofour/gitlab-kubernetes

Length of output: 1413


Add registry and backup object storage configurations to the Helm values.

This file only wires the Rails-consolidated object storage (via gitlab-s3-main-secret), but the container registry and backups require their own dedicated secret references in the chart. According to the GitLab Helm chart documentation, these components do not inherit from global.appConfig.object_store.connection—they each need independent configurations:

  • Registry: Requires registry.storage.secret and registry.storage.key pointing to the registry credentials secret
  • Backups: Requires gitlab.toolbox.backups.objectStorage.config.secret and gitlab.toolbox.backups.objectStorage.config.key pointing to the backup credentials secret

Currently, neither is configured in values.yaml, leaving the registry and backup services unable to authenticate to their respective Spaces buckets. The secrets are created in Terraform (lines 55–92) but remain unconsumed.

🧰 Tools
🪛 Checkov (3.2.513)

[low] 34-35: Base64 High Entropy String

(CKV_SECRET_6)

Comment thread
clofour marked this conversation as resolved.
time_zone: UTC


postgresql:
install: false

redis:
install: false

minio:
install: false
86 changes: 86 additions & 0 deletions terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions terraform/cluster.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
data "digitalocean_kubernetes_versions" "current" {
version_prefix = var.k8s_version
}

resource "digitalocean_kubernetes_cluster" "main" {
name = var.cluster_name
region = var.region
version = data.digitalocean_kubernetes_versions.current.latest_version
vpc_uuid = digitalocean_vpc.main.id

auto_upgrade = false
surge_upgrade = true
Comment thread
clofour marked this conversation as resolved.

node_pool {
name = "default"
size = var.node_size
node_count = var.node_count
labels = { role = "general" }
}
}
8 changes: 8 additions & 0 deletions terraform/dependencies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ terraform {
source = "digitalocean/digitalocean"
version = "~> 2.81.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 3.0.1"
}
helm = {
source = "hashicorp/helm"
version = "~> 3.1.1"
}
random = {
source = "hashicorp/random"
version = "~> 3.8.1"
Expand Down
29 changes: 29 additions & 0 deletions terraform/helm.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
resource "helm_release" "gitlab" {
name = "gitlab"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
repository = "https://charts.gitlab.io/"
chart = "gitlab"
Comment thread
clofour marked this conversation as resolved.
version = "9.10.3"

values = [
templatefile("${path.module}/../helm/gitlab/values.yaml", {
domain = var.domain_name
gitlab_host = var.gitlab_host
registry_host = var.registry_host
postgres_host = digitalocean_database_cluster.postgres.private_host
postgres_port = digitalocean_database_cluster.postgres.port
postgres_database = digitalocean_database_db.gitlab.name
postgres_username = digitalocean_database_user.gitlab.name
redis_host = digitalocean_database_cluster.valkey.private_host
redis_port = digitalocean_database_cluster.valkey.port
buckets = {for key, bucket in digitalocean_spaces_bucket.gitlab : key => bucket.name}
})
]

depends_on = [
kubernetes_secret_v1.gitlab_postgres,
kubernetes_secret_v1.gitlab_redis,
kubernetes_secret_v1.gitlab_s3_main,
digitalocean_database_db.gitlab
]
}
100 changes: 86 additions & 14 deletions terraform/kubernetes.tf
Original file line number Diff line number Diff line change
@@ -1,20 +1,92 @@
data "digitalocean_kubernetes_versions" "current" {
version_prefix = var.k8s_version
resource "kubernetes_namespace_v1" "gitlab" {
metadata {
name = "gitlab"
}

depends_on = [ digitalocean_kubernetes_cluster.main ]
}

resource "kubernetes_secret_v1" "gitlab_postgres" {
metadata {
name = "gitlab-postgres-secret"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
}

data = {
password = digitalocean_database_user.gitlab.password
}

type = "Opaque"
}

resource "digitalocean_kubernetes_cluster" "main" {
name = var.cluster_name
region = var.region
version = data.digitalocean_kubernetes_versions.current.latest_version
vpc_uuid = digitalocean_vpc.main.id
resource "kubernetes_secret_v1" "gitlab_redis" {
metadata {
name = "gitlab-redis-secret"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
}

data = {
password = digitalocean_database_cluster.valkey.password
}
Comment thread
clofour marked this conversation as resolved.

auto_upgrade = false
surge_upgrade = true
type = "Opaque"
}

resource "kubernetes_secret_v1" "gitlab_s3_main" {
metadata {
name = "gitlab-s3-main-secret"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
}

node_pool {
name = "default"
size = var.node_size
node_count = var.node_count
labels = { role = "general" }
data = {
connection = yamlencode({
provider = "AWS"
region = var.region
endpoint = "https://${var.region}.digitaloceanspaces.com"
aws_access_key_id = var.spaces_access_id
aws_secret_access_key = var.spaces_secret_key
path_style = true
})
}

type = "Opaque"
}

resource "kubernetes_secret_v1" "gitlab_s3_registry" {
metadata {
name = "gitlab-s3-registry-secret"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
}

data = {
connection = yamlencode({
accesskey = var.spaces_access_id
secretkey = var.spaces_secret_key
region = var.region
regionendpoint = "https://${var.region}.digitaloceanspaces.com"
bucket = digitalocean_spaces_bucket.gitlab["registry"].name
})
}

type = "Opaque"
}

resource "kubernetes_secret_v1" "gitlab_s3_backup" {
metadata {
name = "gitlab-s3-backup-secret"
namespace = kubernetes_namespace_v1.gitlab.metadata[0].name
}

data = {
connection = yamlencode({
provider = "AWS"
region = var.region
endpoint = "https://${var.region}.digitaloceanspaces.com"
aws_access_key_id = var.spaces_access_id
aws_secret_access_key = var.spaces_secret_key
path_style = true
})
}

type = "Opaque"
Comment on lines +9 to +91
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Back this stack with an encrypted, access-restricted state backend.

These kubernetes_secret_v1 resources copy database and Spaces credentials into Terraform state as well as into the cluster. Make sure the backend is remote, encrypted, and tightly scoped before rollout.

}
Comment thread
clofour marked this conversation as resolved.
2 changes: 1 addition & 1 deletion terraform/postgres.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ resource "digitalocean_database_cluster" "postgres" {

resource "digitalocean_database_db" "gitlab" {
cluster_id = digitalocean_database_cluster.postgres.id
name = "gitlab_production"
name = "gitlab"
}

resource "digitalocean_database_user" "gitlab" {
Expand Down
18 changes: 18 additions & 0 deletions terraform/providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,22 @@ provider "digitalocean" {
token = var.do_token
spaces_access_id = var.spaces_access_id
spaces_secret_key = var.spaces_secret_key
}

provider "kubernetes" {
host = digitalocean_kubernetes_cluster.main.endpoint
token = digitalocean_kubernetes_cluster.main.kube_config[0].token
cluster_ca_certificate = base64decode(
digitalocean_kubernetes_cluster.main.kube_config[0].cluster_ca_certificate
)
}

provider "helm" {
kubernetes = {
host = digitalocean_kubernetes_cluster.main.endpoint
token = digitalocean_kubernetes_cluster.main.kube_config[0].token
cluster_ca_certificate = base64decode(
digitalocean_kubernetes_cluster.main.kube_config[0].cluster_ca_certificate
)
}
}
Loading