# How to Manage Projects and Access Control in Harbor: Complete RBAC Implementation

> Learn to manage projects and access control in Harbor with a complete RBAC implementation. Enforce permissions effectively using policy maps for enhanced security.

- Repository: [Harbor/harbor](https://github.com/goharbor/harbor)
- Tags: how-to-guide
- Published: 2026-04-09

---

**Harbor isolates container repositories into projects protected by role-based access control (RBAC), enforcing permissions through policy maps defined in [`src/common/rbac/project/rbac_role.go`](https://github.com/goharbor/harbor/blob/main/src/common/rbac/project/rbac_role.go) that grant specific actions to roles like projectAdmin, maintainer, and developer.**

Harbor organizes registries into logical units called projects. According to the goharbor/harbor source code, these projects function as isolated namespaces where access control policies determine exactly which users, groups, or robot accounts can perform operations on repositories, tags, and member configurations.

## Harbor Project Architecture and Data Model

### Core Project Structure

The fundamental project definition resides in **[`src/pkg/project/models/project.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/project/models/project.go)**. This struct contains the primary fields that define a project:

- **`ProjectID`** – The primary key for database operations
- **`OwnerID`** – References the user who owns the project, typically a system administrator
- **`Name`** – The unique, lowercase project identifier validated by [`project/manager.go`](https://github.com/goharbor/harbor/blob/main/project/manager.go) using the regular expression `^[a-z0-9]+(?:[._-][a-z0-9]+)*$`
- **`Metadata`** – A key-value map storing configuration flags including `public`, `enable_content_trust`, and `proxy_speed_kb`
- **`RegistryID`** – Non-zero values indicate proxy-cache projects that mirror external registries

### Project Lifecycle Management

All project CRUD operations route through the **Project controller** at **[`src/server/v2.0/handler/project.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/project.go)**.

The `CreateProject` handler validates incoming requests against the name regex, checks the system-level configuration `OnlyAdminCreateProject` to determine if creation is restricted to administrators, injects default storage quota policies, and finally delegates persistence to `project.Ctl.Create`.

For deletion, the `DeleteProject` handler first validates the requester's permissions through the RBAC layer before invoking `project.Ctl.Delete` to remove the project and associated resources.

## RBAC Roles and Permission Policies

### Role Definitions and Policy Maps

Harbor's RBAC engine lives in **[`src/common/rbac/project/rbac_role.go`](https://github.com/goharbor/harbor/blob/main/src/common/rbac/project/rbac_role.go)**, which defines the `rolePoliciesMap` variable mapping role names to allowed actions:

```go
var rolePoliciesMap = map[string][]*types.Policy{
    "projectAdmin": {
        {Resource: rbac.ResourceSelf, Action: rbac.ActionRead},
        {Resource: rbac.ResourceMember, Action: rbac.ActionCreate},
        // ... full permissions for project administration
    },
    "maintainer": {
        {Resource: rbac.ResourceSelf, Action: rbac.ActionRead},
        {Resource: rbac.ResourceMember, Action: rbac.ActionRead},
        // ... repository and artifact management
    },
    "developer": {
        // ... push and pull permissions
    },
    "guest": {
        // ... read-only access
    },
    "limitedGuest": {
        // ... limited read access only
    },
}

```

Each role grants specific permissions on resources such as `self`, `member`, `metadata`, `repository`, `tag`, and `scanner`.

### Role Evaluation and Enforcement

When API requests reach Harbor handlers, the `RequireProjectAccess` method in the `BaseAPI` extracts the current security context and queries the RBAC evaluator to determine if the user's role list contains the required permission for the requested action on the target resource.

The system calculates role priority through the `highestRole` function, which assigns numeric scores: **projectAdmin** (50), **maintainer** (40), **developer** (30), **guest** (20), and **limitedGuest** (10). This ranking exposes `current_user_role_id` in API responses for client-side permission hints.

## Managing Project Members

### Member Data Access Layer

Project membership data persists in the **`project_member`** table and is accessed through **[`src/pkg/member/dao/dao.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/member/dao/dao.go)**. The `AddProjectMember` function implements upsert logic by first deleting existing records for the same `(project_id, entity_id, entity_type)` tuple before inserting the new role assignment.

### Querying and Counting Members

The `GetProjectMember` function constructs a UNION SQL query that retrieves both individual user members and group members associated with a project. For role-based analytics, `GetTotalOfProjectMembers` counts members filtered by specific roles:

```go
total, err := a.memberMgr.GetTotalOfProjectMembers(orm.Clone(ctx), p.ProjectID, nil, role)

```

This function powers the `projectAPI.getProjectMemberSummary` endpoint to populate the `ProjectSummary` structure with accurate member statistics.

## Practical Implementation Examples

### Creating Projects via REST API

The following curl command creates a private project with content trust enabled:

```bash
curl -u admin:Harbor12345 -X POST "https://harbor.mycorp.com/api/v2.0/projects" \
  -H "Content-Type: application/json" \
  -d '{
        "project_name": "myteam",
        "metadata": {
            "public": "false",
            "enable_content_trust": "true"
        }
      }'

```

The server validates the project name against the regex pattern, enforces admin-only creation if configured, and stores metadata in the `project_metadata` table.

### Adding Members with Role Assignments

To assign the developer role (ID 3) to a user:

```bash
curl -u admin:Harbor12345 -X POST "https://harbor.mycorp.com/api/v2.0/projects/myteam/members" \
  -H "Content-Type: application/json" \
  -d '{
        "role_id": 3,
        "member_user": { "username": "jdoe" }
      }'

```

Internally, this calls `memberMgr.AddProjectMember`, which executes the DAO logic in [`src/pkg/member/dao/dao.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/member/dao/dao.go) to persist the membership record.

### Programmatic Member Management in Go

List all members of a project using the internal SDK:

```go
import (
    "context"
    "github.com/goharbor/harbor/src/pkg/member"
    "github.com/goharbor/harbor/src/pkg/project"
)

func listMembers(ctx context.Context, projectName string) ([]*member.Models.Member, error) {
    // Resolve project ID from name
    p, err := project.Ctl.GetByName(ctx, projectName)
    if err != nil {
        return nil, err
    }

    // Query members without filters
    members, err := member.Mgr.GetProjectMember(ctx, member.Models.Member{
        ProjectID: p.ProjectID,
    }, nil)
    return members, err
}

```

To determine a user's highest role for permission checking:

```go
import (
    "github.com/goharbor/harbor/src/common"
    "github.com/goharbor/harbor/src/pkg/member"
)

func highestUserRole(ctx context.Context, projID int64, userID int) (int, error) {
    roles, err := member.Mgr.ListRoles(ctx, &member.Models.User{UserID: userID}, projID)
    if err != nil {
        return 0, err
    }
    
    // Match Harbor's internal role ranking
    rank := map[int]int{
        common.RoleProjectAdmin: 50,
        common.RoleMaintainer:   40,
        common.RoleDeveloper:    30,
        common.RoleGuest:        20,
        common.RoleLimitedGuest: 10,
    }
    
    var bestRole, bestScore int
    for _, r := range roles {
        if s := rank[r]; s > bestScore {
            bestRole, bestScore = r, s
        }
    }
    return bestRole, nil
}

```

## Summary

- **Projects** in Harbor are isolated namespaces defined in [`src/pkg/project/models/project.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/project/models/project.go), with unique lowercase names validated by `^[a-z0-9]+(?:[._-][a-z0-9]+)*$`
- **RBAC enforcement** relies on [`src/common/rbac/project/rbac_role.go`](https://github.com/goharbor/harbor/blob/main/src/common/rbac/project/rbac_role.go), which maps five distinct roles (projectAdmin, maintainer, developer, guest, limitedGuest) to specific resource actions
- **Member management** occurs through [`src/pkg/member/dao/dao.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/member/dao/dao.go), supporting both individual users and groups with role-based counting and upsert operations
- **API handlers** in [`src/server/v2.0/handler/project.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/project.go) coordinate creation, deletion, and permission checks through the `RequireProjectAccess` security context
- **Role priorities** follow a numeric scale (50 to 10) that determines the effective permission level when users hold multiple roles

## Frequently Asked Questions

### What are the default RBAC roles available in Harbor projects?

Harbor defines five standard roles in [`src/common/rbac/project/rbac_role.go`](https://github.com/goharbor/harbor/blob/main/src/common/rbac/project/rbac_role.go): **projectAdmin** (full control, priority 50), **maintainer** (repository management, priority 40), **developer** (push and pull, priority 30), **guest** (read-only, priority 20), and **limitedGuest** (restricted read access, priority 10). Each role maps to a specific set of allowed actions on resources like repositories, tags, and project metadata.

### How does Harbor validate project names during creation?

Project names must match the regular expression `^[a-z0-9]+(?:[._-][a-z0-9]+)*$` enforced in [`src/pkg/project/manager.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/project/manager.go). This validation ensures names contain only lowercase alphanumeric characters with optional periods, underscores, or hyphens as internal separators. The `CreateProject` handler in [`src/server/v2.0/handler/project.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/project.go) applies this validation before persisting to the database.

### Where does Harbor store project membership and role assignments?

Membership data resides in the **`project_member`** database table, accessed through the DAO implementations in **[`src/pkg/member/dao/dao.go`](https://github.com/goharbor/harbor/blob/main/src/pkg/member/dao/dao.go)**. The `AddProjectMember` function handles role assignments by first removing existing entries for the same entity, then inserting the new role record. The `GetProjectMember` function retrieves memberships through a UNION query that combines individual users and group entries.

### Can system administrators restrict project creation privileges?

Yes. Harbor checks the `OnlyAdminCreateProject` configuration flag in the `CreateProject` handler at [`src/server/v2.0/handler/project.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/project.go). When enabled, only users with system administrator privileges can successfully create new projects through the API. Standard users receive a permission denied response when attempting to create projects under this configuration.