Enable secure sudo access for GitLab Remote Development workspaces

1 month ago 13
News Banner

Looking for an Interim or Fractional CTO to support your business?

Read more

A development environment often requires sudo permissions to install, configure, and use dependencies during runtime. GitLab now allows secure sudo access for GitLab Remote Development workspaces. This tutorial shows you how to enable GitLab workspace users to securely use sudo commands to perform common tasks.

The challenge

For the sake of this article, say your project is as simple as the below code.

package main import ( "encoding/json" "log/slog" "net/http" "os" ) func main() { // Set up JSON logger logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { panic(err) } defer logFile.Close() jsonHandler := slog.NewJSONHandler(logFile, nil) logger := slog.New(jsonHandler) slog.SetDefault(logger) // Define handlers http.HandleFunc("/path1", handleRequest) http.HandleFunc("/path2", handleRequest) // Start server slog.Info("Starting server on :3000") err = http.ListenAndServe(":3000", nil) if err != nil { slog.Error("Server failed to start", "error", err) } } func handleRequest(w http.ResponseWriter, r *http.Request) { data := make(map[string]interface{}) for k, v := range r.Header { data[k] = v } data["method"] = r.Method data["url"] = r.URL.String() data["remote_addr"] = r.RemoteAddr response, err := json.MarshalIndent(data, "", " ") if err != nil { slog.Error("Failed to marshal metadata", "error", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } // Log the metadata slog.Info("Request received", "path", r.URL.Path, "response", string(response), ) // Write response w.Header().Set("Content-Type", "application/json") w.Write(response) }

This code starts an HTTP server on port 3000, exposes two paths: path1 and path2. Each HTTP request received is logged to a file server.log.

Let's run this code with go run main.go and generate some requests.

i=1 while [ "$i" -le 100 ]; do echo "Iteration $i" if [ $((random_number % 2)) -eq 0 ]; then curl "localhost:3000/path1" else curl "localhost:3000/path2" fi i=$((i + 1)) done

As you work on this application, you realize the need to analyze the logs to debug an issue. You look at the log file and it is long to parse with a simple glance. You remember there is a handy tool, jq, which parses JSON data. But your workspace does not have it installed.

You want to install jq through the package manager for this workspace only.

sudo apt update sudo apt install jq

The output is:

sudo: The "no new privileges" flag is set, which prevents sudo from running as root. sudo: If sudo is running in a container, you may need to adjust the container configuration to disable the flag.

This happens because GitLab workspaces explicitly disallows sudo access to prevent privilege escalation on the Kubernetes host.

Now, there is a more secure way to run sudo commands in a workspace.

How sudo access works

That is exactly what we have unlocked in the 17.4 release of GitLab.

You can configure secure sudo access for workspaces using any of the following options:

  • Sysbox
  • Kata Containers
  • User namespaces

We will set up three GitLab agents for workspaces to demonstrate each option.

Sysbox

Sysbox is a container runtime that improves container isolation and enables containers to run the same workloads as virtual machines.

To configure sudo access for a workspace with Sysbox:

  1. In the Kubernetes cluster, install Sysbox.
  2. In the GitLab agent for workspaces, set the following config:
remote_development: enabled: true dns_zone: "sysbox-update.me.com" default_runtime_class: "sysbox-runc" allow_privilege_escalation: true
  1. Add other settings in the agent config as per your requirements. GitLab agent for workspaces settings for more information about individual settings.
  2. Allow the agent to be used for workspaces in a group. See the documentation for more information.
  3. Update GitLab Workspaces Proxy to serve traffic for the domain used in the above agent configuration. See Tutorial: Set up the GitLab workspaces proxy for more information.

Kata Containers

Kata Containers is a standard implementation of lightweight virtual machines that perform like containers but provide the workload isolation and security of virtual machines.

To configure sudo access for a workspace with Kata Containers:

  1. In the Kubernetes cluster, install Kata Containers.
  2. In the GitLab agent for workspaces, set the following config:
remote_development: enabled: true dns_zone: "kata-update.me.com" default_runtime_class: "kata-qemu" allow_privilege_escalation: true
  1. Add other settings in the agent config as per your requirements. GitLab agent for workspaces settings for more information about individual settings.
  2. Allow the agent to be used for workspaces in a group. See the documentation for more information.
  3. Update GitLab Workspaces Proxy to serve traffic for the domain used in the above agent configuration. See Tutorial: Set up the GitLab workspaces proxy for more information.

User namespaces

User namespaces isolate the user running inside the container from the user on the host.

To configure sudo access for a workspace with user namespaces:

  1. In the Kubernetes cluster, configure user namespaces.
  2. In the GitLab agent for workspaces, set the following config:
remote_development: enabled: true dns_zone: "userns-update.me.com" use_kubernetes_user_namespaces: true allow_privilege_escalation: true
  1. Add other settings in the agent config as per your requirements. GitLab agent for workspaces settings for more information about individual settings.
  2. Allow the agent to be used for workspaces in a group. See the documentation for more information.
  3. Update GitLab Workspaces Proxy to serve traffic for the domain used in the above agent configuration. See Tutorial: Set up the GitLab workspaces proxy for more information.

Setting up a Kubernetes cluster with user namespaces configured is challenging since it is behind a beta feature gate in Kubernetes Version 1.31.0. This means it is not yet possible to configure such a cluster on the major cloud providers because they don't provide a mechanism to enable feature gates in their managed Kubernetes offering. Here is an example of configuring a simple Kuberenetes cluster using kubeadm.

Create a workspace

If you now create a workspace with these agents and try installing jq through a package manager, it should succeed!

You can analyze the logs using jq. Say you wanted to inspect the log entries where the path is /path1, you can run:

jq 'select(.path == "/path1")' server.log

The output is:

{ "time": "2024-10-31T12:04:38.474806+05:30", "level": "INFO", "msg": "Request received", "path": "/path1", "response": "{\n \"Accept\": [\n \"*/*\"\n ],\n \"User-Agent\": [\n \"curl/8.7.1\"\n ],\n \"method\": \"GET\",\n \"remote_addr\": \"[::1]:61246\",\n \"url\": \"/path1\"\n}" } { "time": "2024-10-31T12:06:22.397453+05:30", "level": "INFO", "msg": "Request received", "path": "/path1", "response": "{\n \"Accept\": [\n \"*/*\"\n ],\n \"User-Agent\": [\n \"curl/8.7.1\"\n ],\n \"method\": \"GET\",\n \"remote_addr\": \"[::1]:61311\",\n \"url\": \"/path1\"\n}" } { "time": "2024-10-31T12:19:34.974354+05:30", "level": "INFO", "msg": "Request received", "path": "/path1", "response": "{\n \"Accept\": [\n \"*/*\"\n ],\n \"User-Agent\": [\n \"curl/8.7.1\"\n ],\n \"method\": \"GET\",\n \"remote_addr\": \"[::1]:61801\",\n \"url\": \"/path1\"\n}" }

Get started today

Learn even more with our Configure sudo access for a workspace documentation. See GitLab agent for workspaces settings for details on individual settings.

New to GitLab Remote Development? Here is a quickstart guide to get you up to speed.

Read Entire Article