@@ -3,30 +3,23 @@ package v1
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
- "net/url "
6
+ "regexp "
7
7
"strings"
8
8
9
- "k8s.io/apimachinery/pkg/runtime"
10
-
11
- "github.com/stretchr/objx"
12
-
13
- "github.com/mongodb/mongodb-kubernetes-operator/pkg/authentication/scram"
14
- "github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/annotations"
15
-
16
9
appsv1 "k8s.io/api/apps/v1"
17
10
corev1 "k8s.io/api/core/v1"
18
-
19
- "github.com/mongodb/mongodb-kubernetes-operator/pkg/automationconfig"
20
- "github.com/mongodb/mongodb-kubernetes-operator/pkg/util/scale"
21
-
11
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
+ "k8s.io/apimachinery/pkg/runtime"
22
13
"k8s.io/apimachinery/pkg/runtime/schema"
23
-
24
14
"k8s.io/apimachinery/pkg/types"
25
-
26
- "regexp"
27
-
28
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29
15
"k8s.io/apimachinery/pkg/util/validation"
16
+
17
+ "github.com/mongodb/mongodb-kubernetes-operator/pkg/authentication/authtypes"
18
+ "github.com/mongodb/mongodb-kubernetes-operator/pkg/automationconfig"
19
+ "github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/annotations"
20
+ "github.com/mongodb/mongodb-kubernetes-operator/pkg/util/constants"
21
+ "github.com/mongodb/mongodb-kubernetes-operator/pkg/util/scale"
22
+ "github.com/stretchr/objx"
30
23
)
31
24
32
25
type Type string
@@ -452,20 +445,22 @@ type MongoDBUser struct {
452
445
DB string `json:"db,omitempty"`
453
446
454
447
// PasswordSecretRef is a reference to the secret containing this user's password
455
- PasswordSecretRef SecretKeyReference `json:"passwordSecretRef"`
448
+ // +optional
449
+ PasswordSecretRef SecretKeyReference `json:"passwordSecretRef,omitempty"`
456
450
457
451
// Roles is an array of roles assigned to this user
458
452
Roles []Role `json:"roles"`
459
453
460
454
// ScramCredentialsSecretName appended by string "scram-credentials" is the name of the secret object created by the mongoDB operator for storing SCRAM credentials
461
455
// These secrets names must be different for each user in a deployment.
462
456
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
463
- ScramCredentialsSecretName string `json:"scramCredentialsSecretName"`
457
+ // +optional
458
+ ScramCredentialsSecretName string `json:"scramCredentialsSecretName,omitempty"`
464
459
465
460
// ConnectionStringSecretName is the name of the secret object created by the operator which exposes the connection strings for the user.
466
461
// If provided, this secret must be different for each user in a deployment.
467
462
// +optional
468
- ConnectionStringSecretName string `json:"connectionStringSecretName"`
463
+ ConnectionStringSecretName string `json:"connectionStringSecretName,omitempty "`
469
464
470
465
// Additional options to be appended to the connection string.
471
466
// These options apply only to this user and will override any existing options in the resource.
@@ -584,6 +579,18 @@ type Authentication struct {
584
579
// Modes is an array specifying which authentication methods should be enabled.
585
580
Modes []AuthMode `json:"modes"`
586
581
582
+ // AgentMode contains the authentication mode used by the automation agent.
583
+ // +optional
584
+ AgentMode AuthMode `json:"agentMode,omitempty"`
585
+
586
+ // AgentCertificateSecret is a reference to a Secret containing the certificate and the key for the automation agent
587
+ // The secret needs to have available:
588
+ // - certificate under key: "tls.crt"
589
+ // - private key under key: "tls.key"
590
+ // If additionally, tls.pem is present, then it needs to be equal to the concatenation of tls.crt and tls.key
591
+ // +optional
592
+ AgentCertificateSecret * corev1.LocalObjectReference `json:"agentCertificateSecretRef,omitempty"`
593
+
587
594
// IgnoreUnknownUsers set to true will ensure any users added manually (not through the CRD)
588
595
// will not be removed.
589
596
@@ -595,17 +602,28 @@ type Authentication struct {
595
602
IgnoreUnknownUsers * bool `json:"ignoreUnknownUsers,omitempty"`
596
603
}
597
604
598
- // +kubebuilder:validation:Enum=SCRAM;SCRAM-SHA-256;SCRAM-SHA-1
605
+ // +kubebuilder:validation:Enum=SCRAM;SCRAM-SHA-256;SCRAM-SHA-1;X509
599
606
type AuthMode string
600
607
608
+ func IsAuthPresent (authModes []AuthMode , auth string ) bool {
609
+ for _ , authMode := range authModes {
610
+ if string (authMode ) == auth {
611
+ return true
612
+ }
613
+ }
614
+ return false
615
+ }
616
+
601
617
// ConvertAuthModeToAuthMechanism acts as a map but is immutable. It allows users to use different labels to describe the
602
618
// same authentication mode.
603
619
func ConvertAuthModeToAuthMechanism (authModeLabel AuthMode ) string {
604
620
switch authModeLabel {
605
621
case "SCRAM" , "SCRAM-SHA-256" :
606
- return scram .Sha256
622
+ return constants .Sha256
607
623
case "SCRAM-SHA-1" :
608
- return scram .Sha1
624
+ return constants .Sha1
625
+ case "X509" :
626
+ return constants .X509
609
627
default :
610
628
return ""
611
629
}
@@ -673,52 +691,51 @@ func (m *MongoDBCommunity) GetOwnerReferences() []metav1.OwnerReference {
673
691
return []metav1.OwnerReference {ownerReference }
674
692
}
675
693
676
- // GetScramOptions returns a set of Options that are used to configure scram
694
+ // GetAuthOptions returns a set of Options that are used to configure scram
677
695
// authentication.
678
- func (m * MongoDBCommunity ) GetScramOptions () scram .Options {
696
+ func (m * MongoDBCommunity ) GetAuthOptions () authtypes .Options {
679
697
ignoreUnknownUsers := true
680
698
if m .Spec .Security .Authentication .IgnoreUnknownUsers != nil {
681
699
ignoreUnknownUsers = * m .Spec .Security .Authentication .IgnoreUnknownUsers
682
700
}
683
701
684
702
authModes := m .Spec .Security .Authentication .Modes
685
703
defaultAuthMechanism := ConvertAuthModeToAuthMechanism (defaultMode )
686
- var autoAuthMechanism string
704
+ autoAuthMechanism := ConvertAuthModeToAuthMechanism ( m . Spec . GetAgentAuthMode ())
687
705
authMechanisms := make ([]string , len (authModes ))
688
706
689
- if len ( authModes ) == 0 {
707
+ if autoAuthMechanism == "" {
690
708
autoAuthMechanism = defaultAuthMechanism
691
- } else {
692
- autoAuthMechanism = ConvertAuthModeToAuthMechanism (authModes [0 ])
709
+ }
693
710
711
+ if len (authModes ) == 0 {
712
+ authMechanisms = []string {defaultAuthMechanism }
713
+ } else {
694
714
for i , authMode := range authModes {
695
715
if authMech := ConvertAuthModeToAuthMechanism (authMode ); authMech != "" {
696
716
authMechanisms [i ] = authMech
697
- if authMech == defaultAuthMechanism {
698
- autoAuthMechanism = defaultAuthMechanism
699
- }
700
717
}
701
718
}
702
719
}
703
720
704
- return scram .Options {
705
- AuthoritativeSet : ! ignoreUnknownUsers ,
706
- KeyFile : scram .AutomationAgentKeyFilePathInContainer ,
707
- AutoAuthMechanisms : authMechanisms ,
708
- AgentName : scram .AgentName ,
709
- AutoAuthMechanism : autoAuthMechanism ,
721
+ return authtypes .Options {
722
+ AuthoritativeSet : ! ignoreUnknownUsers ,
723
+ KeyFile : constants .AutomationAgentKeyFilePathInContainer ,
724
+ AuthMechanisms : authMechanisms ,
725
+ AgentName : constants .AgentName ,
726
+ AutoAuthMechanism : autoAuthMechanism ,
710
727
}
711
728
}
712
729
713
- // GetScramUsers converts all of the users from the spec into users
714
- // that can be used to configure scram authentication.
715
- func (m * MongoDBCommunity ) GetScramUsers () []scram .User {
716
- users := make ([]scram .User , len (m .Spec .Users ))
730
+ // GetAuthUsers converts all the users from the spec into users
731
+ // that can be used to configure authentication.
732
+ func (m * MongoDBCommunity ) GetAuthUsers () []authtypes .User {
733
+ users := make ([]authtypes .User , len (m .Spec .Users ))
717
734
for i , u := range m .Spec .Users {
718
- roles := make ([]scram .Role , len (u .Roles ))
735
+ roles := make ([]authtypes .Role , len (u .Roles ))
719
736
for j , r := range u .Roles {
720
737
721
- roles [j ] = scram .Role {
738
+ roles [j ] = authtypes .Role {
722
739
Name : r .Name ,
723
740
Database : r .DB ,
724
741
}
@@ -734,20 +751,76 @@ func (m *MongoDBCommunity) GetScramUsers() []scram.User {
734
751
u .DB = defaultDBForUser
735
752
}
736
753
737
- users [i ] = scram .User {
754
+ users [i ] = authtypes .User {
738
755
Username : u .Name ,
739
756
Database : u .DB ,
740
757
Roles : roles ,
741
- PasswordSecretKey : u .GetPasswordSecretKey (),
742
- PasswordSecretName : u .PasswordSecretRef .Name ,
743
- ScramCredentialsSecretName : u .GetScramCredentialsSecretName (),
744
758
ConnectionStringSecretName : u .GetConnectionStringSecretName (m .Name ),
745
759
ConnectionStringOptions : u .AdditionalConnectionStringConfig .Object ,
746
760
}
761
+
762
+ if u .DB != constants .ExternalDB {
763
+ users [i ].ScramCredentialsSecretName = u .GetScramCredentialsSecretName ()
764
+ users [i ].PasswordSecretKey = u .GetPasswordSecretKey ()
765
+ users [i ].PasswordSecretName = u .PasswordSecretRef .Name
766
+ }
747
767
}
748
768
return users
749
769
}
750
770
771
+ // AgentCertificateSecretNamespacedName returns the namespaced name of the secret containing the agent certificate.
772
+ func (m * MongoDBCommunity ) AgentCertificateSecretNamespacedName () types.NamespacedName {
773
+ return types.NamespacedName {
774
+ Namespace : m .Namespace ,
775
+ Name : m .Spec .GetAgentCertificateRef (),
776
+ }
777
+ }
778
+
779
+ // AgentCertificatePemSecretNamespacedName returns the namespaced name of the secret containing the agent certificate in pem format.
780
+ func (m * MongoDBCommunity ) AgentCertificatePemSecretNamespacedName () types.NamespacedName {
781
+ return types.NamespacedName {
782
+ Namespace : m .Namespace ,
783
+ Name : m .Spec .GetAgentCertificateRef () + "-pem" ,
784
+ }
785
+ }
786
+
787
+ // GetAgentCertificateRef returns the name of the secret containing the agent certificate.
788
+ // If it is specified in the CR, it will return this. Otherwise, it default to agent-certs.
789
+ func (m * MongoDBCommunitySpec ) GetAgentCertificateRef () string {
790
+ agentCertSecret := "agent-certs"
791
+ if m .Security .Authentication .AgentCertificateSecret != nil && m .Security .Authentication .AgentCertificateSecret .Name != "" {
792
+ agentCertSecret = m .Security .Authentication .AgentCertificateSecret .Name
793
+ }
794
+ return agentCertSecret
795
+ }
796
+
797
+ // GetAgentAuthMode return the agent authentication mode. If the agent auth mode is specified, it will return this.
798
+ // Otherwise, if the spec.security.authentication.modes array is empty, it will default to SCRAM-SHA-256.
799
+ // If spec.security.authentication.modes has one element, the agent auth mode will default to that.
800
+ // If spec.security.authentication.modes has more than one element, then agent auth will need to be specified,
801
+ // with one exception: if spec.security.authentication.modes contains only SCRAM-SHA-256 and SCRAM-SHA-1, then it defaults to SCRAM-SHA-256 (for backwards compatibility).
802
+ func (m * MongoDBCommunitySpec ) GetAgentAuthMode () AuthMode {
803
+ if m .Security .Authentication .AgentMode != "" {
804
+ return m .Security .Authentication .AgentMode
805
+ }
806
+
807
+ if len (m .Security .Authentication .Modes ) == 0 {
808
+ return "SCRAM-SHA-256"
809
+ } else if len (m .Security .Authentication .Modes ) == 1 {
810
+ return m .Security .Authentication .Modes [0 ]
811
+ } else if len (m .Security .Authentication .Modes ) == 2 {
812
+ if (IsAuthPresent (m .Security .Authentication .Modes , "SCRAM" ) || IsAuthPresent (m .Security .Authentication .Modes , "SCRAM-SHA-256" )) &&
813
+ IsAuthPresent (m .Security .Authentication .Modes , "SCRAM-SHA-1" ) {
814
+ return "SCRAM-SHA-256"
815
+ }
816
+ }
817
+ return ""
818
+ }
819
+
820
+ func (m * MongoDBCommunitySpec ) IsAgentX509 () bool {
821
+ return m .GetAgentAuthMode () == "X509"
822
+ }
823
+
751
824
// IsStillScaling returns true if this resource is currently scaling,
752
825
// considering both arbiters and regular members.
753
826
func (m * MongoDBCommunity ) IsStillScaling () bool {
@@ -817,7 +890,7 @@ func (m *MongoDBCommunity) GetOptionsString() string {
817
890
//
818
891
// Takes into account both user options and resource options.
819
892
// User options will override any existing options in the resource.
820
- func (m * MongoDBCommunity ) GetUserOptionsString (user scram .User ) string {
893
+ func (m * MongoDBCommunity ) GetUserOptionsString (user authtypes .User ) string {
821
894
generalOptionsMap := m .Spec .AdditionalConnectionStringConfig .Object
822
895
userOptionsMap := user .ConnectionStringOptions
823
896
optionValues := make ([]string , len (generalOptionsMap )+ len (userOptionsMap ))
@@ -866,12 +939,10 @@ func (m *MongoDBCommunity) MongoSRVURI(clusterDomain string) string {
866
939
867
940
// MongoAuthUserURI returns a mongo uri which can be used to connect to this deployment
868
941
// and includes the authentication data for the user
869
- func (m * MongoDBCommunity ) MongoAuthUserURI (user scram .User , password string , clusterDomain string ) string {
942
+ func (m * MongoDBCommunity ) MongoAuthUserURI (user authtypes .User , password string , clusterDomain string ) string {
870
943
optionsString := m .GetUserOptionsString (user )
871
-
872
- return fmt .Sprintf ("mongodb://%s:%s@%s/%s?replicaSet=%s&ssl=%t%s" ,
873
- url .QueryEscape (user .Username ),
874
- url .QueryEscape (password ),
944
+ return fmt .Sprintf ("mongodb://%s%s/%s?replicaSet=%s&ssl=%t%s" ,
945
+ user .GetLoginString (password ),
875
946
strings .Join (m .Hosts (clusterDomain ), "," ),
876
947
user .Database ,
877
948
m .Name ,
@@ -881,16 +952,14 @@ func (m *MongoDBCommunity) MongoAuthUserURI(user scram.User, password string, cl
881
952
882
953
// MongoAuthUserSRVURI returns a mongo srv uri which can be used to connect to this deployment
883
954
// and includes the authentication data for the user
884
- func (m * MongoDBCommunity ) MongoAuthUserSRVURI (user scram .User , password string , clusterDomain string ) string {
955
+ func (m * MongoDBCommunity ) MongoAuthUserSRVURI (user authtypes .User , password string , clusterDomain string ) string {
885
956
if clusterDomain == "" {
886
957
clusterDomain = defaultClusterDomain
887
958
}
888
959
889
960
optionsString := m .GetUserOptionsString (user )
890
-
891
- return fmt .Sprintf ("mongodb+srv://%s:%s@%s.%s.svc.%s/%s?replicaSet=%s&ssl=%t%s" ,
892
- url .QueryEscape (user .Username ),
893
- url .QueryEscape (password ),
961
+ return fmt .Sprintf ("mongodb+srv://%s%s.%s.svc.%s/%s?replicaSet=%s&ssl=%t%s" ,
962
+ user .GetLoginString (password ),
894
963
m .ServiceName (),
895
964
m .Namespace ,
896
965
clusterDomain ,
0 commit comments