diff --git a/api/v1/nificluster_types.go b/api/v1/nificluster_types.go index 1e21053456..3cd6944ad6 100644 --- a/api/v1/nificluster_types.go +++ b/api/v1/nificluster_types.go @@ -111,6 +111,8 @@ type NifiClusterSpec struct { ControllerUserIdentity *string `json:"controllerUserIdentity,omitempty"` // SingleUserConfiguration if enabled handles the information related to this authentication method SingleUserConfiguration SingleUserConfiguration `json:"singleUserConfiguration,omitempty"` + // OidcConfiguration if enabled handles the information related to this authentication method + OidcConfiguration OidcConfiguration `json:"oidcConfiguration,omitempty"` // @TODO: Block Controller change } @@ -134,6 +136,37 @@ type SingleUserConfiguration struct { SecretKeys UserSecretKeys `json:"secretKeys,omitempty"` } +// You can look into single-user access here: https://exceptionfactory.com/posts/2021/07/21/single-user-access-and-https-in-apache-nifi/ +type OidcConfiguration struct { + // enabled specifies whether or not the cluster should use single user authentication for Nifi + // +kubebuilder:default:=false + // +optional + Enabled bool `json:"enabled"` + // authorizerEnabled specifies if the cluster should use use the single-user-authorizer instead of the managed-authorizer + // +kubebuilder:default:= + // +optional + DiscoveryUrl string `json:"discoveryUrl,omitempty"` + // authorizerEnabled specifies if the cluster should use use the single-user-authorizer instead of the managed-authorizer + // +kubebuilder:default:= + // +optional + ClientId string `json:"clientId,omitempty"` + // secretRef references the secret containing the informations required to authentiticate to the cluster + // +optional + ClientSecretRef *SecretReference `json:"clientSecretRef,omitempty"` + // authorizerEnabled specifies if the cluster should use use the single-user-authorizer instead of the managed-authorizer + // +kubebuilder:default:=CN=([^,])(?:, (?:O|OU)=.)? + // +optional + PatternDn string `json:"patternDn,omitempty"` + // authorizerEnabled specifies if the cluster should use use the single-user-authorizer instead of the managed-authorizer + // +kubebuilder:default:=$1 + // +optional + ValueDn string `json:"valueDn,omitempty"` + // authorizerEnabled specifies if the cluster should use use the single-user-authorizer instead of the managed-authorizer + // +kubebuilder:default:=None + // +optional + TransformDn string `json:"transformDn,omitempty"` +} + type UserSecretKeys struct { // username specifies he name of the secret key to retrieve the user name // +kubebuilder:default:=username diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index e6b8eb21ad..1ab1b83641 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -541,6 +541,7 @@ func (in *NifiClusterSpec) DeepCopyInto(out *NifiClusterSpec) { **out = **in } in.SingleUserConfiguration.DeepCopyInto(&out.SingleUserConfiguration) + in.OidcConfiguration.DeepCopyInto(&out.OidcConfiguration) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NifiClusterSpec. @@ -1661,6 +1662,16 @@ func (in *SingleUserConfiguration) DeepCopyInto(out *SingleUserConfiguration) { out.SecretKeys = in.SecretKeys } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OidcConfiguration) DeepCopyInto(out *OidcConfiguration) { + *out = *in + if in.ClientSecretRef != nil { + in, out := &in.ClientSecretRef, &out.ClientSecretRef + *out = new(SecretReference) + **out = **in + } +} + // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SingleUserConfiguration. func (in *SingleUserConfiguration) DeepCopy() *SingleUserConfiguration { if in == nil { diff --git a/helm/nifi-cluster/values.yaml b/helm/nifi-cluster/values.yaml index a7bc50a7dd..d08c17a3f9 100644 --- a/helm/nifi-cluster/values.yaml +++ b/helm/nifi-cluster/values.yaml @@ -53,6 +53,17 @@ cluster: secretKeys: username: "username" password: "password" + + oidcConfiguration: + enabled: false + discoveryUrl: "" + clientId: "" + clientSecretRef: + name: "oidcClientSecret" + namespace: "nifi" + patternDn: "CN=([^,])(?:, (?:O|OU)=.)?" + valueDn: "$1" + transformDn: "NONE" pod: # -- Annotations to apply to every pod diff --git a/pkg/resources/nifi/secretconfig.go b/pkg/resources/nifi/secretconfig.go index 692977afb1..4a9d5dd0a6 100644 --- a/pkg/resources/nifi/secretconfig.go +++ b/pkg/resources/nifi/secretconfig.go @@ -130,6 +130,20 @@ func (r *Reconciler) getNifiPropertiesConfigString(nConfig *v1.NodeConfig, id in webProxyHosts = strings.Join(append(dnsNames, base.WebProxyHosts...), ",") } + if strings.Contains(config.NifiPropertiesTemplate, "user.oidc.client.secret") { + // read secret value + clientSecret := &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: OidcConfiguration.SecretRef.Name, + NameSpace: OidcConfiguration.SecretRef.NameSpace, + }, + Key: clientSecret, + }, + } + + strings.Replace(config.NifiPropertiesTemplate, "nifi.security.user.oidc.client.secret=clientSecret", "nifi.security.user.oidc.client.secret=" + clientSecret, 1) + } useSSL := configcommon.UseSSL(r.NifiCluster) var out bytes.Buffer t := template.Must(template.New("nConfig-config").Parse(config.NifiPropertiesTemplate)) @@ -162,6 +176,7 @@ func (r *Reconciler) getNifiPropertiesConfigString(nConfig *v1.NodeConfig, id in // "LdapConfiguration": r.NifiCluster.Spec.LdapConfiguration, "SingleUserConfiguration": r.NifiCluster.Spec.SingleUserConfiguration, + "OidcConfiguration": r.NifiCluster.Spec.OidcConfiguration, "IsNode": nConfig.GetIsNode(), "ZookeeperConnectString": r.NifiCluster.Spec.ZKAddress, "ZookeeperPath": r.NifiCluster.Spec.GetZkPath(), @@ -300,6 +315,7 @@ func (r *Reconciler) getLoginIdentityProvidersConfigString(nConfig *v1.NodeConfi "Id": id, "LdapConfiguration": r.NifiCluster.Spec.LdapConfiguration, "SingleUserConfiguration": r.NifiCluster.Spec.SingleUserConfiguration, + "OidcConfiguration": r.NifiCluster.Spec.OidcConfiguration, }); err != nil { log.Error("error occurred during parsing the config template", zap.String("clusterName", r.NifiCluster.Name), @@ -517,6 +533,7 @@ func (r *Reconciler) getAuthorizersConfigString(nConfig *v1.NodeConfig, id int32 "NodeList": nodeList, "ControllerUser": r.NifiCluster.GetNifiControllerUserIdentity(), "SingleUserConfiguration": r.NifiCluster.Spec.SingleUserConfiguration, + "OidcConfiguration": r.NifiCluster.Spec.OidcConfiguration, }); err != nil { log.Error("error occurred during parsing the config template", zap.String("clusterName", r.NifiCluster.Name), diff --git a/pkg/resources/templates/config/nifi_properties.go b/pkg/resources/templates/config/nifi_properties.go index 8046be4e24..25c1148e58 100644 --- a/pkg/resources/templates/config/nifi_properties.go +++ b/pkg/resources/templates/config/nifi_properties.go @@ -182,7 +182,14 @@ nifi.security.user.authorizer=single-user-authorizer {{else}} nifi.security.user.authorizer={{ .Authorizer }} {{end}} -{{if .LdapConfiguration.Enabled}} +{{ if .OidcConfiguration.Enabled}} +nifi.security.user.oidc.discovery.url={{ .OidcConfiguration.discoveryUrl }} +nifi.security.user.oidc.client.id={{ .OidcConfiguration.clientId }} +nifi.security.user.oidc.client.secret=clientSecret +nifi.security.identity.mapping.pattern.dn={{ .OidcConfiguration.patternDn }} +nifi.security.identity.mapping.value.dn={{ .OidcConfiguration.valueDn }} +nifi.security.identity.mapping.transform.dn={{ .OidcConfiguration.transformDn }} +{{else if .LdapConfiguration.Enabled}} nifi.security.user.login.identity.provider=ldap-provider {{else if .SingleUserConfiguration.Enabled}} nifi.security.user.login.identity.provider=single-user-provider