Day-2 | Groups, Projects & RBAC | 30 Days Of GitLab DevOps
This module explores the core organizational units of GitLab: Groups, Subgroups, and Projects, alongside Role-Based Access Control (RBAC). You will learn how to design an enterprise-grade repository structure, manage permissions efficiently through inheritance, and automate the creation of complex nested hierarchies using the GitLab REST API and Bash scripting.
1. Demystifying the GitLab Project
A common misconception among beginners is that a GitLab project is merely a Git source code repository. In reality, a GitLab project is an all-in-one, end-to-end DevOps platform. It integrates version control with planning, execution, security, and deployment tools.
Every project you create contains five core pillars:
- Git Repository: Houses the actual source code, branches, commit history, and tags.
- CI/CD Engine: Executes automated pipelines defined in a
.gitlab-ci.ymlfile. - Issue Tracker: Serves as a work-tracking platform (similar to Jira) to manage bugs, feature requests, and milestones.
- Merge Request (MR) Workflows: Facilitates code reviews, discussions, and automated checks before merging code from a feature branch into the default branch.
- Environments & Deployments: Tracks where code is deployed (e.g., Development, Staging, Production) and manages deployment history.
2. The Three Core Project Types in Enterprise DevOps
In an enterprise environment, projects are categorized by their function. Organizations typically divide their work into three distinct project types:
Application Projects
These projects contain the functional source code of the application. Examples include a Node.js Express frontend, a Java Spring Boot backend, or a Python microservice. Each application project runs its own build, test, and package pipelines.
Infrastructure Projects
These projects manage Infrastructure as Code (IaC) and configuration files. They store Terraform configurations, Helm charts, Ansible playbooks, or Kubernetes YAML manifests. These projects enable GitOps workflows, where changes to infrastructure are reviewed and applied via CI/CD pipelines.
Configuration Projects
These projects act as centralized utility repositories. They store shared, reusable CI/CD pipeline templates, custom scripts, and shared libraries. Other projects reference these centralized templates to avoid code duplication across pipelines.
3. Architectural Best Practices: Monolith vs. Microservice Repositories
When building an application (such as an e-commerce platform), you must decide how to structure your repositories.
The Naive Approach (Mono-repository Folders)
A single repository contains folders for every service:
- The Problem: A change in the
email-servicefolder triggers the entire repository's pipeline unless complex path-filtering rules are written. Access control is difficult to restrict; a developer working only on email notifications must be granted access to the entire repository, including sensitive payment code.
The Production-Ready Approach (Multi-project Microservices)
Create a separate GitLab project for each microservice:
- The Solution: Each microservice has an independent lifecycle, its own CI/CD pipeline, isolated access controls, and dedicated deployment environments.
4. Understanding GitLab Groups and Namespaces
A Group in GitLab is a logical namespace used to organize related projects. It acts as a folder structure that can hold projects, other subgroups, or a combination of both.
Groups solve the problem of workspace clutter. Instead of having hundreds of disconnected projects on a flat dashboard, groups allow you to assemble projects by department, product line, or technical layer.
5. Centralized Access Control & Shared Resources
Groups provide two major operational advantages: Centralized Access Control and Shared Resource Management.
Centralized Access Control (Inheritance)
Instead of manually adding users and assigning permissions to 20 different projects, you can assign user permissions at the Group level.
Shared Resource Management
Groups allow you to define resources once and share them across all child projects:
- Shared Runners: Register a CI/CD runner at the group level. Every project inside that group can run its pipelines on this runner without individual configuration.
- Group Variables: Define sensitive credentials (like AWS keys or database passwords) at the group level. They are securely passed to all child pipelines.
- Shared CI/CD Templates: Store common pipeline steps at the group level to enforce compliance across all projects.
6. Comparative Analysis: Managing GitLab With vs. Without Groups
7. Designing an Enterprise-Grade Group & Subgroup Hierarchy
The diagram below illustrates a production-ready hierarchy for an e-commerce application. It separates concerns by technical layer and restricts access based on team roles.
8. GitLab RBAC (Role-Based Access Control) Deep Dive
GitLab uses a strict Role-Based Access Control (RBAC) model. The table below details the five core roles used in enterprise workflows.
9. Real-World Role Mapping & Least Privilege Principles
To maintain a secure environment, apply the Principle of Least Privilege (PoLP). Assign users the minimum level of access necessary to complete their work.
- Development Team: Assigned the Developer role on application subgroups so they can write code and run test pipelines without altering infrastructure settings.
- SRE & Platform Team: Assigned the Maintainer role on the
infrasubgroup to manage environments, modify CI/CD variables, and apply Terraform configurations. - Security Team: Assigned the Reporter role across all groups to audit code and monitor pipelines without write access.
- Billing & Executives: Assigned the Guest role at the parent group level to view high-level issue boards and financial dashboards.
10. Step-by-Step UI Walkthrough: Building the E-Commerce Hierarchy
This guide walks you through manually creating the e-commerce group structure, importing external code, and configuring permission inheritance using the GitLab User Interface.
Step 1: Create the Parent Group
- Log in to your GitLab account.
- Click the
+(Plus) icon in the top navigation bar and select New group. - Select Create group.
- Enter the Group name:
ecom-microservice. - Set the Visibility level to Private.
- Click Create group.
Step 2: Create Subgroups
- Inside the
ecom-microservicegroup page, click New subgroup. - Name the subgroup
front-endand set its visibility to Private. Click Create subgroup. - Navigate back to the parent group and repeat the process to create the
back-endandinfrasubgroups.
Step 3: Create Projects from Templates
- Navigate to the
front-endsubgroup. - Click New project -> Create from template.
- Locate the NodeJS Express template and click Use template.
- Name the project
client-frontendand click Create project. - Navigate to the
back-endsubgroup, click New project -> Create from template, select the Spring template, name itbackend-source-code, and click Create project.
Step 4: Import an External Infrastructure Project
- Navigate to the
infrasubgroup. - Click New project -> Import project.
- Select Repository by URL.
- Enter the Git repository URL (e.g., an external GitHub repository containing Terraform code):
https://github.com/example/eks-terraform-code.git - Name the project
EKS Terraform Code, set the visibility to Private, and click Create project.
Step 5: Verify Permission Inheritance
- Go to the parent group
ecom-microserviceand select Manage -> Members from the left sidebar. - Click Invite members, enter a colleague's email, select the Developer role, and click Invite.
- Navigate to the nested
client-frontendproject and check its Members page. You will see the invited user listed with the Developer role, marked as an inherited membership. - To isolate access, add a user directly to the
infrasubgroup as a Maintainer. This user will have administrative access to the infrastructure repositories but will not see or access thefront-endorback-endsubgroups.
11. Automating GitLab Hierarchy with Bash & GitLab REST API
For large organizations, manually creating groups and projects via the UI is inefficient and error-prone. You can automate this process using the GitLab REST API and a Bash script.
Step 1: Retrieve the Parent Group ID
- Navigate to your parent group page in the GitLab UI.
- Under the group name, locate and copy the numeric Group ID (e.g.,
98765432).
Step 2: Generate a Personal Access Token (PAT)
- Click your profile picture in the top-left corner and select Preferences.
- Select Access Tokens from the left sidebar.
- Click Add new token.
- Name the token
Git Bash API Token. - Select the
apiscope (grants complete read/write access to the API). - Click Create personal access token and copy the generated token immediately. You will not be able to see it again.
Step 3: The Automation Script
Create a file named create-gitlab-structure.sh on your local machine and paste the following script. This script uses curl to interact with the GitLab API, creating subgroups and projects automatically.
#!/usr/bin/env bash
# Exit immediately if a command exits with a non-zero status
set -e
# ==============================================================================
# CONFIGURATION
# ==============================================================================
GITLAB_URL="https://gitlab.com/api/v4"
PRIVATE_TOKEN="YOUR_PERSONAL_ACCESS_TOKEN" # Replace with your PAT
PARENT_GROUP_ID="YOUR_PARENT_GROUP_ID" # Replace with your Parent Group ID
# ==============================================================================
# HELPER FUNCTIONS
# ==============================================================================
# Function to create a subgroup
create_subgroup() {
local name=$1
local path=$2
echo "Creating subgroup: ${name}..."
response=$(curl --silent --request POST "${GITLAB_URL}/groups" \
--header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"name\": \"${name}\",
\"path\": \"${path}\",
\"parent_id\": ${PARENT_GROUP_ID},
\"visibility\": \"private\"
}")
# Extract and return the newly created subgroup ID
echo "$response" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2
}
# Function to create a project inside a subgroup
create_project() {
local name=$1
local namespace_id=$2
echo "Creating project: ${name} inside namespace: ${namespace_id}..."
curl --silent --request POST "${GITLAB_URL}/projects" \
--header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"name\": \"${name}\",
\"namespace_id\": ${namespace_id},
\"visibility\": \"private\",
\"initialize_with_readme\": true
}" > /dev/null
}
# ==============================================================================
# EXECUTION FLOW
# ==============================================================================
echo "Starting automated GitLab structure creation..."
# 1. Create Subgroups
FRONTEND_SUBGROUP_ID=$(create_subgroup "Frontend Team" "front-end")
echo "Frontend Subgroup ID: ${FRONTEND_SUBGROUP_ID}"
BACKEND_SUBGROUP_ID=$(create_subgroup "Backend Team" "back-end")
echo "Backend Subgroup ID: ${BACKEND_SUBGROUP_ID}"
INFRA_SUBGROUP_ID=$(create_subgroup "Infrastructure Team" "infra")
echo "Infrastructure Subgroup ID: ${INFRA_SUBGROUP_ID}"
# 2. Create Projects inside Frontend Subgroup
create_project "web-app" "${FRONTEND_SUBGROUP_ID}"
# 3. Create Projects inside Backend Subgroup
create_project "auth-service" "${BACKEND_SUBGROUP_ID}"
create_project "payment-service" "${BACKEND_SUBGROUP_ID}"
create_project "order-service" "${BACKEND_SUBGROUP_ID}"
# 4. Create Projects inside Infrastructure Subgroup
create_project "terraform-provisioning" "${INFRA_SUBGROUP_ID}"
create_project "kubernetes-manifests" "${INFRA_SUBGROUP_ID}"
echo "GitLab structure created successfully!"
Step 4: Run the Script
Open Git Bash (or your Linux/macOS terminal), make the script executable, and run it:
chmod +x create-gitlab-structure.sh
./create-gitlab-structure.sh
Navigate back to your GitLab dashboard. The entire nested structure, complete with initialized README files inside each project, is now ready for use.
12. Summary and Key Takeaways
- A Project is an Ecosystem: A GitLab project is not just a Git repository; it integrates issue tracking, CI/CD pipelines, merge requests, and environment management.
- Decouple Microservices: Avoid storing multiple microservices in folders within a single repository. Create a dedicated GitLab project for each microservice to ensure independent pipelines and isolated access controls.
- Groups Provide Structure: Use groups and subgroups to organize projects logically by department, product line, or technical layer.
- Leverage Permission Inheritance: Assign user permissions at the group level. These permissions automatically cascade down to all subgroups and projects, reducing administrative overhead.
- Share Resources Efficiently: Register runners, define environment variables, and store CI/CD templates at the group level to share them across all child projects.
- Enforce Least Privilege: Use GitLab's RBAC roles (Guest, Reporter, Developer, Maintainer, Owner) to restrict access. Developers should write code, SREs should manage infrastructure, and auditors should have read-only access.
- Automate Workspace Setup: Use the GitLab REST API and Bash scripts to automate workspace creation. This ensures consistent, repeatable, and error-free configurations across your organization.