diff --git a/.github/workflows/dev-be-ci.yaml b/.github/workflows/dev-be-ci.yaml index aba5c67db..22af882e8 100644 --- a/.github/workflows/dev-be-ci.yaml +++ b/.github/workflows/dev-be-ci.yaml @@ -358,7 +358,7 @@ jobs: - name: Add CI user to admin role run: | - kubectl patch configmap everest-rbac -n everest-system --patch "$(kubectl get configmap everest-rbac -n everest-system -o json | jq '.data["policy.csv"] += "\ng, everest_ci, admin:role"' | jq '{data: { "policy.csv": .data["policy.csv"] } }')" + kubectl patch configmap everest-rbac -n everest-system --patch "$(kubectl get configmap everest-rbac -n everest-system -o json | jq '.data["policy.csv"] += "\ng, everest_ci, role:admin"' | jq '{data: { "policy.csv": .data["policy.csv"] } }')" kubectl get configmap everest-rbac -n everest-system -ojsonpath='{.data.policy\.csv}' - name: Run integration tests diff --git a/api-tests/generated/types.ts b/api-tests/generated/types.ts index a0ef68ea0..bdf9cf8dd 100644 --- a/api-tests/generated/types.ts +++ b/api-tests/generated/types.ts @@ -40,11 +40,11 @@ export interface paths { * *Example:* * Assume the following RBAC policy, and users `alice` and `bob`: * ``` - * p, admin:role, namespaces, read, * - * p, admin:role, database-engines, *, *\/* - * p, admin:role, database-clusters, *, *\/* + * p, role:dev, namespaces, read, * + * p, role:dev, database-engines, *, *\/* + * p, role:dev, database-clusters, *, *\/* * p, bob, database-clusters, *, *\/* - * g, alice, admin:role + * g, alice, role:dev * ``` * The API will return the following permissions for `alice`: * ``` @@ -844,7 +844,7 @@ export interface components { }; NamespaceList: string[]; UserPermissions: { - enabled?: boolean; + enabled: boolean; permissions?: string[][]; }; UserCredentials: { diff --git a/api/everest-server.gen.go b/api/everest-server.gen.go index 294d22e57..9c768089b 100644 --- a/api/everest-server.gen.go +++ b/api/everest-server.gen.go @@ -2917,18 +2917,18 @@ var swaggerSpec = []string{ "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/client/everest-client.gen.go b/client/everest-client.gen.go index 6658a1612..529b1e37b 100644 --- a/client/everest-client.gen.go +++ b/client/everest-client.gen.go @@ -8381,18 +8381,18 @@ var swaggerSpec = []string{ "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/commands/settings/rbac/can.go b/commands/settings/rbac/can.go index b97898be7..3ba726f81 100644 --- a/commands/settings/rbac/can.go +++ b/commands/settings/rbac/can.go @@ -39,8 +39,8 @@ $ everestctl settings rbac can alice read database-clusters my-namespace/cluster # Check if user 'alice' can perform all/any actions on 'cluster-1' in namespace 'my-namespace' $ everestctl settings rbac can alice '*' database-clusters my-namespace/cluster-1 -# Check if role 'admin:role' can update backup 'prod-backup-1' in namespace 'prod-namespace' -$ everestctl settings rbac can admin:role update database-cluster-backups prod-namespace/prod-backup-1 +# Check if role 'role:admin' can update backup 'prod-backup-1' in namespace 'prod-namespace' +$ everestctl settings rbac can role:admin update database-cluster-backups prod-namespace/prod-backup-1 # Check if user 'bob' can delete all/any backups in namespace 'prod-namespace' $ everestctl settings rbac can bob delete database-cluster-backups prod-namespace/* diff --git a/deploy/quickstart-k8s.yaml b/deploy/quickstart-k8s.yaml index 7591f17b7..39929b340 100644 --- a/deploy/quickstart-k8s.yaml +++ b/deploy/quickstart-k8s.yaml @@ -92,15 +92,7 @@ metadata: data: enabled: "false" policy.csv: | - p, admin:role, namespaces, *, * - p, admin:role, database-engines, *, */* - p, admin:role, database-clusters, *, */* - p, admin:role, database-cluster-backups, *, */* - p, admin:role, database-cluster-restores, *, */* - p, admin:role, database-cluster-credentials, *, */* - p, admin:role, backup-storages, *, */* - p, admin:role, monitoring-instances, *, */* - g, admin, admin:role + g, admin, role:admin --- apiVersion: apps/v1 kind: Deployment diff --git a/docs/spec/openapi.yml b/docs/spec/openapi.yml index 5e00e892b..2d4c165ca 100644 --- a/docs/spec/openapi.yml +++ b/docs/spec/openapi.yml @@ -83,11 +83,11 @@ paths: *Example:* Assume the following RBAC policy, and users `alice` and `bob`: ``` - p, admin:role, namespaces, read, * - p, admin:role, database-engines, *, */* - p, admin:role, database-clusters, *, */* + p, role:dev, namespaces, read, * + p, role:dev, database-engines, *, */* + p, role:dev, database-clusters, *, */* p, bob, database-clusters, *, */* - g, alice, admin:role + g, alice, role:dev ``` The API will return the following permissions for `alice`: ``` diff --git a/pkg/common/constants.go b/pkg/common/constants.go index 619daa54f..86c8cc123 100644 --- a/pkg/common/constants.go +++ b/pkg/common/constants.go @@ -49,8 +49,12 @@ const ( // EverestJWTPublicKeyFile is the path to the JWT public key. EverestJWTPublicKeyFile = "/etc/jwt/id_rsa.pub" + // EverestRBACRolePrefix is the prefix for roles. + EverestRBACRolePrefix = "role:" // EverestAdminUser is the name of the admin user. EverestAdminUser = "admin" + // EverestAdminRole is the name of the admin role. + EverestAdminRole = EverestRBACRolePrefix + "admin" // EverestSettingsConfigMapName is the name of the Everest settings ConfigMap. EverestSettingsConfigMapName = "everest-settings" diff --git a/pkg/rbac/rbac.go b/pkg/rbac/rbac.go index 5eb076b5f..159b5c76e 100644 --- a/pkg/rbac/rbac.go +++ b/pkg/rbac/rbac.go @@ -91,6 +91,10 @@ func refreshEnforcerInBackground( if err := validatePolicy(enforcer); err != nil { panic("invalid policy detected - " + err.Error()) } + // Calling LoadPolicy() re-writes the entire model, so we need to add back the admin role. + if err := loadAdminPolicy(enforcer); err != nil { + panic("failed to load admin policy - " + err.Error()) + } enforcer.EnableEnforce(IsEnabled(cm)) }) if inf.Start(ctx, &corev1.ConfigMap{}) != nil { @@ -116,6 +120,9 @@ func newEnforcer(adapter persist.Adapter, enableLogs bool) (*casbin.Enforcer, er if err != nil { return nil, err } + if err := loadAdminPolicy(enf); err != nil { + return nil, errors.Join(err, errors.New("failed to load admin policy")) + } if err := validatePolicy(enf); err != nil { return nil, err } @@ -178,6 +185,28 @@ func GetUser(c echo.Context) (string, error) { return subject, nil } +func loadAdminPolicy(enf casbin.IEnforcer) error { + paths, _, err := buildPathResourceMap("") // reads the swagger API definition + if err != nil { + return err + } + resources := make(map[string]struct{}) + for _, resource := range paths { + resources[resource] = struct{}{} + } + action := "*" + for resource := range resources { + object := "*/*" + if resource == ResourceNamespaces { + object = "*" + } + if _, err := enf.AddPolicy(common.EverestAdminRole, resource, action, object); err != nil { + return err + } + } + return nil +} + // buildPathResourceMap builds a map of paths to resources and a list of resources. // Returns: (resourceMap, skipPaths, error) . func buildPathResourceMap(basePath string) (map[string]string, []string, error) { diff --git a/pkg/rbac/testdata/policy-1-good.csv b/pkg/rbac/testdata/policy-1-good.csv index 54b93f8b2..95de35c30 100644 --- a/pkg/rbac/testdata/policy-1-good.csv +++ b/pkg/rbac/testdata/policy-1-good.csv @@ -1,29 +1,29 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* -p, admin:role, database-clusters, *, */* -p, admin:role, database-cluster-backups, *, */* -p, admin:role, database-cluster-restores, *, */* -p, admin:role, backup-storages, *, */* -p, admin:role, monitoring-instances, *, */* +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* +p, role:admin, database-clusters, *, */* +p, role:admin, database-cluster-backups, *, */* +p, role:admin, database-cluster-restores, *, */* +p, role:admin, backup-storages, *, */* +p, role:admin, monitoring-instances, *, */* -p, readonly:role, namespaces, read, * -p, readonly:role, database-engines, read, */* -p, readonly:role, database-clusters, read, */* -p, readonly:role, database-cluster-backups, read, */* -p, readonly:role, database-cluster-restores, read, */* -p, readonly:role, backup-storages, read, */* -p, readonly:role, monitoring-instances, read, */* +p, role:readonly, namespaces, read, * +p, role:readonly, database-engines, read, */* +p, role:readonly, database-clusters, read, */* +p, role:readonly, database-cluster-backups, read, */* +p, role:readonly, database-cluster-restores, read, */* +p, role:readonly, backup-storages, read, */* +p, role:readonly, monitoring-instances, read, */* -p, devteam:role, namespaces, *, * -p, devteam:role, database-engines, *, dev/* -p, devteam:role, database-clusters, *, dev/* -p, devteam:role, database-cluster-backups, *, dev/* -p, devteam:role, database-cluster-restores, *, dev/* -p, devteam:role, backup-storages, *, */* -p, devteam:role, monitoring-instances, *, */* +p, role:devteam, namespaces, *, * +p, role:devteam, database-engines, *, dev/* +p, role:devteam, database-clusters, *, dev/* +p, role:devteam, database-cluster-backups, *, dev/* +p, role:devteam, database-cluster-restores, *, dev/* +p, role:devteam, backup-storages, *, */* +p, role:devteam, monitoring-instances, *, */* p, alice, database-clusters, create, alice/* -g, admin, admin:role -g, alice, readonly:role -g, bob, devteam:role +g, admin, role:admin +g, alice, role:readonly +g, bob, role:devteam diff --git a/pkg/rbac/testdata/policy-2-bad.csv b/pkg/rbac/testdata/policy-2-bad.csv index ece5f7a06..96e679083 100644 --- a/pkg/rbac/testdata/policy-2-bad.csv +++ b/pkg/rbac/testdata/policy-2-bad.csv @@ -1,4 +1,4 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* this is a bad policy xxxxxxxxxx diff --git a/pkg/rbac/testdata/policy-3-bad.csv b/pkg/rbac/testdata/policy-3-bad.csv index a3df4d912..b1f42d1a3 100644 --- a/pkg/rbac/testdata/policy-3-bad.csv +++ b/pkg/rbac/testdata/policy-3-bad.csv @@ -1,6 +1,6 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* -p, admin:role, monitoring-instances, *, */* -p, admin:role, monitoring instances, *, */* -g, admin, admin:role +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* +p, role:admin, monitoring-instances, *, */* +p, role:admin, monitoring instances, *, */* +g, admin, role:admin diff --git a/pkg/rbac/testdata/policy-4-bad.csv b/pkg/rbac/testdata/policy-4-bad.csv index 2c56b4989..6a4c01ac5 100644 --- a/pkg/rbac/testdata/policy-4-bad.csv +++ b/pkg/rbac/testdata/policy-4-bad.csv @@ -1,5 +1,5 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* -p, admin:role, monitoring-instances, *, */* -p, notexists:role, monitoring-instances, *, */* -g, admin, admin:role +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* +p, role:admin, monitoring-instances, *, */* +p, role:notexists, monitoring-instances, *, */* +g, admin, role:admin diff --git a/pkg/rbac/testdata/policy-5-bad.csv b/pkg/rbac/testdata/policy-5-bad.csv index 1a84c8773..04f82c877 100644 --- a/pkg/rbac/testdata/policy-5-bad.csv +++ b/pkg/rbac/testdata/policy-5-bad.csv @@ -1,4 +1,4 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* -p, admin:role, monitoring-instances, *, */*, asdfasdf -g, admin, admin:role +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* +p, role:admin, monitoring-instances, *, */*, asdfasdf +g, admin, role:admin diff --git a/pkg/rbac/testdata/policy-6-bad.csv b/pkg/rbac/testdata/policy-6-bad.csv index 1917f7e89..7bc650274 100644 --- a/pkg/rbac/testdata/policy-6-bad.csv +++ b/pkg/rbac/testdata/policy-6-bad.csv @@ -1,4 +1,4 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* p, alice, non-existent-resource, *, */* -g, admin, admin:role +g, admin, role:admin diff --git a/pkg/rbac/testdata/policy-7-bad.csv b/pkg/rbac/testdata/policy-7-bad.csv index 7cfa614db..b3fd24661 100644 --- a/pkg/rbac/testdata/policy-7-bad.csv +++ b/pkg/rbac/testdata/policy-7-bad.csv @@ -1,4 +1,4 @@ -p, admin:role, namespaces, read, * -p, admin:role, database-engines, *, */* -a, admin:role, database-clusters, *, */* +p, role:admin, namespaces, read, * +p, role:admin, database-engines, *, */* +a, role:admin, database-clusters, *, */* diff --git a/pkg/rbac/validate.go b/pkg/rbac/validate.go index eb22903bb..3c6572659 100644 --- a/pkg/rbac/validate.go +++ b/pkg/rbac/validate.go @@ -11,6 +11,7 @@ import ( "github.com/casbin/casbin/v2" "go.uber.org/zap" + "github.com/percona/everest/pkg/common" "github.com/percona/everest/pkg/kubernetes" ) @@ -82,7 +83,11 @@ func checkResourceNames(policies [][]string) error { func checkRoles(roles []string, policies [][]string) error { for _, policy := range policies { roleName := policy[0] - if !strings.HasSuffix(roleName, ":role") { + if !strings.HasPrefix(roleName, common.EverestRBACRolePrefix) { + continue + } + if roleName == common.EverestAdminRole { + // Its fine to not assign the admin role to any user. continue } if !slices.Contains(roles, roleName) { diff --git a/pkg/rbac/validate_test.go b/pkg/rbac/validate_test.go index 48319375e..34b6dfc4c 100644 --- a/pkg/rbac/validate_test.go +++ b/pkg/rbac/validate_test.go @@ -71,16 +71,16 @@ func TestCheckResourceNames(t *testing.T) { }{ { policies: [][]string{ - {"admin:role", "database-clusters", "create", "*"}, - {"admin:role", "monitoring-instances", "*", "*"}, + {"role:admin", "database-clusters", "create", "*"}, + {"role:admin", "monitoring-instances", "*", "*"}, }, valid: true, }, { policies: [][]string{ - {"admin:role", "database-clusters", "create", "*"}, - {"admin:role", "monitoring-instances", "*", "*"}, - {"admin:role", "does-not-exist", "*", "*"}, + {"role:admin", "database-clusters", "create", "*"}, + {"role:admin", "monitoring-instances", "*", "*"}, + {"role:admin", "does-not-exist", "*", "*"}, }, valid: false, }, @@ -108,19 +108,19 @@ func TestCheckRoles(t *testing.T) { valid bool }{ { - roles: []string{"admin:role", "viewer:role"}, + roles: []string{"role:admin", "role:viewer"}, policies: [][]string{ - {"admin:role", "database-clusters", "create", "*"}, - {"admin:role", "monitoring-instances", "*", "*"}, + {"role:admin", "database-clusters", "create", "*"}, + {"role:admin", "monitoring-instances", "*", "*"}, }, valid: true, }, { - roles: []string{"admin:role", "viewer:role"}, + roles: []string{"role:admin", "role:viewer"}, policies: [][]string{ - {"admin:role", "database-clusters", "create", "*"}, - {"admin:role", "monitoring-instances", "*", "*"}, - {"does-not-exist:role", "monitoring-instances", "*", "*"}, + {"role:admin", "database-clusters", "create", "*"}, + {"role:admin", "monitoring-instances", "*", "*"}, + {"role:does-not-exist", "monitoring-instances", "*", "*"}, }, valid: false, }, @@ -147,19 +147,19 @@ func TestValidateTerms(t *testing.T) { valid bool }{ { - terms: []string{"admin:role", "database-clusters", "create", "*"}, + terms: []string{"role:admin", "database-clusters", "create", "*"}, valid: true, }, { - terms: []string{"admin!!:role", "database-clusters", "create", "*"}, + terms: []string{"role:admin!!", "database-clusters", "create", "*"}, valid: false, }, { - terms: []string{"admin!!:role", "database clusters", "create", "*"}, + terms: []string{"role:admin!!", "database clusters", "create", "*"}, valid: false, }, { - terms: []string{"admin!!:role", "", "create", "*"}, + terms: []string{"role:admin!!", "", "create", "*"}, valid: false, }, }