390 lines
22 KiB
Markdown
390 lines
22 KiB
Markdown
# 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:
|
||
|
||
<p align="center">
|
||
<img src="diagram.png" alt="Gitlab">
|
||
</p>
|
||
|
||
## Table of contents
|
||
|
||
<!-- TOC -->
|
||
* [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)
|
||
<!-- TOC -->
|
||
|
||
## 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.<br/><br/>
|
||
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.<br/><br/>
|
||
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://<GITLAB_DOMAIN>/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 <your_certificate.crt> -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)
|
||
|
||
<!-- TFDOC OPTS files:1 show_extra:1 -->
|
||
<!-- BEGIN TFDOC -->
|
||
## Files
|
||
|
||
| name | description | modules | resources |
|
||
|---|---|---|---|
|
||
| [gitlab.tf](./gitlab.tf) | None | <code>compute-vm</code> · <code>iam-service-account</code> · <code>net-lb-int</code> | |
|
||
| [main.tf](./main.tf) | Module-level locals and resources. | <code>project</code> | |
|
||
| [outputs.tf](./outputs.tf) | Module outputs. | | |
|
||
| [services.tf](./services.tf) | None | <code>cloudsql-instance</code> · <code>gcs</code> | <code>google_redis_instance</code> |
|
||
| [ssl.tf](./ssl.tf) | None | | <code>tls_cert_request</code> · <code>tls_locally_signed_cert</code> · <code>tls_private_key</code> · <code>tls_self_signed_cert</code> |
|
||
| [variables.tf](./variables.tf) | Module variables. | | |
|
||
|
||
## Variables
|
||
|
||
| name | description | type | required | default | producer |
|
||
|---|---|:---:|:---:|:---:|:---:|
|
||
| [gitlab_instance_config](variables.tf#L69) | Gitlab Compute Engine instance config. | <code title="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) }), {}) })">object({…})</code> | ✓ | | |
|
||
| [network_config](variables.tf#L89) | Shared VPC network configurations to use for Gitlab Runner VM. | <code title="object({ host_project = optional(string) network_self_link = string subnet_self_link = string })">object({…})</code> | ✓ | | |
|
||
| [prefix](variables.tf#L98) | Prefix used for resource names. | <code>string</code> | ✓ | | |
|
||
| [project_id](variables.tf#L117) | Project id, references existing project if `project_create` is null. | <code>string</code> | ✓ | | |
|
||
| [region](variables.tf#L136) | GCP Region. | <code>string</code> | ✓ | | |
|
||
| [admin_principals](variables.tf#L17) | Users, groups and/or service accounts that are assigned roles, in IAM format (`group:foo@example.com`). | <code>list(string)</code> | | <code>[]</code> | |
|
||
| [cloudsql_config](variables.tf#L23) | Cloud SQL Postgres config. | <code title="object({ name = optional(string, "gitlab-0") database_version = optional(string, "POSTGRES_13") tier = optional(string, "db-custom-2-8192") })">object({…})</code> | | <code>{}</code> | |
|
||
| [gcs_config](variables.tf#L34) | GCS for Object Storage config. | <code title="object({ enable_versioning = optional(bool, false) location = optional(string, "EU") storage_class = optional(string, "STANDARD") })">object({…})</code> | | <code>{}</code> | |
|
||
| [gitlab_config](variables.tf#L45) | Gitlab configuration. | <code title="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) })">object({…})</code> | | <code>{}</code> | |
|
||
| [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. | <code title="object({ billing_account_id = string parent = string })">object({…})</code> | | <code>null</code> | |
|
||
| [redis_config](variables.tf#L122) | Redis Config. | <code title="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") })">object({…})</code> | | <code>{}</code> | |
|
||
|
||
## 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. | ✓ | |
|
||
<!-- END TFDOC -->
|
||
## 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
|
||
```
|