Skip to content

Commit 4b7b0d7

Browse files
author
Ivan Ivic
authored
[DK-2071] Support assigning roles to mongodb users (#12)
* Support assigning roles to db users * Update README * Default mongodb readWrite role via kubebuilder * Remove roles abstraction from postgres, it should be replaced with permissions settings
1 parent 178d81f commit 4b7b0d7

File tree

9 files changed

+92
-37
lines changed

9 files changed

+92
-37
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ spec:
7777
name: my-app-mongodb-credentials
7878
credentials:
7979
name: my-app-mongodb
80+
roles:
81+
- name: readWrite
8082
---
8183
apiVersion: v1
8284
kind: Secret

api/v1beta1/database_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ type SecretReference struct {
7272
PasswordField string `json:"passwordField"`
7373
}
7474

75+
type Role struct {
76+
Name string `json:"name"`
77+
}
78+
7579
// Extension is a resource representing database extension
7680
type Extension struct {
7781
Name string `json:"name"`

api/v1beta1/mongodbuser_type.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,15 @@ type MongoDBUserSpec struct {
2828
// +required
2929
Credentials *SecretReference `json:"credentials"`
3030

31-
// Roles is not yet suppported
3231
// +optional
33-
//Roles []*MongoDBRole `json:"roles"`
32+
// +kubebuilder:default:={{name: readWrite}}
33+
Roles *[]Role `json:"roles"`
3434

3535
// CustomData is not yet supported
3636
// +optional
3737
//CustomData map[string]string `json:"customData"`
3838
}
3939

40-
// MongoDBRole see https://docs.mongodb.com/manual/reference/method/db.createUser/#create-user-with-roles
41-
type MongoDBRole struct {
42-
// +optional
43-
// +kubebuilder:default:=readWrite
44-
Role string `json:"role"`
45-
}
46-
4740
// GetStatusConditions returns a pointer to the Status.Conditions slice
4841
func (in *MongoDBUser) GetStatusConditions() *[]metav1.Condition {
4942
return &in.Status.Conditions
@@ -83,6 +76,10 @@ func (in *MongoDBUser) GetCredentials() *SecretReference {
8376
return in.Spec.Credentials
8477
}
8578

79+
func (in *MongoDBUser) GetRoles() *[]Role {
80+
return in.Spec.Roles
81+
}
82+
8683
// +kubebuilder:object:root=true
8784

8885
// MongoDBUserList contains a list of MongoDBUser

api/v1beta1/postgresqluser_type.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222
)
2323

2424
type PostgreSQLUserSpec struct {
25-
Database *DatabaseReference `json:"database"`
26-
Credentials *SecretReference `json:"credentials"`
25+
// +required
26+
Database *DatabaseReference `json:"database"`
27+
28+
// +required
29+
Credentials *SecretReference `json:"credentials"`
2730
}
2831

2932
// GetStatusConditions returns a pointer to the Status.Conditions slice
@@ -65,6 +68,11 @@ func (in *PostgreSQLUser) GetCredentials() *SecretReference {
6568
return in.Spec.Credentials
6669
}
6770

71+
func (in *PostgreSQLUser) GetRoles() *[]Role {
72+
// NOOP
73+
return nil
74+
}
75+
6876
// +kubebuilder:object:root=true
6977

7078
// PostgreSQLUserList contains a list of PostgreSQLUser

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 24 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/db/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type Invoke func(ctx context.Context, uri, database, username, password string)
1010
// Handler is a wrapper arround a certain database client
1111
type Handler interface {
1212
Close() error
13-
SetupUser(database string, username string, password string) error
13+
SetupUser(database string, username string, password string, roles []string) error
1414
DropUser(database string, username string) error
1515
CreateDatabaseIfNotExists(database string) error
1616
EnableExtension(name string) error

common/db/mongodb.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,20 @@ func (m *MongoDBRepository) Close() error {
6161
return m.client.Disconnect(ctx)
6262
}
6363

64-
// CreateDatabaseIfNotExists is a dummy to apply to fullfill the contract,
64+
// CreateDatabaseIfNotExists is a dummy to apply to fulfill the contract,
6565
// we don't need to create the database on MongoDB
6666
func (m *MongoDBRepository) CreateDatabaseIfNotExists(database string) error {
6767
return nil
6868
}
6969

70-
func (m *MongoDBRepository) SetupUser(database string, username string, password string) error {
70+
func (m *MongoDBRepository) SetupUser(database string, username string, password string, roles []string) error {
7171
doesUserExist, err := m.doesUserExist(database, username)
7272
if err != nil {
7373
return err
7474
}
7575

7676
if !doesUserExist {
77-
if err := m.createUser(database, username, password); err != nil {
77+
if err := m.createUser(database, username, password, roles); err != nil {
7878
return err
7979
}
8080
if doesUserExistNow, err := m.doesUserExist(database, username); err != nil {
@@ -83,7 +83,7 @@ func (m *MongoDBRepository) SetupUser(database string, username string, password
8383
return errors.New("user doesn't exist after create")
8484
}
8585
} else {
86-
if err := m.updateUserPasswordAndRoles(database, username, password); err != nil {
86+
if err := m.updateUserPasswordAndRoles(database, username, password, roles); err != nil {
8787
return err
8888
}
8989
}
@@ -138,19 +138,37 @@ func (m *MongoDBRepository) getAllUsers(database string, username string) (Users
138138
return users, nil
139139
}
140140

141-
func (m *MongoDBRepository) createUser(database string, username string, password string) error {
141+
func (m *MongoDBRepository) getRoles(database string, roles []string) []bson.M {
142+
// by default, assign readWrite role (backward compatibility)
143+
if roles == nil || len(roles) == 0 {
144+
return []bson.M{{
145+
"role": "readWrite",
146+
"db": database,
147+
}}
148+
}
149+
rs := make([]bson.M, 0)
150+
for _, r := range roles {
151+
rs = append(rs, bson.M{
152+
"role": r,
153+
"db": database,
154+
})
155+
}
156+
return rs
157+
}
158+
159+
func (m *MongoDBRepository) createUser(database string, username string, password string, roles []string) error {
142160
command := &bson.D{primitive.E{Key: "createUser", Value: username}, primitive.E{Key: "pwd", Value: password},
143-
primitive.E{Key: "roles", Value: []bson.M{{"role": "readWrite", "db": database}}}}
161+
primitive.E{Key: "roles", Value: m.getRoles(database, roles)}}
144162
r := m.runCommand(database, command)
145163
if _, err := r.DecodeBytes(); err != nil {
146164
return err
147165
}
148166
return nil
149167
}
150168

151-
func (m *MongoDBRepository) updateUserPasswordAndRoles(database string, username string, password string) error {
169+
func (m *MongoDBRepository) updateUserPasswordAndRoles(database string, username string, password string, roles []string) error {
152170
command := &bson.D{primitive.E{Key: "updateUser", Value: username}, primitive.E{Key: "pwd", Value: password},
153-
primitive.E{Key: "roles", Value: []bson.M{{"role": "readWrite", "db": database}}}}
171+
primitive.E{Key: "roles", Value: m.getRoles(database, roles)}}
154172
r := m.runCommand(database, command)
155173
if _, err := r.DecodeBytes(); err != nil {
156174
return err

common/db/postgresql.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ type PostgreSQLRepository struct {
1414
dbpool *pgxpool.Pool
1515
}
1616

17+
const (
18+
DefaultPostgreSQLReadRole = "read"
19+
DefaultPostgreSQLReadWriteRole = "readWrite"
20+
)
21+
1722
func NewPostgreSQLRepository(ctx context.Context, uri, database, username, password string) (Handler, error) {
1823
opt, err := url.Parse(uri)
1924
if err != nil {
@@ -64,7 +69,7 @@ func (s *PostgreSQLRepository) CreateDatabaseIfNotExists(database string) error
6469
}
6570
}
6671

67-
func (s *PostgreSQLRepository) SetupUser(database string, user string, password string) error {
72+
func (s *PostgreSQLRepository) SetupUser(database string, user string, password string, roles []string) error {
6873
if err := s.createUserIfNotExists(user); err != nil {
6974
return err
7075
}

controllers/handler.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type user interface {
4040
runtime.Object
4141
GetStatusConditions() *[]metav1.Condition
4242
GetCredentials() *infrav1beta1.SecretReference
43+
GetRoles() *[]infrav1beta1.Role
4344
GetDatabase() string
4445
}
4546

@@ -72,6 +73,17 @@ func extractCredentials(credentials *infrav1beta1.SecretReference, secret *corev
7273
return user, pw, nil
7374
}
7475

76+
func extractRoles(roles *[]infrav1beta1.Role) []string {
77+
if roles == nil || len(*roles) == 0 {
78+
return nil
79+
}
80+
rolesToReturn := make([]string, 0)
81+
for _, r := range *roles {
82+
rolesToReturn = append(rolesToReturn, r.Name)
83+
}
84+
return rolesToReturn
85+
}
86+
7587
func reconcileDatabase(c client.Client, pool *db.ClientPool, invoke db.Invoke, database database, recorder record.EventRecorder) (database, ctrl.Result) {
7688
// Fetch referencing root secret
7789
secret := &corev1.Secret{}
@@ -203,7 +215,7 @@ func reconcileUser(database database, c client.Client, pool *db.ClientPool, invo
203215
return user, ctrl.Result{Requeue: true}
204216
}
205217

206-
err = dbHandler.SetupUser(database.GetDatabaseName(), usr, pw)
218+
err = dbHandler.SetupUser(database.GetDatabaseName(), usr, pw, extractRoles(user.GetRoles()))
207219
if err != nil {
208220
msg := fmt.Sprintf("Failed to provison user account: %s", err.Error())
209221
recorder.Event(user, "Normal", "error", msg)

0 commit comments

Comments
 (0)