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
Systemfor administrative functions orProjectfor repository-specific access (lines 88-91) - Action: REST-like verbs including
create,read,update,delete,list,pull, andpush(lines 21-38) - Resource: Logical objects such as
project,repository,artifact, androbot(lines 40-84) - Policy: A resource-action-effect triple (defaulting to
allow), stored in thePoliciesMapfor 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:
src/common/rbac/const.go— DefinesAction,Resource, scopes, and the built-inPoliciesMapfor system and project scopessrc/common/rbac/project/rbac_role.go— Maps role names to policy sets and implements theRBACRoleinterfacesrc/common/rbac/project/namespace.go— Encodes project ID into resource pathssrc/server/v2.0/handler/base.go— ContainsRequireProjectAccessandRequireSystemAccessfor API enforcementsrc/server/v2.0/handler/project.go— Exposes project member management endpointssrc/pkg/rbac/model/model.go— Database entities (RolePermission,PermissionPolicy) for persisting RBAC policies
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
RequireProjectAccessinsrc/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →