How to Set Up Role-Based Access Control (RBAC) in Harbor: A Complete Implementation Guide

Harbor implements role-based access control (RBAC) by mapping users and robot accounts to predefined roles that grant specific resource-action permissions within project namespaces, enforced through the RequireProjectAccess and RequireSystemAccess methods in the API handlers.

Harbor, the open-source container and artifact registry, provides a sophisticated RBAC system to secure your container images and helm charts. Understanding how to set up role-based access control (RBAC) in Harbor is essential for managing multi-team environments and ensuring least-privilege access to your projects. This guide explains the architecture based on the goharbor/harbor source code and provides practical steps to configure permissions.

Understanding Harbor's RBAC Architecture

Harbor's RBAC model uses a classic design where roles represent collections of policies (resource-action pairs) evaluated against user identities within specific project namespaces. The implementation distinguishes between System scope (admin-level) and Project scope (per-project access).

Core RBAC Components

The foundational definitions reside in src/common/rbac/const.go. This file establishes:

  • Scope: Either System for administrative functions or Project for repository-specific access (lines 88-91)
  • Action: REST-like verbs including create, read, update, delete, list, pull, and push (lines 21-38)
  • Resource: Logical objects such as project, repository, artifact, and robot (lines 40-84)
  • Policy: A resource-action-effect triple (defaulting to allow), stored in the PoliciesMap for both system and project scopes (lines 163-214)

Role Definitions and Mappings

Project-level roles are defined in src/common/rbac/project/rbac_role.go. The rolePoliciesMap associates five standard roles with specific policy sets:

  • projectAdmin (ID: 1)
  • maintainer (ID: 2)
  • developer (ID: 3)
  • guest (ID: 4)
  • limitedGuest (ID: 5)

Each role implements the RBACRole interface through the projectRBACRole struct, which builds a namespace for the target project using NewNamespace(projectID) and prefixes policies with that namespace (resource := namespace.Resource(policy.Resource)) as implemented in lines 40-47.

Namespace Resolution

Resource isolation depends on namespace encoding implemented in src/common/rbac/project/namespace.go (lines 54-57). A project namespace encodes the project ID into the resource path (e.g., /project/123/repository), ensuring policies apply only to specific projects. System-wide resources use the namespace implementation in src/common/rbac/system/namespace.go.

Configuring RBAC in Harbor

Setting up role-based access control involves creating projects, assigning members to roles, and optionally configuring robot accounts with scoped permissions.

Step 1: Create a Project

First, establish a project namespace to contain your repositories:

curl -u admin:Admin123 -X POST "https://harbor.example.com/api/v2.0/projects" \
     -H "Content-Type: application/json" \
     -d '{"project_name":"myproj","public":false}'

This creates a private project that serves as the boundary for your RBAC policies.

Step 2: Assign Members to Roles

Add users to the project with specific role IDs defined in src/common/role/role.go. The API expects integer IDs: 1 for projectAdmin, 2 for maintainer, 3 for developer, 4 for guest, and 5 for limitedGuest.

To assign developer permissions (ID: 3) to user ID 42:

curl -u admin:Admin123 -X POST "https://harbor.example.com/api/v2.0/projects/1/members" \
     -H "Content-Type: application/json" \
     -d '{
           "role_id": 3,
           "member_user": {"user_id": 42}
         }'

The handlers in src/server/v2.0/handler/project.go process these requests, while src/server/v2.0/handler/base.go provides RequireProjectAccess (lines 102-109 and 126-136) to validate the requesting user holds the necessary role permissions.

Step 3: Configure Robot Accounts with Scoped Permissions

For CI/CD pipelines, create robot accounts with granular permissions. Robot accounts can receive system-level policies appended through providers like NolimitProvider, as referenced in src/common/rbac/const.go (lines 119-128).

Create a robot account with pull and push access to project 1:

curl -u admin:Admin123 -X POST "https://harbor.example.com/api/v2.0/projects/1/robots" \
     -H "Content-Type: application/json" \
     -d '{
           "name": "ci-bot",
           "access": [
             {"resource": "/project/1/repository", "action": "pull"},
             {"resource": "/project/1/repository", "action": "push"}
           ]
         }'

Step 4: Validate Access Controls

Verify your RBAC configuration by attempting operations that require specific permissions. The enforcement occurs in src/server/v2.0/handler/base.go through methods like RequireProjectAccess, which builds the full resource path via the namespace and delegates to the security context (secCtx.Can).

A 403 Forbidden response indicates the user lacks the required policy in their role, while successful execution confirms proper RBAC setup.

Programmatic RBAC Management

For automated workflows, Harbor's Go SDK provides type-safe access to the RBAC APIs.

Adding Project Members via Go SDK

The following example demonstrates adding a developer role using the Harbor Go client:

import (
    "github.com/go-openapi/runtime/client"
    "github.com/goharbor/harbor/src/server/v2.0/client/project"
    "github.com/goharbor/harbor/src/server/v2.0/client/operations"
)

// Authenticate to Harbor
auth := client.BasicAuth("admin", "Admin123")
transport := client.New("harbor.example.com", "/api/v2.0", []string{"https"})
transport.DefaultAuthentication = auth

// Add developer role (3) for user ID 42 to project 1
payload := &project.AddProjectMemberParams{
    ProjectID: 1,
    Member: &models.Member{
        RoleID:    3,
        MemberUser: &models.User{UserID: 42},
    },
}
_, err := operations.NewAddProjectMember(transport, nil).AddProjectMember(payload)
if err != nil { log.Fatalf("add member failed: %v", err) }

Internal Policy Lookup

Internally, Harbor evaluates permissions by retrieving policies for a given role and prefixing them with the project namespace:

// role := &projectRBACRole{projectID: 1, roleID: common.RoleDeveloper}
// policies := role.GetPolicies() 
// Returns []*types.Policy with namespace-prefixed resources like "/project/1/repository"

The GetPolicies method defined in src/common/rbac/project/rbac_role.go (lines 24-46) returns the policy set associated with the role ID, enabling the RBAC evaluator to check against the requested resource and action.

Key Source Files for RBAC Implementation

Understanding these files from the goharbor/harbor repository clarifies the complete authorization flow:

Summary

  • Harbor RBAC operates on a scope-based model distinguishing between System and Project levels, defined in src/common/rbac/const.go
  • Five standard project roles (projectAdmin, maintainer, developer, guest, limitedGuest) map to specific policy sets in src/common/rbac/project/rbac_role.go
  • Namespace isolation ensures policies apply only to specific projects through path encoding in src/common/rbac/project/namespace.go
  • API enforcement occurs via RequireProjectAccess in src/server/v2.0/handler/base.go, which evaluates the security context against namespace-prefixed resources
  • Role IDs for API calls correspond to: 1 (projectAdmin), 2 (maintainer), 3 (developer), 4 (guest), and 5 (limitedGuest)
  • Robot accounts support granular, scoped permissions for automated systems without human user accounts

Frequently Asked Questions

What are the default role IDs in Harbor's RBAC system?

Harbor assigns integer IDs to project roles as defined in src/common/role/role.go: 1 for projectAdmin, 2 for maintainer, 3 for developer, 4 for guest, and 5 for limitedGuest. When using the API to add members, you must specify these numeric IDs rather than string names.

How does Harbor isolate resources between projects?

Harbor uses namespaces to scope resources, implemented in src/common/rbac/project/namespace.go. The system encodes the project ID into the resource path (e.g., /project/123/repository), ensuring that policies granted to a user in project 123 cannot access resources in project 456. The projectRBACRole struct automatically prefixes all policies with the project namespace before evaluation.

Where does Harbor enforce RBAC checks in the API layer?

API handlers invoke RequireProjectAccess or RequireSystemAccess from src/server/v2.0/handler/base.go (lines 102-109 and 126-136). These methods build the fully qualified resource using the namespace helper, then delegate to the security context's Can method to verify the user possesses a role containing the required policy.

Can robot accounts have different permissions than human users?

Yes, robot accounts support scoped permissions through the robot permission provider system. According to src/common/rbac/const.go, robot accounts can receive additional system-level policies (lines 119-128). When creating a robot account via the API, you specify explicit resource-action pairs (such as pull and push on specific repositories), allowing more granular access than standard human roles.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →