diff --git a/blueprints/third-party-solutions/README.md b/blueprints/third-party-solutions/README.md
index 13a441b2..94449181 100644
--- a/blueprints/third-party-solutions/README.md
+++ b/blueprints/third-party-solutions/README.md
@@ -26,4 +26,10 @@ The blueprints in this folder show how to automate installation of specific thir
These examples show how to deploy F5 BigIP-VE load balancers in GCP.
+
+
+### Gitlab
+
+ This blueprint shows how to deploy a Gitlab instance in GCP. The architecture is based on the reference described in the [official documentation](https://docs.gitlab.com/ee/administration/reference_architectures/1k_users.html) with managed services such as Cloud SQL, Memorystore and Cloud Storage.
+
\ No newline at end of file
diff --git a/blueprints/third-party-solutions/gitlab/README.md b/blueprints/third-party-solutions/gitlab/README.md
new file mode 100644
index 00000000..f720b8b0
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/README.md
@@ -0,0 +1,389 @@
+# Gitlab Blueprint
+
+This blueprint is responsible for provisioning a production ready Gitlab instance on the landing zone infrastructure. The [reference architecture](https://docs.gitlab.com/ee/administration/reference_architectures/1k_users.html) of this deployment target 1K users, updates to the current code is required in of HA and/or higher capacity requirements.
+
+The following diagram illustrates the high-level design of created resources, which can be adapted to specific requirements via variables:
+
+
+
+
+
+## Table of contents
+
+
+* [Gitlab Blueprint](#gitlab-blueprint)
+ * [Table of contents](#table-of-contents)
+ * [Managed Services for Seamless Operations](#managed-services-for-seamless-operations)
+ * [Object Storage <-> Google Cloud Storage](#object-storage-----google-cloud-storage)
+ * [Identity](#identity)
+ * [SAML Integration](#saml-integration)
+ * [Google Workspace Setup](#google-workspace-setup)
+ * [Others Identity Integration](#others-identity-integration)
+ * [Email](#email)
+ * [Sendgrid integration](#sendgrid-integration)
+ * [SSL Certificate Configuration](#ssl-certificate-configuration)
+ * [Networking and scalability](#networking-and-scalability)
+ * [HA](#ha)
+ * [Deployment](#deployment)
+ * [Step 0: Cloning the repository](#step-0--cloning-the-repository)
+ * [Step 2: Prepare the variables](#step-2--prepare-the-variables)
+ * [Step 3: Deploy resources](#step-3--deploy-resources)
+ * [Step 4: Use the created resources](#step-4--use-the-created-resources)
+ * [Reference and useful links](#reference-and-useful-links)
+ * [Files](#files)
+ * [Variables](#variables)
+ * [Outputs](#outputs)
+
+
+## Managed Services for Seamless Operations
+
+This Gitlab installation prioritizes the use of Google Cloud managed services to
+streamline infrastructure management and optimization. Here's a breakdown of the
+managed services incorporated:
+
+1. [Google Cloud Storage](https://cloud.google.com/storage): is a highly
+ scalable and secure object storage service for storing and accessing data in
+ Google Cloud.
+2. [Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/postgres): Cloud SQL
+ for Postgres is a fully managed database service on Google Cloud Platform. It
+ eliminates database administration tasks, allowing you to focus on your
+ application, while offering high performance, automatic scaling, and secure
+ management of your PostgreSQL databases.
+3. [Memorystore](https://cloud.google.com/memorystore?hl=en): GCP Memorystore
+ offers a fully managed Redis service for in-memory data caching and
+ high-performance data access.
+
+Benefits:
+
+- Reduced Operational Overhead: Google handles infrastructure setup,
+ maintenance, and updates, freeing up your time and resources.
+- Enhanced Security: Managed services often benefit from Google's comprehensive
+ security measures and expertise.
+- Scalability: Easily adjust resource allocation to meet evolving demands.
+- Cost Optimization: Pay for the resources you use, benefiting from Google's
+ infrastructure optimization.
+ Integration: Managed services seamlessly integrate with other GCP services,
+ promoting a cohesive cloud environment.
+ This module embraces managed services to deliver a resilient, scalable, and
+ cost-effective application architecture on Google Cloud.
+
+### Object Storage <-> Google Cloud Storage
+
+GitLab supports using an object storage service for holding numerous types of
+data. It’s recommended over NFS and in general it’s better in larger setups as
+object storage is typically much more performant, reliable, and scalable.
+
+A single storage connection to Cloud Storage is configured for all object types,
+which leverages default Google Compute Engine credential (the so called "
+consolidated form"). A Cloud Storage bucket is bootstrapped for each object
+type, the table below summarized such a configuration:
+
+| Object Type | Description | Cloud Storage Bucket |
+|------------------|----------------------------------------|-----------------------------------|
+| artifacts | CI artifacts | ${prefix}-gitlab-artifacts |
+| external_diffs | Merge request diffs | ${prefix}-mr-diffs |
+| uploads | User uploads | ${prefix}-gitlab-uploads |
+| lfs | Git Large File Storage objects | ${prefix}-gitlab-lfs |
+| packages | Project packages (e.g. PyPI, Maven ..) | ${prefix}-gitlab-packages |
+| dependency_proxy | Dependency Proxy | ${prefix}-gitlab-dependency-proxy |
+| terraform_state | Terraform state files | ${prefix}-gitlab-terraform-state |
+| pages | Pages | ${prefix}-gitlab-pages |
+
+For more information on Gitlab object storage and Google Cloud Storage
+integration please refer to the official Gitlab documentation available at the
+following [link](https://docs.gitlab.com/ee/administration/object_storage.html).
+
+- [PostgreSQL service](https://docs.gitlab.com/ee/administration/postgresql/external.html)
+
+Updated postgres configuration to match documentation, created required database
+in postgres instance.
+
+- [Redis](https://docs.gitlab.com/ee/administration/redis/replication_and_failover_external.html)
+
+## Identity
+
+GitLab integrates with a number of OmniAuth providers as well as external
+authentication and authorization providers such as Google Secure LDAP and many
+other providers.
+At this time this stage can deal with SAML integration for both user
+authentication and provisioning, in order to setup SAML integration please
+provide the saml block on gitlab_config variable.
+
+### SAML Integration
+
+This section details how configure GitLab to act as a SAML service provider (
+SP). This allows GitLab to consume assertions from a SAML identity provider (
+IdP), such as Cloud Identity, to authenticate users. Please find instructions
+below for integration with:
+
+- [Google Workspace](#google-workspace-setup)
+
+#### Google Workspace Setup
+
+Setup of Google Workspace is documented in the official Gitlab documentation
+available at the
+following [link](https://docs.gitlab.com/ee/integration/saml.html#set-up-google-workspace)
+which are also reported below for simplicity.
+
+Create a custom SAML webapp following instructions available at the
+following [link](https://support.google.com/a/answer/6087519), providing these
+information in the service provider configuration:
+
+| Configuration | Typical Value | Cloud Storage Bucket |
+|-------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------|
+| Name of SAML App | Gitlab | Name of the app |
+| ACS URL | https:///users/auth/saml/callback | Assertion Consumer Service URL. |
+| GITLAB_DOMAIN | gitlab.example.com | Your GitLab instance domain. |
+| Entity ID | https://gitlab.example.com | A value unique to your SAML application. Set it to the issuer in your GitLab configuration. |
+| Name ID | EMAIL | Required value. Also known as name_identifier_format. |
+
+Then setup the following SAML attribute mappings:
+
+| Google Directory attributes | App attributes |
+|--------------------------------|----------------|
+| Basic information > Email | email |
+| Basic Information > First name | first_name |
+| Basic Information > Last name | last_name |
+
+After configuring the Google Workspace SAML application, record the following
+information:
+
+| Value | Description |
+|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| SSO URL | Setup in gitlab_config.saml.sso_target_url variable |
+| Certificate (download) | Setup in gitlab_config.saml.idp_cert_fingerprint (obtain value with the following command `openssl x509 -in -noout -fingerprint -sha1`) |
+
+### Others Identity Integration
+
+- [OpenID Connect OmniAuth](https://docs.gitlab.com/ee/administration/auth/oidc.html#configure-google)
+- [Google Secure LDAP](https://docs.gitlab.com/ee/administration/auth/ldap/google_secure_ldap.html)
+
+## Email
+
+### Gmail / Workspace
+
+- [ ] [documentation](https://docs.gitlab.com/ee/administration/incoming_email.html#gmail)
+
+### Sendgrid integration
+
+Use
+the [Google Cloud Marketplace](https://console.cloud.google.com/marketplace/details/sendgrid-app/sendgrid-email)
+to sign up for the SendGrid email service. Make a note of your SendGrid SMTP
+account credentials, which include username, password, and hostname. Your SMTP
+username and password are the same as what you used to sign up for the service.
+The SendGrid hostname is smtp.sendgrid.net.
+Create an API key:
+Sign in to SendGrid and go to Settings > API Keys.
+
+1. Create an API key.
+2. Select the permissions for the key. At a minimum, the key must have Mail send
+ permissions to send email.
+3. Click Save to create the key.
+4. SendGrid generates a new key. This is the only copy of the key, so make sure
+ that you copy the key and save it for later.
+
+Configure the sendgrid API key in the gitlab_config variable, under mail,
+sendgrid arguments as per the following example:
+
+```terraform
+gitlab_config = {
+ hostname = "gitlab.example.com"
+ mail = {
+ sendgrid = {
+ api_key = "test"
+ }
+ }
+}
+```
+
+## SSL Certificate Configuration
+
+This module provides flexibility in configuring SSL certificates for the server.
+You have two options:
+
+1. **Provide Your Own Certificates**: If you have existing SSL certificates, you
+ can place them in the certs folder within the module's directory. The module
+ will automatically detect and use them.
+ File Names: Ensure the files are named ${gitlab_hostname}.crt (for the
+ certificate) and
+ gitlab_hostname.key (for the private key). Although it is not required in
+ this stage it is mandatory to also place inside the certs folder the server
+ CA certificate which is later use to secure HTTPS access from the Gitlab
+ runner. Name of the CA certificate should be: ${gitlab_hostname}.ca.crt
+2. **Use Automatically Generated Self-Signed Certificates**: If you don't
+ provide certificates, the module will generate a self-signed certificate for
+ immediate use.
+ Updating Later: You can replace the self-signed certificate with your own
+ certificates at any time by placing them in the certs folder and re-running
+ Terraform.
+
+**Important Notes:**
+
+Certificate Validation: Self-signed certificates are not validated by browsers
+and will trigger warnings. Use them only for development or testing
+environments.
+
+For more information on how to configure HTTPS on Gitlab please refer to the
+original Gitlab documentation available at the
+following [link](https://docs.gitlab.com/omnibus/settings/ssl/#configure-https-manually).
+
+## Networking and scalability
+
+- [Load balancer](https://docs.gitlab.com/ee/administration/load_balancer.html)
+
+## HA
+
+- [High Availability](http://ubimol.it/12.0/ee/administration/high_availability/README.html)
+
+### Deployment
+
+#### Step 0: Cloning the repository
+
+If you want to deploy from your Cloud Shell, click on the image below, sign in
+if required and when the prompt appears, click on “confirm”.
+
+[![Open Cloudshell](../../../assets/images/cloud-shell-button.png)](https://shell.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fcloud-foundation-fabric&cloudshell_workspace=blueprints%2Fthird-party-solutions%2Fwordpress%2Fcloudrun)
+
+Otherwise, in your console of choice:
+
+```bash
+git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric
+```
+
+Before you deploy the architecture, you will need at least the following
+information (for more precise configuration see the Variables section):
+
+* The project ID
+
+The VPC host project, VPC and subnets should already exist and the following networking requirements are satisfied:
+- configured PSA for Cloud SQL on the VPC
+- subnets configured with PGA and Cloud NAT for internet access
+- Inbound firewall rule for IAP on port 22
+- Inbound firewall rule for TCP ports 80, 443, 2222 from proxy subnet CIDR (gitlab)
+
+#### Step 2: Prepare the variables
+
+Once you have the required information, head back to your cloned repository.
+Make sure you’re in the directory of this tutorial (where this README is in).
+
+Configure the Terraform variables in your `terraform.tfvars` file.
+See [terraform.tfvars.sample](terraform.tfvars.sample) as starting point - just
+copy it to `terraform.tfvars` and edit the latter. See the variables
+documentation below.
+
+#### Step 3: Deploy resources
+
+Initialize your Terraform environment and deploy the resources:
+
+```shell
+terraform init
+terraform apply
+```
+
+#### Step 4: Use the created resources
+
+Connect to squid-proxy for accessing gitlab instance using the gcloud command
+available in the `ssh_to_bastion` terraform output.
+
+```bash
+terraform output ssh_to_bastion
+```
+
+A gcloud command like the following should be available
+
+```bash
+gcloud compute ssh squid-vm --project ${project} --zone europe-west8-b -- -L 3128:127.0.0.1:3128 -N -q -f
+```
+
+Set as system proxy ip 127.0.0.1 and port 3128 and connect to Gitlab hostname https://gitlab.gcp.example.com.
+Use default admin password available in /run/gitlab/config/initial_root_password or reset admin password via the following command on the Docker container:
+
+```bash
+gitlab-rake “gitlab:password:reset”
+```
+
+## Reference and useful links
+
+- [Reference architecture up to 1k users](https://docs.gitlab.com/ee/administration/reference_architectures/1k_users.html)
+- [`/etc/gitlab/gitlab.rb` template](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template)
+- [`/etc/gitlab/gitlab.rb` default options](https://docs.gitlab.com/ee/administration/package_information/defaults.html)
+
+
+
+## Files
+
+| name | description | modules | resources |
+|---|---|---|---|
+| [gitlab.tf](./gitlab.tf) | None | compute-vm
· iam-service-account
· net-lb-int
| |
+| [main.tf](./main.tf) | Module-level locals and resources. | project
| |
+| [outputs.tf](./outputs.tf) | Module outputs. | | |
+| [services.tf](./services.tf) | None | cloudsql-instance
· gcs
| google_redis_instance
|
+| [ssl.tf](./ssl.tf) | None | | tls_cert_request
· tls_locally_signed_cert
· tls_private_key
· tls_self_signed_cert
|
+| [variables.tf](./variables.tf) | Module variables. | | |
+
+## Variables
+
+| name | description | type | required | default | producer |
+|---|---|:---:|:---:|:---:|:---:|
+| [gitlab_instance_config](variables.tf#L69) | Gitlab Compute Engine instance config. | object({…})
| ✓ | | |
+| [network_config](variables.tf#L89) | Shared VPC network configurations to use for Gitlab Runner VM. | object({…})
| ✓ | | |
+| [prefix](variables.tf#L98) | Prefix used for resource names. | string
| ✓ | | |
+| [project_id](variables.tf#L117) | Project id, references existing project if `project_create` is null. | string
| ✓ | | |
+| [region](variables.tf#L136) | GCP Region. | string
| ✓ | | |
+| [admin_principals](variables.tf#L17) | Users, groups and/or service accounts that are assigned roles, in IAM format (`group:foo@example.com`). | list(string)
| | []
| |
+| [cloudsql_config](variables.tf#L23) | Cloud SQL Postgres config. | object({…})
| | {}
| |
+| [gcs_config](variables.tf#L34) | GCS for Object Storage config. | object({…})
| | {}
| |
+| [gitlab_config](variables.tf#L45) | Gitlab configuration. | object({…})
| | {}
| |
+| [project_create](variables.tf#L108) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…})
| | null
| |
+| [redis_config](variables.tf#L122) | Redis Config. | object({…})
| | {}
| |
+
+## Outputs
+
+| name | description | sensitive | consumers |
+|---|---|:---:|---|
+| [gitlab_ilb_ip](outputs.tf#L26) | Gitlab Internal Load Balancer IP Address. | | |
+| [instance](outputs.tf#L31) | Gitlab compute engine instance. | | |
+| [postgresql_users](outputs.tf#L36) | Gitlab postgres user password. | ✓ | |
+| [project](outputs.tf#L42) | GCP project. | | |
+| [ssh_to_gitlab](outputs.tf#L47) | gcloud command to ssh gitlab instance. | | |
+| [ssl_certs](outputs.tf#L52) | Gitlab SSL Certificates. | ✓ | |
+
+## Test
+
+```hcl
+module "test" {
+ source = "./fabric/blueprints/third-party-solutions/gitlab"
+ gitlab_config = {
+ hostname = "gitlab.gcp.example.com"
+ mail = {
+ sendgrid = {
+ api_key = "sample_api_key"
+ }
+ }
+ saml = {
+ idp_cert_fingerprint = "67:90:96.....REPLACE_ME"
+ sso_target_url = "https://accounts.google.com/o/saml2/idp?idpid=REPLACE_ME"
+ }
+ }
+ gitlab_instance_config = {
+ replica_zone = "europe-west8-c"
+ zone = "europe-west8-b"
+ data_disk = {
+ replica_zone = "europe-west8-c"
+ }
+ }
+ network_config = {
+ host_project = "host-project"
+ network_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/global/networks/prod-landing-0"
+ subnet_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/regions/europe-west1/subnetworks/landing-default-ew1"
+ }
+ prefix = "prefix"
+ project_create = {
+ billing_account_id = "1234-ABCD-1234"
+ parent = "folders/1234563"
+ }
+ project_id = "my-project"
+ region = "europe-west8"
+}
+# tftest modules=14 resources=50
+```
diff --git a/blueprints/third-party-solutions/gitlab/TODO.md b/blueprints/third-party-solutions/gitlab/TODO.md
new file mode 100644
index 00000000..e6eae43e
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/TODO.md
@@ -0,0 +1,20 @@
+# Gitlab TODOs
+
+- Integrations
+ - [x] Identity
+ - [x] SAML
+ - [ ] Email:
+ - [ ] Gmail / Workspace
+ - [x] Sendgrid
+- [x] ILB
+- [ ] MIG
+- [ ] Gitaly
+- [x] HTTPS SSL
+- [x] Gitlab SSH on port 2222
+- [x] Check object store, use GCS wherever possible
+- [x] Cloud SQL HA
+- Memorystore
+ - [ ] HA
+ - [ ] PSC instead of PSA
+- [x] Integration with Cloud Logging for Gitlab running on Docker container
+- [ ] Integrate with Certificate Manager for SSH certificates
diff --git a/blueprints/third-party-solutions/gitlab/assets/cloud-config.yaml b/blueprints/third-party-solutions/gitlab/assets/cloud-config.yaml
new file mode 100644
index 00000000..cfce725e
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/assets/cloud-config.yaml
@@ -0,0 +1,118 @@
+#cloud-config
+
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# https://hub.docker.com/r/nginx/nginx/
+# https://nginx.io/manual/toc/#installation
+
+write_files:
+ - path: /var/lib/docker/daemon.json
+ permissions: '0644'
+ owner: root
+ content: |
+ {
+ "live-restore": true,
+ "storage-driver": "overlay2",
+ "log-driver": "gcplogs",
+ "log-opts": {
+ "gcp-meta-name": "gitlab-0",
+ "max-size": "1024m"
+ }
+ }
+ - path: /tmp/gitlab/config/gitlab.rb
+ permissions: '0600'
+ owner: root
+ content: |
+ ${gitlab_rb}
+ - path: /tmp/gitlab/ssl/${gitlab_cert_name}.key
+ permissions: '0600'
+ owner: root
+ content: |
+ ${gitlab_ssl_key}
+ - path: /tmp/gitlab/ssl/${gitlab_cert_name}.crt
+ permissions: '0600'
+ owner: root
+ content: |
+ ${gitlab_ssl_crt}
+ - path: /tmp/gitlab/sshd_config
+ permissions: '0644'
+ owner: root
+ content: |
+ ${gitlab_sshd_config}
+
+ - path: /etc/systemd/system/gitlab-data.service
+ permissions: '0644'
+ owner: root
+ content: |
+ [Unit]
+ Description=Gitlab data disk
+ ConditionPathExists=/dev/disk/by-id/google-data
+ Before=gitlab.service
+ [Service]
+ Type=oneshot
+ ExecStart=/bin/mkdir -p /run/gitlab
+ ExecStart=/bin/bash -c \
+ "/bin/lsblk -fn -o FSTYPE \
+ /dev/disk/by-id/google-data |grep ext4 \
+ || mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard \
+ /dev/disk/by-id/google-data"
+ ExecStart=/bin/bash -c \
+ "mount |grep /run/gitlab \
+ || mount -t ext4 /dev/disk/by-id/google-data /run/gitlab"
+ ExecStart=/sbin/resize2fs /dev/disk/by-id/google-data
+ ExecStart=/bin/mkdir -p /run/gitlab/config
+ ExecStart=/bin/mkdir -p /run/gitlab/ssl
+ ExecStart=/bin/mv /tmp/gitlab/config/gitlab.rb /run/gitlab/config/gitlab.rb
+ ExecStart=/bin/mv /tmp/gitlab/sshd_config /run/gitlab/sshd_config
+ ExecStart=/bin/bash -c "base64 -d -i /tmp/gitlab/ssl/${gitlab_cert_name}.key > /run/gitlab/ssl/${gitlab_cert_name}.key"
+ ExecStart=/bin/bash -c "base64 -d -i /tmp/gitlab/ssl/${gitlab_cert_name}.crt > /run/gitlab/ssl/${gitlab_cert_name}.crt"
+ RemainAfterExit=true
+
+ # https://docs.gitlab.com/ee/install/docker.html#pre-configure-docker-container
+
+ - path: /etc/systemd/system/gitlab.service
+ permissions: '0644'
+ owner: root
+ content: |
+ [Unit]
+ Description=Start gitlab container
+ After=gitlab-data.service gcr-online.target docker.socket
+ Wants=gitlab-data.service gcr-online.target docker.socket docker-events-collector.service
+ [Service]
+ Environment="HOME=/home/gitlab"
+ ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
+ ExecStartPre=mkdir -p /run/gitlab
+ ExecStart=/usr/bin/docker run --rm --name=gitlab \
+ --hostname ${gitlab_config.hostname} \
+ --shm-size 256m \
+ --env GITLAB_OMNIBUS_CONFIG="" \
+ --publish 443:443 \
+ --publish 80:80 \
+ --publish 2222:2222 \
+ -v /run/gitlab/config:/etc/gitlab \
+ -v /run/gitlab/ssl:/etc/gitlab/ssl \
+ -v /run/gitlab/logs:/var/log/gitlab \
+ -v /run/gitlab/data:/var/opt/gitlab \
+ -v /run/gitlab/sshd_config:/assets/sshd_config \
+ gitlab/gitlab-ce
+ ExecStop=/usr/bin/docker stop gitlab
+
+runcmd:
+ - systemctl start node-problem-detector
+ - iptables -I INPUT 1 -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
+ - iptables -I INPUT 1 -p tcp -m tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
+ - iptables -I INPUT 1 -p tcp -m tcp --dport 2222 -m state --state NEW,ESTABLISHED -j ACCEPT
+ - systemctl daemon-reload
+ - systemctl start gitlab
diff --git a/blueprints/third-party-solutions/gitlab/assets/config.rb.tpl b/blueprints/third-party-solutions/gitlab/assets/config.rb.tpl
new file mode 100644
index 00000000..8aaf0c5e
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/assets/config.rb.tpl
@@ -0,0 +1,118 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# /etc/gitlab/gitlab.rb
+
+external_url "https://${hostname}"
+letsencrypt['enable'] = false
+nginx['redirect_http_to_https'] = true
+
+# https://docs.gitlab.com/omnibus/settings/redis.html
+gitlab_rails['redis_enable_client'] = false
+gitlab_rails['redis_host'] = '${redis.host}'
+gitlab_rails['redis_port'] = ${redis.port}
+# TODO: use auth
+# gitlab_rails['redis_password'] = nil
+redis['enable'] = false
+
+# https://docs.gitlab.com/omnibus/settings/database.html#using-a-non-packaged-postgresql-database-management-server
+postgresql['enable'] = false
+gitlab_rails['db_adapter'] = 'postgresql'
+gitlab_rails['db_encoding'] = 'utf8'
+gitlab_rails['db_host'] = '${cloudsql.host}'
+gitlab_rails['db_port'] = 5432
+gitlab_rails['db_password'] = '${cloudsql.password}'
+
+# https://docs.gitlab.com/ee/administration/object_storage.html#google-cloud-storage-gcs
+# Consolidated object storage configuration
+gitlab_rails['object_store']['enabled'] = true
+gitlab_rails['object_store']['proxy_download'] = true
+gitlab_rails['object_store']['connection'] = {
+ 'provider' => 'Google',
+ 'google_project' => '${project_id}',
+ 'google_application_default' => true
+}
+# full example using the consolidated form
+# https://docs.gitlab.com/ee/administration/object_storage.html#full-example-using-the-consolidated-form-and-amazon-s3
+gitlab_rails['object_store']['objects']['artifacts']['bucket'] = '${prefix}-gitlab-artifacts'
+gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = '${prefix}-gitlab-mr-diffs'
+gitlab_rails['object_store']['objects']['lfs']['bucket'] = '${prefix}-gitlab-lfs'
+gitlab_rails['object_store']['objects']['uploads']['bucket'] = '${prefix}-gitlab-uploads'
+gitlab_rails['object_store']['objects']['packages']['bucket'] = '${prefix}-gitlab-packages'
+gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = '${prefix}-gitlab-dependency-proxy'
+gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = '${prefix}-gitlab-terraform-state'
+gitlab_rails['object_store']['objects']['pages']['bucket'] = '${prefix}-gitlab-pages'
+
+# SAML configuration
+# https://docs.gitlab.com/ee/integration/saml.html
+%{ if saml != null }
+gitlab_rails['omniauth_enabled'] = true
+gitlab_rails['omniauth_external_providers'] = ['saml']
+# create new user in case of sign in with SAML provider
+gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
+# do not force approval from admins for newly created users
+gitlab_rails['omniauth_block_auto_created_users'] = false
+# automatically link a first-time SAML sign-in with existing GitLab users if their email addresses match
+gitlab_rails['omniauth_auto_link_saml_user'] = true
+# Force user redirection to SAML
+# To bypass the auto sign-in setting, append ?auto_sign_in=false in the sign in URL, for example: https://gitlab.example.com/users/sign_in?auto_sign_in=false.
+%{ if saml.forced }
+gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml'
+%{ endif }
+# SHA1 Fingerprint
+gitlab_rails['omniauth_providers'] = [
+ {
+ name: "saml",
+ label: "SAML",
+ args: {
+ assertion_consumer_service_url: "https://${hostname}/users/auth/saml/callback",
+ idp_cert_fingerprint: '${saml.idp_cert_fingerprint}',
+ idp_sso_target_url: '${saml.sso_target_url}',
+ issuer: "https://${hostname}",
+ name_identifier_format: "${saml.name_identifier_format}"
+ }
+ }
+]
+%{ endif }
+
+
+# mail configuration
+%{ if mail.sendgrid != null }
+gitlab_rails['smtp_enable'] = true
+gitlab_rails['smtp_address'] = "smtp.sendgrid.net"
+gitlab_rails['smtp_port'] = 587
+gitlab_rails['smtp_user_name'] = "apikey"
+gitlab_rails['smtp_password'] = "${mail.sendgrid.api_key}"
+gitlab_rails['smtp_domain'] = "smtp.sendgrid.net"
+gitlab_rails['smtp_authentication'] = "plain"
+gitlab_rails['smtp_enable_starttls_auto'] = true
+gitlab_rails['smtp_tls'] = false
+# If use Single Sender Verification You must configure from. If not fail
+# 550 The from address does not match a verified Sender Identity. Mail cannot be sent until this error is resolved.
+# Visit https://sendgrid.com/docs/for-developers/sending-email/sender-identity/ to see the Sender Identity requirements
+%{ if try(mail.sendgrid.email_from != null, false) }
+gitlab_rails['gitlab_email_from'] = '${mail.sendgrid.email_from}'
+%{ endif }
+%{ if try(mail.sendgrid.email_reply_to != null, false) }
+gitlab_rails['email_reply_to'] = '${mail.sendgrid.email_reply_to}'
+%{ endif }
+%{ endif }
+
+
+gitlab_rails['gitlab_shell_ssh_port'] = 2222
+# gitlab_sshd['enable'] = true
+# gitlab_sshd['listen_address'] = '[::]:2222'
+
+# https://docs.gitlab.com/omnibus/installation/index.html#set-up-the-initial-password
+# gitlab_rails['initial_root_password'] = ''
\ No newline at end of file
diff --git a/blueprints/third-party-solutions/gitlab/assets/sshd_config b/blueprints/third-party-solutions/gitlab/assets/sshd_config
new file mode 100644
index 00000000..942dd5f8
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/assets/sshd_config
@@ -0,0 +1,27 @@
+Port 2222
+ChallengeResponseAuthentication no
+HostKey /etc/gitlab/ssh_host_rsa_key
+HostKey /etc/gitlab/ssh_host_ecdsa_key
+HostKey /etc/gitlab/ssh_host_ed25519_key
+Protocol 2
+PermitRootLogin no
+PasswordAuthentication no
+MaxStartups 100:30:200
+AllowUsers git
+PrintMotd no
+PrintLastLog no
+PubkeyAuthentication yes
+AuthorizedKeysFile %h/.ssh/authorized_keys /gitlab-data/ssh/authorized_keys
+AuthorizedKeysCommand /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k
+AuthorizedKeysCommandUser git
+
+# With "UsePAM yes" the "!" is seen as a password disabled account and not fully locked so ssh public key login works
+# Please make sure that the account is created without passwordlogin ("*" in /etc/shadow) or configure pam.
+# Issue #5891 https://gitlab.com/gitlab-org/omnibus-gitlab
+UsePAM no
+
+# Disabling use DNS in ssh since it tends to slow connecting
+UseDNS no
+
+# Enable the use of Git protocol v2
+AcceptEnv GIT_PROTOCOL
diff --git a/blueprints/third-party-solutions/gitlab/diagram.png b/blueprints/third-party-solutions/gitlab/diagram.png
new file mode 100644
index 00000000..d3f43ab0
Binary files /dev/null and b/blueprints/third-party-solutions/gitlab/diagram.png differ
diff --git a/blueprints/third-party-solutions/gitlab/gitlab.tf b/blueprints/third-party-solutions/gitlab/gitlab.tf
new file mode 100644
index 00000000..29ee4c5d
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/gitlab.tf
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+locals {
+ gitlab_rb = templatefile("${path.module}/assets/config.rb.tpl", {
+ project_id = module.project.project_id
+ cloudsql = {
+ host = module.db.instances.primary.private_ip_address
+ password = module.db.user_passwords.gitlab
+ }
+ mail = var.gitlab_config.mail
+ redis = {
+ host = google_redis_instance.cache.host
+ port = google_redis_instance.cache.port
+ }
+ prefix = var.prefix
+ saml = var.gitlab_config.saml
+ hostname = var.gitlab_config.hostname
+ })
+ gitlab_ssl_crt = local.self_signed_ssl_certs_required ? tls_locally_signed_cert.gitlab_server_singed_cert.0.cert_pem : file("${path.module}/certs/${var.gitlab_config.hostname}.crt")
+ gitlab_ssl_key = local.self_signed_ssl_certs_required ? tls_private_key.gitlab_server_key.0.private_key_pem : file("${path.module}/certs/${var.gitlab_config.hostname}.key")
+ gitlab_ssl_ca_crt = local.self_signed_ssl_certs_required ? tls_self_signed_cert.gitlab_ca_cert.0.cert_pem : file("${path.module}/certs/${var.gitlab_config.hostname}.ca.crt")
+ gitlab_ssl_ca_key = local.self_signed_ssl_certs_required ? tls_private_key.gitlab_ca_private_key.0.private_key_pem : ""
+ self_signed_ssl_certs_required = fileexists("${path.module}/certs/${var.gitlab_config.hostname}.crt") && fileexists("${path.module}/certs/${var.gitlab_config.hostname}.key") && fileexists("${path.module}/certs/${var.gitlab_config.hostname}.ca.crt") ? false : true
+ gitlab_user_data = templatefile("${path.module}/assets/cloud-config.yaml", {
+ gitlab_config = var.gitlab_config
+ gitlab_rb = indent(6, local.gitlab_rb)
+ gitlab_sshd_config = indent(6, file("${path.module}/assets/sshd_config"))
+ gitlab_cert_name = var.gitlab_config.hostname
+ gitlab_ssl_key = indent(6, base64encode(local.gitlab_ssl_key))
+ gitlab_ssl_crt = indent(6, base64encode(local.gitlab_ssl_crt))
+ })
+}
+
+module "gitlab-sa" {
+ source = "../../../modules/iam-service-account"
+ project_id = module.project.project_id
+ name = var.gitlab_instance_config.name
+ display_name = "Gitlab instance service account"
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = [module.gitlab-sa.iam_email]
+ }
+ iam_project_roles = {
+ (module.project.project_id) = [
+ "roles/logging.logWriter",
+ "roles/monitoring.metricWriter",
+ "roles/storage.admin"
+ ]
+ }
+}
+
+module "gitlab-instance" {
+ source = "../../../modules/compute-vm"
+ project_id = module.project.project_id
+ zone = var.gitlab_instance_config.zone
+ name = var.gitlab_instance_config.name
+ instance_type = var.gitlab_instance_config.instance_type
+ boot_disk = {
+ initialize_params = {
+ image = "projects/cos-cloud/global/images/family/cos-stable"
+ size = var.gitlab_instance_config.boot_disk.size
+ type = var.gitlab_instance_config.boot_disk.type
+ }
+ }
+ attached_disks = [
+ {
+ name = "data"
+ size = var.gitlab_instance_config.data_disk.size
+ type = var.gitlab_instance_config.data_disk.type
+ options = {
+ replica_zone = var.gitlab_instance_config.replica_zone
+ }
+ }
+ ]
+ network_interfaces = [
+ {
+ network = var.network_config.network_self_link
+ subnetwork = var.network_config.subnet_self_link
+ }
+ ]
+ tags = var.gitlab_instance_config.network_tags
+ metadata = {
+ user-data = local.gitlab_user_data
+ google-logging-enabled = "true"
+ }
+ service_account = {
+ email = module.gitlab-sa.email
+ }
+}
+
+module "ilb" {
+ source = "../../../modules/net-lb-int"
+ project_id = module.project.project_id
+ region = var.region
+ name = "ilb"
+ service_label = "ilb"
+ vpc_config = {
+ network = var.network_config.network_self_link
+ subnetwork = var.network_config.subnet_self_link
+ }
+ group_configs = {
+ gitlab = {
+ zone = var.gitlab_instance_config.zone
+ instances = [
+ module.gitlab-instance.self_link
+ ]
+ }
+ }
+ backends = [
+ { group = module.ilb.groups.gitlab.self_link }
+ ]
+ health_check_config = {
+ https = {
+ port = 443
+ }
+ }
+}
diff --git a/blueprints/third-party-solutions/gitlab/main.tf b/blueprints/third-party-solutions/gitlab/main.tf
new file mode 100644
index 00000000..054ea8fc
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/main.tf
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module "project" {
+ source = "../../../modules/project"
+ parent = try(var.project_create.parent, null)
+ billing_account = try(var.project_create.billing_account_id, null)
+ prefix = var.project_create == null ? null : var.prefix
+ name = var.project_id
+ project_create = var.project_create != null
+ services = [
+ "compute.googleapis.com",
+ "memcache.googleapis.com",
+ "redis.googleapis.com",
+ "sqladmin.googleapis.com",
+ "sql-component.googleapis.com",
+ "stackdriver.googleapis.com",
+ "dns.googleapis.com",
+ "iam.googleapis.com",
+ ]
+ shared_vpc_service_config = {
+ attach = true
+ host_project = var.network_config.host_project
+ service_identity_iam = {
+ "roles/compute.networkUser" = [
+ "cloudservices", "compute"
+ ]
+ }
+ network_users = var.admin_principals
+ }
+}
diff --git a/blueprints/third-party-solutions/gitlab/outputs.tf b/blueprints/third-party-solutions/gitlab/outputs.tf
new file mode 100644
index 00000000..e578f0fc
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/outputs.tf
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+locals {
+ ssl_certs = {
+ "${var.gitlab_config.hostname}.crt" = local.gitlab_ssl_crt
+ "${var.gitlab_config.hostname}.key" = local.gitlab_ssl_key,
+ "${var.gitlab_config.hostname}.ca.crt" = local.gitlab_ssl_ca_crt,
+ "${var.gitlab_config.hostname}.ca.key" = local.gitlab_ssl_ca_key
+ }
+}
+
+output "gitlab_ilb_ip" {
+ description = "Gitlab Internal Load Balancer IP Address."
+ value = module.ilb.forwarding_rule_addresses[""]
+}
+
+output "instance" {
+ description = "Gitlab compute engine instance."
+ value = module.gitlab-instance.instance
+}
+
+output "postgresql_users" {
+ description = "Gitlab postgres user password."
+ sensitive = true
+ value = module.db.user_passwords
+}
+
+output "project" {
+ description = "GCP project."
+ value = module.project
+}
+
+output "ssh_to_gitlab" {
+ description = "gcloud command to ssh gitlab instance."
+ value = nonsensitive("gcloud compute ssh ${module.gitlab-instance.instance.name} --project ${module.project.project_id} --zone ${module.gitlab-instance.instance.zone} -- -L 8080:127.0.0.1:80 -L 2222:127.0.0.1:2222 -L 8443:127.0.0.1:443 -N -q -f")
+}
+
+output "ssl_certs" {
+ description = "Gitlab SSL Certificates."
+ value = local.ssl_certs
+ sensitive = true
+}
diff --git a/blueprints/third-party-solutions/gitlab/services.tf b/blueprints/third-party-solutions/gitlab/services.tf
new file mode 100644
index 00000000..b5168be9
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/services.tf
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+locals {
+ gitlab_buckets = [
+ "gitlab-artifacts", "gitlab-mr-diffs", "gitlab-lfs", "gitlab-uploads",
+ "gitlab-packages", "gitlab-dependency-proxy", "gitlab-terraform-state",
+ "gitlab-pages"
+ ]
+}
+
+#######################################################################
+# GITLAB MANAGED SERVICES #
+#######################################################################
+
+# https://docs.gitlab.com/ee/install/requirements.html#database
+module "db" {
+ source = "../../../modules/cloudsql-instance"
+ project_id = module.project.project_id
+ region = var.region
+ name = var.cloudsql_config.name
+ availability_type = var.gitlab_config.ha_required ? "REGIONAL" : "ZONAL"
+ network_config = {
+ authorized_networks = {}
+ connectivity = {
+ psa_config = {
+ private_network = var.network_config.network_self_link
+ }
+ }
+ }
+ database_version = var.cloudsql_config.database_version
+ databases = [
+ "gitlabhq_production"
+ ]
+ tier = var.cloudsql_config.tier
+ users = {
+ # generate password for user1
+ gitlab = {
+ password = null
+ type = "BUILT_IN"
+ }
+ }
+}
+
+# https://docs.gitlab.com/ee/install/requirements.html#redis
+resource "google_redis_instance" "cache" {
+ project = module.project.project_id
+ region = var.region
+ name = var.redis_config.name
+ tier = var.redis_config.tier
+ memory_size_gb = var.redis_config.memory_size_gb
+ authorized_network = var.network_config.network_self_link
+ connect_mode = "PRIVATE_SERVICE_ACCESS"
+
+ redis_version = var.redis_config.version
+ display_name = "Gitlab Redis Instance"
+ persistence_config {
+ persistence_mode = var.redis_config.persistence_mode
+ rdb_snapshot_period = var.redis_config.rdb_snapshot_period
+ }
+}
+
+# https://docs.gitlab.com/ee/administration/object_storage.html#google-cloud-storage-gcs
+module "gitlab_object_storage" {
+ source = "../../../modules/gcs"
+ for_each = toset(local.gitlab_buckets)
+ project_id = module.project.project_id
+ prefix = var.prefix
+ name = each.key
+ storage_class = var.gcs_config.storage_class
+ location = var.gcs_config.location
+ versioning = var.gcs_config.enable_versioning
+ iam = {
+ "roles/storage.objectUser" = [
+ "serviceAccount:${module.gitlab-sa.email}",
+ ]
+ }
+}
diff --git a/blueprints/third-party-solutions/gitlab/ssl.tf b/blueprints/third-party-solutions/gitlab/ssl.tf
new file mode 100644
index 00000000..96dd7e3d
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/ssl.tf
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+locals {
+ cert_subjects = [
+ {
+ country = "IT"
+ province = "Lombardy"
+ locality = "Milan"
+ organization = "Example"
+ organizational_unit = "Example"
+ }
+ ]
+}
+
+#######################################################################
+# GITLAB CA PRIVATE KEY #
+#######################################################################
+
+resource "tls_private_key" "gitlab_ca_private_key" {
+ count = local.self_signed_ssl_certs_required ? 1 : 0
+ algorithm = "RSA"
+}
+
+#######################################################################
+# GITLAB CA CERT #
+#######################################################################
+
+resource "tls_self_signed_cert" "gitlab_ca_cert" {
+ count = local.self_signed_ssl_certs_required ? 1 : 0
+ private_key_pem = tls_private_key.gitlab_ca_private_key.0.private_key_pem
+ is_ca_certificate = true
+ dynamic "subject" {
+ for_each = toset(local.cert_subjects)
+ content {
+ country = subject.value.country
+ province = subject.value.province
+ locality = subject.value.locality
+ common_name = "Gitlab CA"
+ organization = subject.value.organization
+ organizational_unit = subject.value.organizational_unit
+ }
+ }
+ validity_period_hours = 43800 // 1825 days or 5 years
+ allowed_uses = [
+ "digital_signature",
+ "cert_signing",
+ "crl_signing",
+ ]
+}
+
+#######################################################################
+# SERVER CERT SIGNED BY CA #
+#######################################################################
+
+resource "tls_private_key" "gitlab_server_key" {
+ count = local.self_signed_ssl_certs_required ? 1 : 0
+ algorithm = "RSA"
+}
+
+# Create CSR for Gitlab Server certificate
+resource "tls_cert_request" "gitlab_server_csr" {
+ count = local.self_signed_ssl_certs_required ? 1 : 0
+ private_key_pem = tls_private_key.gitlab_server_key.0.private_key_pem
+ dns_names = [var.gitlab_config.hostname]
+
+ dynamic "subject" {
+ for_each = toset(local.cert_subjects)
+ content {
+ country = subject.value.country
+ province = subject.value.province
+ locality = subject.value.locality
+ common_name = "Gitlab"
+ organization = subject.value.organization
+ organizational_unit = subject.value.organizational_unit
+ }
+ }
+}
+
+resource "tls_locally_signed_cert" "gitlab_server_singed_cert" {
+ count = local.self_signed_ssl_certs_required ? 1 : 0
+ cert_request_pem = tls_cert_request.gitlab_server_csr.0.cert_request_pem
+ ca_private_key_pem = tls_private_key.gitlab_ca_private_key.0.private_key_pem
+ ca_cert_pem = tls_self_signed_cert.gitlab_ca_cert.0.cert_pem
+
+ validity_period_hours = 43800
+
+ allowed_uses = [
+ "digital_signature",
+ "key_encipherment",
+ "server_auth",
+ "client_auth",
+ ]
+}
diff --git a/blueprints/third-party-solutions/gitlab/terraform.tfvars.sample b/blueprints/third-party-solutions/gitlab/terraform.tfvars.sample
new file mode 100644
index 00000000..e76642af
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/terraform.tfvars.sample
@@ -0,0 +1,19 @@
+gitlab_config = {
+ hostname = "gitlab.gcp.example.com"
+ mail = {
+ sendgrid = {
+ api_key = "sample_api_key"
+ }
+ }
+ saml = {
+ idp_cert_fingerprint = "67:90:96.....REPLACE_ME"
+ sso_target_url = "https://accounts.google.com/o/saml2/idp?idpid=REPLACE_ME"
+ }
+}
+network_config = {
+ host_project = "host-project"
+ network_self_link = "network_self_link"
+ subnet_self_link = "subnetwork_self_link"
+}
+prefix = "prefix"
+project_id = "prod-gitlab-0"
\ No newline at end of file
diff --git a/blueprints/third-party-solutions/gitlab/variables.tf b/blueprints/third-party-solutions/gitlab/variables.tf
new file mode 100644
index 00000000..7d6d2445
--- /dev/null
+++ b/blueprints/third-party-solutions/gitlab/variables.tf
@@ -0,0 +1,139 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "admin_principals" {
+ description = "Users, groups and/or service accounts that are assigned roles, in IAM format (`group:foo@example.com`)."
+ type = list(string)
+ default = []
+}
+
+variable "cloudsql_config" {
+ description = "Cloud SQL Postgres config."
+ type = object({
+ name = optional(string, "gitlab-0")
+ database_version = optional(string, "POSTGRES_13")
+ tier = optional(string, "db-custom-2-8192")
+ })
+ default = {}
+ nullable = false
+}
+
+variable "gcs_config" {
+ description = "GCS for Object Storage config."
+ type = object({
+ enable_versioning = optional(bool, false)
+ location = optional(string, "EU")
+ storage_class = optional(string, "STANDARD")
+ })
+ default = {}
+ nullable = false
+}
+
+variable "gitlab_config" {
+ description = "Gitlab configuration."
+ type = object({
+ hostname = optional(string, "gitlab.gcp.example.com")
+ mail = optional(object({
+ enabled = optional(bool, false)
+ sendgrid = optional(object({
+ api_key = optional(string)
+ email_from = optional(string, null)
+ email_reply_to = optional(string, null)
+ }), null)
+ }), {})
+ saml = optional(object({
+ forced = optional(bool, false)
+ idp_cert_fingerprint = string
+ sso_target_url = string
+ name_identifier_format = optional(string, "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
+ }), null)
+ ha_required = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
+variable "gitlab_instance_config" {
+ description = "Gitlab Compute Engine instance config."
+ type = object({
+ instance_type = optional(string, "n1-highcpu-8")
+ name = optional(string, "gitlab-0")
+ network_tags = optional(list(string), [])
+ replica_zone = optional(string)
+ zone = optional(string)
+ boot_disk = optional(object({
+ size = optional(number, 20)
+ type = optional(string, "pd-standard")
+ }), {})
+ data_disk = optional(object({
+ size = optional(number, 100)
+ type = optional(string, "pd-ssd")
+ replica_zone = optional(string)
+ }), {})
+ })
+}
+
+variable "network_config" {
+ description = "Shared VPC network configurations to use for Gitlab Runner VM."
+ type = object({
+ host_project = optional(string)
+ network_self_link = string
+ subnet_self_link = string
+ })
+}
+
+variable "prefix" {
+ description = "Prefix used for resource names."
+ type = string
+ nullable = false
+ validation {
+ condition = var.prefix != ""
+ error_message = "Prefix cannot be empty."
+ }
+}
+
+variable "project_create" {
+ description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format."
+ type = object({
+ billing_account_id = string
+ parent = string
+ })
+ default = null
+}
+
+variable "project_id" {
+ description = "Project id, references existing project if `project_create` is null."
+ type = string
+}
+
+variable "redis_config" {
+ description = "Redis Config."
+ type = object({
+ memory_size_gb = optional(number, 1)
+ name = optional(string, "gitlab-0")
+ persistence_mode = optional(string, "RDB")
+ rdb_snapshot_period = optional(string, "TWELVE_HOURS")
+ tier = optional(string, "BASIC")
+ version = optional(string, "REDIS_6_X")
+ })
+ default = {}
+ nullable = false
+}
+
+variable "region" {
+ description = "GCP Region."
+ type = string
+}