Skip to content

Commit b0fad82

Browse files
authored
Merge pull request #514 from sapcc/negative-rbac
add keppel.RBACPolicy.ForbiddenPermissions
2 parents 4f4c404 + dcb1799 commit b0fad82

10 files changed

Lines changed: 262 additions & 255 deletions

File tree

cmd/api/gui_redirect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (g *guiRedirecter) tryRedirectToGUI(w http.ResponseWriter, r *http.Request)
7777
return
7878
}
7979
for _, policy := range policies {
80-
if !slices.Contains(policy.Permissions, keppel.GrantsAnonymousPull) {
80+
if !slices.Contains(policy.Permissions, keppel.RBACAnonymousPullPermission) {
8181
continue
8282
}
8383
ip := httpext.GetRequesterIPFor(r)

docs/api-spec.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ The following fields may be returned:
144144
| `accounts[].rbac_policies[].match_repository` | string | The RBAC policy applies to all repositories in this account whose name matches this regex. The leading account name and slash is stripped from the repository name before matching. The notes on regexes below apply. |
145145
| `accounts[].rbac_policies[].match_username` | string | The RBAC policy applies to all users whose name matches this regex. Refer to the [documentation of your auth driver](./drivers/) for the syntax of usernames. The notes on regexes below apply. |
146146
| `accounts[].rbac_policies[].permissions` | list of strings | The permissions granted by the RBAC policy. Acceptable values include `pull`, `push`, `delete`, `anonymous_pull` and `anonymous_first_pull`. When `pull`, `push` or `delete` are included, `match_username` is not empty. When `anonymous_pull` or `anonymous_first_pull` is included, `match_username` is empty. `anonymous_first_pull` is only relevant for external replica accounts and allows unauthenticated users to replicate tags. It should always be combined with an appropriate `match_*` rule. |
147+
| `accounts[].rbac_policies[].forbidden_permissions` | list of strings | The permissions forbidden by the RBAC policy. Acceptable values are the same as for the `permissions` field. This field takes precedence over `permissions`: Any permission listed here will never be given to matching users, even if another matching policy would grant it. |
147148
| `accounts[].replication` | object or omitted | Replication configuration for this account, if any. [See below](#replication-strategies) for details. |
148149
| `accounts[].platform_filter` | list of objects or omitted | Only allowed for replica accounts. If not empty, when replicating an image list manifest (i.e. a multi-architecture image), only submanifests matching one of the given platforms will be replicated. Each entry must have the same format as the `manifests[].platform` field in the [OCI Image Index Specification](https://github.com/opencontainers/image-spec/blob/master/image-index.md). |
149150
| `accounts[].validation` | object or omitted | Validation rules for this account. When included, pushing blobs and manifests not satisfying these validation rules may be rejected. |

internal/api/auth/api_test.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,41 +66,46 @@ type TestCase struct {
6666
var (
6767
policyAnonPull = keppel.RBACPolicy{
6868
RepositoryPattern: "fo+",
69-
Permissions: []keppel.RBACPermission{keppel.GrantsAnonymousPull},
69+
Permissions: []keppel.RBACPermission{keppel.RBACAnonymousPullPermission},
7070
}
7171
policyAnonFirstPull = keppel.RBACPolicy{
7272
RepositoryPattern: "fo+",
73-
Permissions: []keppel.RBACPermission{keppel.GrantsAnonymousPull, keppel.GrantsAnonymousFirstPull},
73+
Permissions: []keppel.RBACPermission{keppel.RBACAnonymousPullPermission, keppel.RBACAnonymousFirstPullPermission},
7474
}
7575
policyPullMatches = keppel.RBACPolicy{
7676
RepositoryPattern: "fo+",
7777
UserNamePattern: "correct.*",
78-
Permissions: []keppel.RBACPermission{keppel.GrantsPull},
78+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission},
79+
}
80+
policyForbidPush = keppel.RBACPolicy{
81+
RepositoryPattern: "fo+",
82+
UserNamePattern: "correct.*",
83+
ForbiddenPermissions: []keppel.RBACPermission{keppel.RBACPushPermission},
7984
}
8085
policyPushMatches = keppel.RBACPolicy{
8186
RepositoryPattern: "fo+",
8287
UserNamePattern: "correct.*",
83-
Permissions: []keppel.RBACPermission{keppel.GrantsPull, keppel.GrantsPush},
88+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission, keppel.RBACPushPermission},
8489
}
8590
policyDeleteMatches = keppel.RBACPolicy{
8691
RepositoryPattern: "fo+",
8792
UserNamePattern: "correct.*",
88-
Permissions: []keppel.RBACPermission{keppel.GrantsPull, keppel.GrantsDelete},
93+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission, keppel.RBACDeletePermission},
8994
}
9095
policyPullDoesNotMatch = keppel.RBACPolicy{
9196
RepositoryPattern: "fo+",
9297
UserNamePattern: "doesnotmatch",
93-
Permissions: []keppel.RBACPermission{keppel.GrantsPull},
98+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission},
9499
}
95100
policyPushDoesNotMatch = keppel.RBACPolicy{
96101
RepositoryPattern: "doesnotmatch",
97102
UserNamePattern: "correct.*",
98-
Permissions: []keppel.RBACPermission{keppel.GrantsPull, keppel.GrantsPush},
103+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission, keppel.RBACPushPermission},
99104
}
100105
policyDeleteDoesNotMatch = keppel.RBACPolicy{
101106
RepositoryPattern: "fo+",
102107
UserNamePattern: "doesnotmatch",
103-
Permissions: []keppel.RBACPermission{keppel.GrantsPull, keppel.GrantsDelete},
108+
Permissions: []keppel.RBACPermission{keppel.RBACPullPermission, keppel.RBACDeletePermission},
104109
}
105110
)
106111

@@ -414,6 +419,19 @@ var testCases = []TestCase{
414419
{Scope: "repository:test1/foo:delete",
415420
RBACPolicy: &policyDeleteMatches,
416421
GrantedActions: "delete"},
422+
// negative RBAC policies can take away permissions
423+
{Scope: "repository:test1/foo:pull",
424+
RBACPolicy: &policyForbidPush,
425+
GrantedActions: "pull"},
426+
{Scope: "repository:test1/foo:push",
427+
RBACPolicy: &policyForbidPush,
428+
GrantedActions: ""},
429+
{Scope: "repository:test1/foo:pull,push",
430+
RBACPolicy: &policyForbidPush,
431+
GrantedActions: "pull"},
432+
{Scope: "repository:test1/foo:delete",
433+
RBACPolicy: &policyForbidPush,
434+
GrantedActions: "delete"},
417435
}
418436

419437
// TODO expect refresh_token when offline_token=true is given

0 commit comments

Comments
 (0)