Add DatabasePermissions field to role (#37797)

* Add DatabasePermissions field to role.

* Change error wording in a minor way

* Update api/types/role.go

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* Update api/proto/teleport/legacy/types/types.proto

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* Update autogenerated files

* Guard against wildcards in `spec.allow.db_permissions`

---------

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>
This commit is contained in:
Krzysztof Skrzętnicki
2024-02-07 20:03:11 +00:00
committed by GitHub
co-authored by STeve Huang
parent 12f6baa530
commit bc1ba9c23c
12 changed files with 2704 additions and 1875 deletions
@@ -2964,6 +2964,25 @@ message RoleConditions {
// GroupLabelsExpression is a predicate expression used to allow/deny
// access to user groups.
string GroupLabelsExpression = 37 [(gogoproto.jsontag) = "group_labels_expression,omitempty"];
// DatabasePermissions specifies a set of permissions that will be granted
// to the database user when using automatic database user provisioning.
repeated DatabasePermission DatabasePermissions = 38 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "db_permissions,omitempty"
];
}
// DatabasePermission specifies the database object permission for the user.
message DatabasePermission {
// Permission is the list of string representations of the permission to be given, e.g. SELECT, INSERT, UPDATE, ...
repeated string Permissions = 1 [(gogoproto.jsontag) = "permissions"];
// Match is a list of object labels that must be matched for the permission to be granted.
wrappers.LabelValues Match = 2 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "match",
(gogoproto.customtype) = "Labels"
];
}
// KubernetesResource is the Kubernetes resource identifier.
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2023 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import "github.com/gravitational/trace"
// DatabasePermissions is a list of DatabasePermission objects.
type DatabasePermissions []DatabasePermission
func (m *DatabasePermission) CheckAndSetDefaults() error {
if len(m.Permissions) == 0 {
return trace.BadParameter("database permission list cannot be empty")
}
for _, permission := range m.Permissions {
if permission == "" {
return trace.BadParameter("individual database permissions cannot be empty strings")
}
}
for key, val := range m.Match {
if key == Wildcard && !(len(val) == 1 && val[0] == Wildcard) {
return trace.BadParameter("database permission: selector *:<val> is not supported")
}
}
return nil
}
+76
View File
@@ -0,0 +1,76 @@
// Copyright 2024 Gravitational, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
apiutils "github.com/gravitational/teleport/api/utils"
)
func TestDatabasePermission(t *testing.T) {
tests := []struct {
name string
permissions []string
match Labels
expectedErr error
}{
{
name: "valid permissions",
permissions: []string{"read", "write"},
match: map[string]apiutils.Strings{"env": {"production"}},
expectedErr: nil,
},
{
name: "empty permission list",
permissions: []string{},
match: map[string]apiutils.Strings{"env": {"production"}},
expectedErr: trace.BadParameter("database permission list cannot be empty"),
},
{
name: "empty individual permission",
permissions: []string{"read", ""},
match: map[string]apiutils.Strings{"env": {"production"}},
expectedErr: trace.BadParameter("individual database permissions cannot be empty strings"),
},
{
name: "wildcard selector with invalid value",
permissions: []string{"read"},
match: map[string]apiutils.Strings{Wildcard: {"invalid"}},
expectedErr: trace.BadParameter("database permission: selector *:<val> is not supported"),
},
{
name: "wildcard selector with valid value",
permissions: []string{"read"},
match: map[string]apiutils.Strings{Wildcard: {Wildcard}},
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dbPermission := &DatabasePermission{
Permissions: tt.permissions,
Match: tt.match,
}
err := dbPermission.CheckAndSetDefaults()
require.ErrorIs(t, tt.expectedErr, err)
})
}
}
+41
View File
@@ -152,6 +152,11 @@ type Role interface {
// SetDatabaseRoles sets a list of database roles for auto-provisioned users.
SetDatabaseRoles(RoleConditionType, []string)
// GetDatabasePermissions gets database permissions for auto-provisioned users.
GetDatabasePermissions(rct RoleConditionType) DatabasePermissions
// SetDatabasePermissions sets database permissions for auto-provisioned users.
SetDatabasePermissions(RoleConditionType, DatabasePermissions)
// GetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
GetImpersonateConditions(rct RoleConditionType) ImpersonateConditions
// SetImpersonateConditions sets conditions this role is allowed or denied to impersonate.
@@ -705,6 +710,23 @@ func (r *RoleV6) SetDatabaseRoles(rct RoleConditionType, values []string) {
}
}
// GetDatabasePermissions gets a list of database permissions for auto-provisioned users.
func (r *RoleV6) GetDatabasePermissions(rct RoleConditionType) DatabasePermissions {
if rct == Allow {
return r.Spec.Allow.DatabasePermissions
}
return r.Spec.Deny.DatabasePermissions
}
// SetDatabasePermissions sets a list of database permissions for auto-provisioned users.
func (r *RoleV6) SetDatabasePermissions(rct RoleConditionType, values DatabasePermissions) {
if rct == Allow {
r.Spec.Allow.DatabasePermissions = values
} else {
r.Spec.Deny.DatabasePermissions = values
}
}
// GetImpersonateConditions returns conditions this role is allowed or denied to impersonate.
func (r *RoleV6) GetImpersonateConditions(rct RoleConditionType) ImpersonateConditions {
cond := r.Spec.Deny.Impersonate
@@ -1129,6 +1151,25 @@ func (r *RoleV6) CheckAndSetDefaults() error {
}
}
for i, perm := range r.Spec.Allow.DatabasePermissions {
if err := perm.CheckAndSetDefaults(); err != nil {
return trace.BadParameter("failed to process 'allow' db_permission #%v: %v", i+1, err)
}
// Wildcards permissions are disallowed. Even though this should never pass the db-specific driver,
// it doesn't hurt to check it here. Wildcards *are* allowed on deny side,
// which is why this check is here and not in CheckAndSetDefaults().
for _, permission := range perm.Permissions {
if permission == Wildcard {
return trace.BadParameter("individual database permissions cannot be wildcards strings")
}
}
}
for i, perm := range r.Spec.Deny.DatabasePermissions {
if err := perm.CheckAndSetDefaults(); err != nil {
return trace.BadParameter("failed to process 'deny' db_permission #%v: %v", i+1, err)
}
}
for i := range r.Spec.Allow.Rules {
err := r.Spec.Allow.Rules[i].CheckAndSetDefaults()
if err != nil {
+2165 -1875
View File
File diff suppressed because it is too large Load Diff
@@ -86,6 +86,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -547,6 +569,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -1284,6 +1328,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -1745,6 +1811,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -89,6 +89,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -550,6 +572,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -89,6 +89,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -550,6 +572,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -86,6 +86,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -547,6 +569,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -1284,6 +1328,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -1745,6 +1811,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -89,6 +89,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -550,6 +572,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -89,6 +89,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
@@ -550,6 +572,28 @@ spec:
type: string
nullable: true
type: array
db_permissions:
description: DatabasePermissions specifies a set of permissions
that will be granted to the database user when using automatic
database user provisioning.
items:
properties:
match:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: Match is a list of object labels that must
be matched for the permission to be granted.
type: object
permissions:
description: Permission is the list of string representations
of the permission to be given, e.g. SELECT, INSERT, UPDATE,
...
items:
type: string
nullable: true
type: array
type: object
type: array
db_roles:
description: DatabaseRoles is a list of databases roles for automatic
user creation.
+14
View File
@@ -153,6 +153,9 @@ type AccessChecker interface {
// allowed roles are returned.
CheckDatabaseRoles(database types.Database, userRequestedRoles []string) (roles []string, err error)
// GetDatabasePermissions returns a set of database permissions applicable for the user.
GetDatabasePermissions() (allow types.DatabasePermissions, deny types.DatabasePermissions)
// CheckImpersonate checks whether current user is allowed to impersonate
// users and roles
CheckImpersonate(currentUser, impersonateUser types.User, impersonateRoles []types.Role) error
@@ -605,6 +608,17 @@ func (a *accessChecker) checkDatabaseRoles(database types.Database) (types.Creat
return allowedRoleSet.GetCreateDatabaseUserMode(), utils.StringsSliceFromSet(rolesMap), nil
}
// GetDatabasePermissions returns a set of database permissions applicable for the user.
func (a *accessChecker) GetDatabasePermissions() (allow types.DatabasePermissions, deny types.DatabasePermissions) {
for _, role := range a.RoleSet {
allow = append(allow, role.GetDatabasePermissions(types.Allow)...)
}
for _, role := range a.RoleSet {
deny = append(deny, role.GetDatabasePermissions(types.Deny)...)
}
return allow, deny
}
// EnumerateDatabaseUsers specializes EnumerateEntities to enumerate db_users.
func (a *accessChecker) EnumerateDatabaseUsers(database types.Database, extraUsers ...string) (EnumerationResult, error) {
// When auto-user provisioning is enabled, only Teleport username is allowed.