diff --git a/CHANGELOG.md b/CHANGELOG.md index 96d76b3691..2ba223613f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Added +- [PR #76](https://github.com/konpyutaika/nifikop/pull/76) - **[Operator/NiFiCluster]** Add ability to override default authorizers.xml template. + ### Changed - [PR #75](https://github.com/konpyutaika/nifikop/pull/75) - **[Operator]** Update PodDisruptionBudget version to policy/v1 instead of policy/v1beta1. diff --git a/api/v1alpha1/nificluster_types.go b/api/v1alpha1/nificluster_types.go index 8138653b4a..c44d06936c 100644 --- a/api/v1alpha1/nificluster_types.go +++ b/api/v1alpha1/nificluster_types.go @@ -177,10 +177,20 @@ type ReadOnlyConfig struct { BootstrapProperties BootstrapProperties `json:"bootstrapProperties,omitempty"` // Logback configuration that will be applied to the node. LogbackConfig LogbackConfig `json:"logbackConfig,omitempty"` + // Authorizer configuration that will be applied to the node. + AuthorizerConfig AuthorizerConfig `json:"authorizerConfig,omitempty"` // BootstrapNotificationServices configuration that will be applied to the node. BootstrapNotificationServicesReplaceConfig BootstrapNotificationServicesConfig `json:"bootstrapNotificationServicesConfig,omitempty"` } +// Optional configuration for the default authorizers.xml template. +type AuthorizerConfig struct { + // A replacement authorizers.xml template configuration that will replace the default template. NOTE: this is a template as seen in authorizers.go. + ReplaceTemplateConfigMap *ConfigmapReference `json:"replaceTemplateConfigMap,omitempty"` + // a replacement authorizers.xml template configuration that will replace the default template and replaceConfigMap. NOTE: this is a template as seen in authorizers.go. + ReplaceTemplateSecretConfig *SecretConfigReference `json:"replaceTemplateSecretConfig,omitempty"` +} + // NifiProperties configuration that will be applied to the node. type NifiProperties struct { // Additionnals nifi.properties configuration that will override the one produced based on template and diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 841c969185..6fa0bee286 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -42,6 +42,31 @@ func (in *AccessPolicy) DeepCopy() *AccessPolicy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthorizerConfig) DeepCopyInto(out *AuthorizerConfig) { + *out = *in + if in.ReplaceTemplateConfigMap != nil { + in, out := &in.ReplaceTemplateConfigMap, &out.ReplaceTemplateConfigMap + *out = new(ConfigmapReference) + **out = **in + } + if in.ReplaceTemplateSecretConfig != nil { + in, out := &in.ReplaceTemplateSecretConfig, &out.ReplaceTemplateSecretConfig + *out = new(SecretConfigReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizerConfig. +func (in *AuthorizerConfig) DeepCopy() *AuthorizerConfig { + if in == nil { + return nil + } + out := new(AuthorizerConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BootstrapNotificationServicesConfig) DeepCopyInto(out *BootstrapNotificationServicesConfig) { *out = *in @@ -1360,6 +1385,7 @@ func (in *ReadOnlyConfig) DeepCopyInto(out *ReadOnlyConfig) { in.ZookeeperProperties.DeepCopyInto(&out.ZookeeperProperties) in.BootstrapProperties.DeepCopyInto(&out.BootstrapProperties) in.LogbackConfig.DeepCopyInto(&out.LogbackConfig) + in.AuthorizerConfig.DeepCopyInto(&out.AuthorizerConfig) in.BootstrapNotificationServicesReplaceConfig.DeepCopyInto(&out.BootstrapNotificationServicesReplaceConfig) } diff --git a/config/crd/bases/nifi.konpyutaika.com_nificlusters.yaml b/config/crd/bases/nifi.konpyutaika.com_nificlusters.yaml index f82d3ae051..b69c5a7ce0 100644 --- a/config/crd/bases/nifi.konpyutaika.com_nificlusters.yaml +++ b/config/crd/bases/nifi.konpyutaika.com_nificlusters.yaml @@ -6093,6 +6093,54 @@ spec: - name type: object type: array + authorizerConfig: + description: Authorizer configuration that will be applied + to the node. + properties: + replaceTemplateConfigMap: + description: 'A replacement authorizers.xml template + configuration that will replace the default template. + NOTE: this is a template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, + that we want use. + type: string + name: + description: Name of the configmap that we want + to refer. + type: string + namespace: + description: Namespace where is located the secret + that we want to refer. + type: string + required: + - data + - name + type: object + replaceTemplateSecretConfig: + description: 'a replacement authorizers.xml template + configuration that will replace the default template + and replaceConfigMap. NOTE: this is a template as + seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, + that we want use. + type: string + name: + description: Name of the configmap that we want + to refer. + type: string + namespace: + description: Namespace where is located the secret + that we want to refer. + type: string + required: + - data + - name + type: object + type: object bootstrapNotificationServicesConfig: description: BootstrapNotificationServices configuration that will be applied to the node. @@ -6523,6 +6571,51 @@ spec: - name type: object type: array + authorizerConfig: + description: Authorizer configuration that will be applied to + the node. + properties: + replaceTemplateConfigMap: + description: 'A replacement authorizers.xml template configuration + that will replace the default template. NOTE: this is a + template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, that + we want use. + type: string + name: + description: Name of the configmap that we want to refer. + type: string + namespace: + description: Namespace where is located the secret that + we want to refer. + type: string + required: + - data + - name + type: object + replaceTemplateSecretConfig: + description: 'a replacement authorizers.xml template configuration + that will replace the default template and replaceConfigMap. + NOTE: this is a template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, that + we want use. + type: string + name: + description: Name of the configmap that we want to refer. + type: string + namespace: + description: Namespace where is located the secret that + we want to refer. + type: string + required: + - data + - name + type: object + type: object bootstrapNotificationServicesConfig: description: BootstrapNotificationServices configuration that will be applied to the node. diff --git a/helm/nifikop/crds/nifi.konpyutaika.com_nificlusters.yaml b/helm/nifikop/crds/nifi.konpyutaika.com_nificlusters.yaml index f82d3ae051..b69c5a7ce0 100644 --- a/helm/nifikop/crds/nifi.konpyutaika.com_nificlusters.yaml +++ b/helm/nifikop/crds/nifi.konpyutaika.com_nificlusters.yaml @@ -6093,6 +6093,54 @@ spec: - name type: object type: array + authorizerConfig: + description: Authorizer configuration that will be applied + to the node. + properties: + replaceTemplateConfigMap: + description: 'A replacement authorizers.xml template + configuration that will replace the default template. + NOTE: this is a template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, + that we want use. + type: string + name: + description: Name of the configmap that we want + to refer. + type: string + namespace: + description: Namespace where is located the secret + that we want to refer. + type: string + required: + - data + - name + type: object + replaceTemplateSecretConfig: + description: 'a replacement authorizers.xml template + configuration that will replace the default template + and replaceConfigMap. NOTE: this is a template as + seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, + that we want use. + type: string + name: + description: Name of the configmap that we want + to refer. + type: string + namespace: + description: Namespace where is located the secret + that we want to refer. + type: string + required: + - data + - name + type: object + type: object bootstrapNotificationServicesConfig: description: BootstrapNotificationServices configuration that will be applied to the node. @@ -6523,6 +6571,51 @@ spec: - name type: object type: array + authorizerConfig: + description: Authorizer configuration that will be applied to + the node. + properties: + replaceTemplateConfigMap: + description: 'A replacement authorizers.xml template configuration + that will replace the default template. NOTE: this is a + template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, that + we want use. + type: string + name: + description: Name of the configmap that we want to refer. + type: string + namespace: + description: Namespace where is located the secret that + we want to refer. + type: string + required: + - data + - name + type: object + replaceTemplateSecretConfig: + description: 'a replacement authorizers.xml template configuration + that will replace the default template and replaceConfigMap. + NOTE: this is a template as seen in authorizers.go.' + properties: + data: + description: The key of the value,in data content, that + we want use. + type: string + name: + description: Name of the configmap that we want to refer. + type: string + namespace: + description: Namespace where is located the secret that + we want to refer. + type: string + required: + - data + - name + type: object + type: object bootstrapNotificationServicesConfig: description: BootstrapNotificationServices configuration that will be applied to the node. diff --git a/pkg/resources/nifi/secretconfig.go b/pkg/resources/nifi/secretconfig.go index d2ff03a52f..42345fe318 100644 --- a/pkg/resources/nifi/secretconfig.go +++ b/pkg/resources/nifi/secretconfig.go @@ -405,6 +405,25 @@ func (r *Reconciler) getAuthorizersConfigString(nConfig *v1alpha1.NodeConfig, id authorizersTemplate := config.EmptyAuthorizersTemplate if r.NifiCluster.Status.NodesState[fmt.Sprint(id)].InitClusterNode { authorizersTemplate = config.AuthorizersTemplate + + // Check for secret/configmap overrides. If there aren't any, then use the default template. + if r.NifiCluster.Spec.ReadOnlyConfig.AuthorizerConfig.ReplaceTemplateConfigMap != nil { + conf, err := r.getConfigMap(context.TODO(), *r.NifiCluster.Spec.ReadOnlyConfig.AuthorizerConfig.ReplaceTemplateConfigMap) + if err == nil { + authorizersTemplate = conf + } + log.Error(err, "error occurred during getting authorizer readonly configmap") + } + + // The secret takes precedence over the ConfigMap, if it exists. + if r.NifiCluster.Spec.ReadOnlyConfig.AuthorizerConfig.ReplaceTemplateSecretConfig != nil { + conf, err := r.getSecrectConfig(context.TODO(), *r.NifiCluster.Spec.ReadOnlyConfig.AuthorizerConfig.ReplaceTemplateSecretConfig) + if err == nil { + authorizersTemplate = conf + } + log.Error(err, "error occurred during getting authorizer readonly secret config") + } + for nId, nodeState := range r.NifiCluster.Status.NodesState { if nodeState.InitClusterNode { nodeList[nId] = utilpki.GetNodeUserName(r.NifiCluster, util.ConvertStringToInt32(nId)) diff --git a/site/docs/3_tasks/2_security/2_authorization/1_custom_authorizer.md b/site/docs/3_tasks/2_security/2_authorization/1_custom_authorizer.md new file mode 100644 index 0000000000..515a8dd806 --- /dev/null +++ b/site/docs/3_tasks/2_security/2_authorization/1_custom_authorizer.md @@ -0,0 +1,83 @@ +--- +id: 1_authorizer +title: Custom User Authorizers +sidebar_label: Custom Authorizers +--- + +:::info +This is an advanced configuration topic. In most cases, the default NiFi authorizer configuration is sufficient. +::: + +According to the NiFi Admin Guide, an [Authorizer](https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#authorizer-configuration) grants users the privileges to manage users and policies by creating preliminary authorizations at startup. By default, the `StandardManagedAuthorizer` leverages a `FileUserGroupProvider` and a `FileAccessPolicyProvider` which are file-based rules for each user you allow to interact with your NiFi cluster. + +In many cases, the default authorizer configuration is enough to control access to a NiFi cluster. However, there may be advanced cases where the default [`managed-authorizer`](https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#standardmanagedauthorizer) isn't sufficient to make every authorization decision you need. In this case, you can provide a custom authorizer extension and use that instead. + +Suppose a custom Authorizer is written and deployed with NiFi that reads the rules from a remote database rather than a local file. We'll call this `DatabaseAuthorizer`. Also suppose it is composed of a `DatabaseUserGroupProvider` and a `DatabaseAccessPolicyProvider`. In order to leverage these, they must end up on NiFi's classpath. + +In order to use this authorizer, you need to update NiFi's `authorizers.xml` configuration. This can be done through NiFiKOp by setting either the `Spec.readOnlyConfig.authorizerConfig.replaceTemplateConfigMap` or `Spec.readOnlyConfig.authorizerConfig.replaceTemplateSecretConfig`. The NiFiKOp deployment is dynamic in that node identities are determined at deploy time, so the authorizer configuration is templated to account for this. This means that the replacement ConfigMap or Secret must also be templated. + +Following the example, the below would be a sufficient authorizer template replacement: + +```yaml +{{- $nodeList := .NodeList }} +{{- $clusterName := .ClusterName }} +{{- $namespace := .Namespace }} + + + file-user-group-provider + org.apache.nifi.authorization.FileUserGroupProvider + ../data/users.xml + + {{ .ControllerUser }} +{{- range $i, $host := .NodeList }} + {{ $host }} +{{- end }} + + + database-user-group-provider + my.custom.DatabaseUserGroupProvider + +{{- range $i, $host := .NodeList }} + {{ $host }} +{{- end }} + + + file-access-policy-provider + org.apache.nifi.authorization.FileAccessPolicyProvider + file-user-group-provider + ../data/authorizations.xml + {{ .ControllerUser }} + +{{- range $i, $host := .NodeList }} + {{ $host }} +{{- end }} + + + + database-access-policy-provider + my.custom.DatabaseAccessPolicyProvider + +{{- range $i, $host := .NodeList }} + {{ $host }} +{{- end }} + + + + managed-authorizer + org.apache.nifi.authorization.StandardManagedAuthorizer + file-access-policy-provider + + + custom-database-authorizer + my.custom.DatabaseAuthorizer + database-access-policy-provider + + +``` + +And finally, the NiFi property `nifi.security.user.authorizer` indicates which of the configured authorizers in the authorizers.xml file to use. Following the example, we'd set the property to: + +```sh +nifi.security.user.authorizer=custom-database-authorizer +``` + diff --git a/site/docs/5_references/1_nifi_cluster/2_read_only_config.md b/site/docs/5_references/1_nifi_cluster/2_read_only_config.md index f7b7f6a793..883d420355 100644 --- a/site/docs/5_references/1_nifi_cluster/2_read_only_config.md +++ b/site/docs/5_references/1_nifi_cluster/2_read_only_config.md @@ -30,6 +30,24 @@ readOnlyConfig: name: raw # Namespace where is located the secret that we want to refer. namespace: nifikop + # Authorizer configuration that will be applied to the node + authorizerConfig: + # An authorizers.xml configuration template that will replace the default template seen in authorizers.go + replaceTemplateConfigMap: + # The key of the value, in data content, that we want use. + data: authorizers.xml + # Name of the configmap that we want to refer. + name: raw + # Namespace where is located the secret that we want to refer. + namespace: nifikop + # An authorizers.xml configuration template that will replace the default template seen in authorizers.go and the replaceTemplateConfigMap + replaceTemplateSecretConfig: + # The key of the value,in data content, that we want use. + data: authorizers.xml + # Name of the configmap that we want to refer. + name: raw + # Namespace where is located the secret that we want to refer. + namespace: nifikop # NifiProperties configuration that will be applied to the node. nifiProperties: # Additionnals nifi.properties configuration that will override the one produced based on template and @@ -132,6 +150,7 @@ readOnlyConfig: |zookeeperProperties|[ZookeeperProperties](#zookeeperproperties)|zookeeper.properties configuration that will be applied to the node.|No|nil| |bootstrapProperties|[BootstrapProperties](#bootstrapproperties)|bootstrap.conf configuration that will be applied to the node.|No|nil| |logbackConfig|[LogbackConfig](#logbackconfig)|logback.xml configuration that will be applied to the node.|No|nil| +|authorizerConfig|[AuthorizerConfig](#authorizerconfig)|authorizers.xml configuration template that will be applied to the node.|No|nil| |bootstrapNotificationServicesConfig|[BootstrapNotificationServices](#bootstrapnotificationservices)|bootstrap_notification_services.xml configuration that will be applied to the node.|No|nil| @@ -172,6 +191,13 @@ readOnlyConfig: |replaceConfigMap|[ConfigmapReference](#configmapreference)|logback.xml configuration that will replace the one produced based on template.|No|nil| |replaceSecretConfig|[SecretConfigReference](#secretconfigreference)|logback.xml configuration that will replace the one produced based on template and overrideConfigMap.|No|nil| +## AuthorizerConfig + +|Field|Type|Description|Required|Default| +|-----|----|-----------|--------|--------| +|replaceTemplateConfigMap|[ConfigmapReference](#configmapreference)|authorizers.xml configuration template that will replace the default template.|No|nil| +|replaceTemplateSecretConfig|[SecretConfigReference](#secretconfigreference)|authorizers.xml configuration that will replace the default template and the replaceTemplateConfigMap.|No|nil| + ## BootstrapNotificationServicesConfig |Field|Type|Description|Required|Default|