Skip to content

Commit cc893f1

Browse files
CLOUDP-314917 CLOUDP-314918 CLOUDP-314919 - Add ClusterMongoDBRole CRD (#54)
# Summary Introduced new CRD for MongoDB roles. The new CRD is cluster-scoped and can be reused in multiple MongoDB deployments even across-namespaces. The CRD design can be found in the [TD](https://docs.google.com/document/d/11j_wg0-s3u8oBI6Ca12AZiHLlUv_ViilYwMvl2LgoiQ/edit?tab=t.bhdbox3ppbto#bookmark=id.jbs82dmgpgr6) ## Proof of Work There are unit and E2E tests verifying that the custom roles are: * Roles are added in automation config * Removing a reference to the role removes the role from automation config * Updating the role triggers a reconciliation, and role is updated in AC * Deleting the role is blocked by the finalizer * Deleting the role after it is removed from resources is not blocked anymore ## Checklist - [ ] Have you linked a jira ticket and/or is the ticket in the title? - [ ] Have you checked whether your jira ticket required DOCSP changes? - [ ] Have you checked for release_note changes? ## Reminder (Please remove this when merging) - Please try to Approve or Reject Changes the PR, keep PRs in review as short as possible - Our Short Guide for PRs: [Link](https://docs.google.com/document/d/1T93KUtdvONq43vfTfUt8l92uo4e4SEEvFbIEKOxGr44/edit?tab=t.0) - Remember the following Communication Standards - use comment prefixes for clarity: * **blocking**: Must be addressed before approval. * **follow-up**: Can be addressed in a later PR or ticket. * **q**: Clarifying question. * **nit**: Non-blocking suggestions. * **note**: Side-note, non-actionable. Example: Praise * --> no prefix is considered a question --------- Co-authored-by: Łukasz Sierant <lukasz.sierant@mongodb.com>
1 parent ca24d93 commit cc893f1

File tree

69 files changed

+2112
-358
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+2112
-358
lines changed

.evergreen-tasks.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ tasks:
254254
commands:
255255
- func: "e2e_test"
256256

257+
- name: e2e_mongodb_custom_roles
258+
tags: [ "patch-run" ]
259+
commands:
260+
- func: "e2e_test"
261+
257262
- name: e2e_replica_set_recovery
258263
tags: [ "patch-run" ]
259264
commands:
@@ -644,7 +649,7 @@ tasks:
644649
commands:
645650
- func: "e2e_test"
646651

647-
- name: e2e_replica_set_custom_roles
652+
- name: e2e_replica_set_ldap_custom_roles
648653
tags: [ "patch-run" ]
649654
commands:
650655
- func: "e2e_test"

.evergreen.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ task_groups:
728728
- e2e_replica_set_ldap_user_to_dn_mapping
729729
# e2e_replica_set_ldap_agent_auth
730730
- e2e_replica_set_ldap_agent_client_certs
731-
- e2e_replica_set_custom_roles
731+
- e2e_replica_set_ldap_custom_roles
732732
- e2e_replica_set_update_roles_no_privileges
733733
- e2e_replica_set_ldap_group_dn
734734
- e2e_replica_set_ldap_group_dn_with_x509_agent
@@ -911,6 +911,7 @@ task_groups:
911911
- e2e_tls_x509_configure_all_options_sc
912912
- e2e_tls_x509_sc
913913
- e2e_meko_mck_upgrade
914+
- e2e_mongodb_custom_roles
914915
- e2e_sharded_cluster_oidc_m2m_group
915916
- e2e_sharded_cluster_oidc_m2m_user
916917
- e2e_multi_cluster_oidc_m2m_group

PROJECT

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
# Code generated by tool. DO NOT EDIT.
2+
# This file is used to track the info used to scaffold your project
3+
# and allow the plugins properly work.
4+
# More info: https://book.kubebuilder.io/reference/project-config.html
15
domain: mongodb.com
2-
layout: go.kubebuilder.io/v3
6+
layout:
7+
- go.kubebuilder.io/v3
8+
plugins:
9+
manifests.sdk.operatorframework.io/v2: {}
10+
scorecard.sdk.operatorframework.io/v2: {}
311
projectName: mongodb-kubernetes
412
repo: github.com/mongodb/mongodb-kubernetes
513
resources:
@@ -30,7 +38,13 @@ resources:
3038
kind: MongoDBUser
3139
path: github.com/mongodb/mongodb-kubernetes/api/v1
3240
version: v1
41+
- api:
42+
crdVersion: v1
43+
namespaced: false
44+
controller: false
45+
domain: mongodb.com
46+
group: mongodb
47+
kind: ClusterMongoDBRole
48+
path: github.com/mongodb/mongodb-kubernetes/api/v1
49+
version: v1
3350
version: "3"
34-
plugins:
35-
manifests.sdk.operatorframework.io/v2: {}
36-
scorecard.sdk.operatorframework.io/v2: {}

RELEASE_NOTES.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
[//]: # (Consider renaming or removing the header for next release, otherwise it appears as duplicate in the published release, e.g: https://github.com/mongodb/mongodb-enterprise-kubernetes/releases/tag/1.22.0 )
22
<!-- Next Release -->
33

4+
# MCK 1.2.0 Release Notes
5+
6+
## New Features
7+
8+
* Added new **ClusterMongoDBRole** CRD to support reusable roles across multiple MongoDB clusters.
9+
* This allows users to define roles once and reuse them in multiple **MongoDB** or **MongoDBMultiCluster** resources. The role can be referenced through the `.spec.security.roleRefs` field. Note that only one of `.spec.security.roles` and `.spec.security.roleRefs` can be used at a time.
10+
* **ClusterMongoDBRole** resources are treated by the operator as a custom role templates that are only used when referenced by the database resources.
11+
* The new resource is watched by default by the operator. This means that the operator will require a new **ClusterRole** and **ClusterRoleBinding** to be created in the cluster. **ClusterRole** and **ClusterRoleBinding** resources are created by default with the helm chart or the kubectl mongodb plugin.
12+
* To disable this behavior in the helm chart, set the `operator.enableClusterMongoDBRoles` value to `false`. This will disable the creation of the necessary RBAC resources for the **ClusterMongoDBRole** resource, as well as disable the watch for this resource.
13+
* To not install the necessary **ClusterRole** and **ClusterRoleBinding** with the kubectl mongodb plugin set the `--create-mongodb-roles-cluster-role` to false.
14+
* The new **ClusterMongoDBRole** resource is designed to be read-only, meaning it can be used by MongoDB deployments managed by different operators.
15+
* The **ClusterMongoDBRole** resource can be deleted at any time, but the operator will not delete any roles that were created using this resource. To properly remove access, you must **manually** remove the reference to the **ClusterMongoDBRole** in the **MongoDB** or **MongoDBMultiCluster** resources.
16+
* The reference documentation for this resource can be found here: **TODO** (link to documentation)
17+
* For more information please see: **TODO** (link to documentation)
18+
19+
20+
<!-- Past Releases -->
21+
422
# MCK 1.1.0 Release Notes
523

624
## New Features
@@ -12,7 +30,6 @@
1230
* minimum MongoDB Community version: 8.0.
1331
* TLS must be disabled in MongoDB (communication between mongot and mongod is in plaintext for now).
1432

15-
<!-- Past Releases -->
1633
# MCK 1.0.1 Release Notes
1734

1835

api/v1/mdb/mongodb_roles_validation.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ func isValidCIDR(cidr string) bool {
270270
return err == nil
271271
}
272272

273-
func roleIsCorrectlyConfigured(role MongoDbRole, mdbVersion string) v1.ValidationResult {
273+
func RoleIsCorrectlyConfigured(role MongoDBRole, mdbVersion string) v1.ValidationResult {
274274
// Extensive validation of the roles attribute
275275

276276
if role.Role == "" {
@@ -305,10 +305,10 @@ func roleIsCorrectlyConfigured(role MongoDbRole, mdbVersion string) v1.Validatio
305305
return v1.ValidationSuccess()
306306
}
307307

308-
func rolesAttributeisCorrectlyConfigured(d DbCommonSpec) v1.ValidationResult {
308+
func rolesAttributeIsCorrectlyConfigured(d DbCommonSpec) v1.ValidationResult {
309309
// Validate every single entry and return error on the first one that fails validation
310310
for _, role := range d.Security.Roles {
311-
if res := roleIsCorrectlyConfigured(role, d.Version); res.Level == v1.ErrorLevel {
311+
if res := RoleIsCorrectlyConfigured(role, d.Version); res.Level == v1.ErrorLevel {
312312
return v1.ValidationError("Error validating role - %s", res.Msg)
313313
}
314314
}

api/v1/mdb/mongodb_types.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,10 +742,16 @@ type SharedConnectionSpec struct {
742742
CloudManagerConfig *PrivateCloudConfig `json:"cloudManager,omitempty"`
743743
}
744744

745+
// +kubebuilder:validation:XValidation:rule="!(has(self.roles) && has(self.roleRefs)) || !(self.roles.size() > 0 && self.roleRefs.size() > 0)",message="At most one of roles or roleRefs can be non-empty"
745746
type Security struct {
746747
TLSConfig *TLSConfig `json:"tls,omitempty"`
747748
Authentication *Authentication `json:"authentication,omitempty"`
748-
Roles []MongoDbRole `json:"roles,omitempty"`
749+
750+
// +optional
751+
Roles []MongoDBRole `json:"roles,omitempty"`
752+
753+
// +optional
754+
RoleRefs []MongoDBRoleRef `json:"roleRefs,omitempty"`
749755

750756
// +optional
751757
CertificatesSecretsPrefix string `json:"certsSecretPrefix"`
@@ -973,7 +979,16 @@ type InheritedRole struct {
973979
Role string `json:"role"`
974980
}
975981

976-
type MongoDbRole struct {
982+
type MongoDBRoleRef struct {
983+
// +kubebuilder:validation:Required
984+
Name string `json:"name"`
985+
986+
// +kubebuilder:validation:Enum=ClusterMongoDBRole
987+
// +kubebuilder:validation:Required
988+
Kind string `json:"kind"`
989+
}
990+
991+
type MongoDBRole struct {
977992
Role string `json:"role"`
978993
AuthenticationRestrictions []AuthenticationRestriction `json:"authenticationRestrictions,omitempty"`
979994
Db string `json:"db"`
@@ -1604,7 +1619,10 @@ func EnsureSecurity(sec *Security) *Security {
16041619
sec.TLSConfig = &TLSConfig{}
16051620
}
16061621
if sec.Roles == nil {
1607-
sec.Roles = make([]MongoDbRole, 0)
1622+
sec.Roles = make([]MongoDBRole, 0)
1623+
}
1624+
if sec.RoleRefs == nil {
1625+
sec.RoleRefs = make([]MongoDBRoleRef, 0)
16081626
}
16091627
return sec
16101628
}

api/v1/mdb/mongodb_validation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ func CommonValidators(db DbCommonSpec) []func(d DbCommonSpec) v1.ValidationResul
394394
deploymentsMustHaveAgentModeInAuthModes,
395395
scramSha1AuthValidation,
396396
ldapAuthRequiresEnterprise,
397-
rolesAttributeisCorrectlyConfigured,
397+
rolesAttributeIsCorrectlyConfigured,
398398
agentModeIsSetIfMoreThanADeploymentAuthModeIsSet,
399399
ldapGroupDnIsSetIfLdapAuthzIsEnabledAndAgentsAreExternal,
400400
specWithExactlyOneSchema,

api/v1/mdb/mongodbbuilder.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,22 @@ func (b *MongoDBBuilder) SetSecurityTLSEnabled() *MongoDBBuilder {
146146
return b
147147
}
148148

149+
func (b *MongoDBBuilder) SetRoles(roles []MongoDBRole) *MongoDBBuilder {
150+
if b.mdb.Spec.Security == nil {
151+
b.mdb.Spec.Security = &Security{}
152+
}
153+
b.mdb.Spec.Security.Roles = roles
154+
return b
155+
}
156+
157+
func (b *MongoDBBuilder) SetRoleRefs(roleRefs []MongoDBRoleRef) *MongoDBBuilder {
158+
if b.mdb.Spec.Security == nil {
159+
b.mdb.Spec.Security = &Security{}
160+
}
161+
b.mdb.Spec.Security.RoleRefs = roleRefs
162+
return b
163+
}
164+
149165
func (b *MongoDBBuilder) SetLabels(labels map[string]string) *MongoDBBuilder {
150166
b.mdb.Labels = labels
151167
return b

api/v1/mdb/zz_generated.deepcopy.go

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

api/v1/mdbmulti/mongodbmultibuilder.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func DefaultMultiReplicaSetBuilder() *MultiReplicaSetBuilder {
4646
Authentication: &mdbv1.Authentication{
4747
Modes: []mdbv1.AuthMode{},
4848
},
49-
Roles: []mdbv1.MongoDbRole{},
49+
Roles: []mdbv1.MongoDBRole{},
5050
},
5151
DuplicateServiceObjects: util.BooleanRef(false),
5252
},
@@ -73,6 +73,14 @@ func (m *MultiReplicaSetBuilder) SetSecurity(s *mdbv1.Security) *MultiReplicaSet
7373
return m
7474
}
7575

76+
func (m *MultiReplicaSetBuilder) SetRoleRefs(roleRefs []mdbv1.MongoDBRoleRef) *MultiReplicaSetBuilder {
77+
if m.Spec.Security == nil {
78+
m.Spec.Security = &mdbv1.Security{}
79+
}
80+
m.Spec.Security.RoleRefs = roleRefs
81+
return m
82+
}
83+
7684
func (m *MultiReplicaSetBuilder) SetClusterSpecList(clusters []string) *MultiReplicaSetBuilder {
7785
randFive, err := rand.Int(rand.Reader, big.NewInt(5))
7886
if err != nil {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package role
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
6+
"github.com/mongodb/mongodb-kubernetes/api/v1"
7+
mdbv1 "github.com/mongodb/mongodb-kubernetes/api/v1/mdb"
8+
)
9+
10+
// ClusterMongoDBRoleSpec defines the desired state of ClusterMongoDBRole.
11+
type ClusterMongoDBRoleSpec struct {
12+
// +kubebuilder:pruning:PreserveUnknownFields
13+
mdbv1.MongoDBRole `json:",inline"`
14+
}
15+
16+
// +kubebuilder:object:root=true
17+
// +k8s:openapi-gen=true
18+
// +kubebuilder:resource:scope=Cluster,shortName=cmdbr
19+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The time since the MongoDB Custom Role resource was created."
20+
21+
// ClusterMongoDBRole is the Schema for the clustermongodbroles API.
22+
type ClusterMongoDBRole struct {
23+
metav1.TypeMeta `json:",inline"`
24+
metav1.ObjectMeta `json:"metadata,omitempty"`
25+
26+
Spec ClusterMongoDBRoleSpec `json:"spec,omitempty"`
27+
}
28+
29+
// +kubebuilder:object:root=true
30+
31+
// ClusterMongoDBRoleList contains a list of ClusterMongoDBRole.
32+
type ClusterMongoDBRoleList struct {
33+
metav1.TypeMeta `json:",inline"`
34+
metav1.ListMeta `json:"metadata,omitempty"`
35+
Items []ClusterMongoDBRole `json:"items"`
36+
}
37+
38+
func init() {
39+
v1.SchemeBuilder.Register(&ClusterMongoDBRole{}, &ClusterMongoDBRoleList{})
40+
}

api/v1/role/doc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package role
2+
3+
// +k8s:deepcopy-gen=package
4+
// +versionName=v1

api/v1/role/groupversion_info.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Package v1 contains API Schema definitions for the mongodb v1 API group
2+
// +kubebuilder:object:generate=true
3+
// +groupName=mongodb.com
4+
package role
5+
6+
import (
7+
"k8s.io/apimachinery/pkg/runtime/schema"
8+
"sigs.k8s.io/controller-runtime/pkg/scheme"
9+
)
10+
11+
var (
12+
// GroupVersion is group version used to register these objects.
13+
GroupVersion = schema.GroupVersion{Group: "mongodb.com", Version: "v1"}
14+
15+
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
16+
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
17+
18+
// AddToScheme adds the types in this group-version to the given scheme.
19+
AddToScheme = SchemeBuilder.AddToScheme
20+
)

0 commit comments

Comments
 (0)