thelabdude commented on a change in pull request #221: URL: https://github.com/apache/lucene-solr-operator/pull/221#discussion_r577999978
########## File path: controllers/util/solr_util.go ########## @@ -1158,3 +1195,170 @@ func createZkConnectionEnvVars(solrCloud *solr.SolrCloud, solrCloudStatus *solr. return envVars, solrOpt, len(zkChroot) > 1 } + +func setupVolumeMountForUserProvidedConfigMapEntry(configMapInfo map[string]string, fileKey string, solrVolumes []corev1.Volume, envVar string) (*corev1.VolumeMount, *corev1.EnvVar, *corev1.Volume) { + volName := strings.ReplaceAll(fileKey, ".", "-") + mountPath := fmt.Sprintf("/var/solr/%s", configMapInfo[fileKey]) + appendedToExisting := false + if configMapInfo[fileKey] == configMapInfo[SolrXmlFile] { + // the user provided a custom log4j2.xml and solr.xml, append to the volume for solr.xml created above + for _, vol := range solrVolumes { + if vol.Name == "solr-xml" { + vol.ConfigMap.Items = append(vol.ConfigMap.Items, corev1.KeyToPath{Key: fileKey, Path: fileKey}) + appendedToExisting = true + volName = vol.Name + break + } + } + } + + var vol *corev1.Volume = nil + if !appendedToExisting { + defaultMode := int32(420) + vol = &corev1.Volume{ + Name: volName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: configMapInfo[fileKey]}, + Items: []corev1.KeyToPath{{Key: fileKey, Path: fileKey}}, + DefaultMode: &defaultMode, + }, + }, + } + } + pathToFile := fmt.Sprintf("%s/%s", mountPath, fileKey) + + return &corev1.VolumeMount{Name: volName, MountPath: mountPath}, &corev1.EnvVar{Name: envVar, Value: pathToFile}, vol +} + +func GenerateSecurityJsonConfigMap(solrCloud *solr.SolrCloud, basicAuthSecret *corev1.Secret) *corev1.ConfigMap { + labels := solrCloud.SharedLabelsWith(solrCloud.GetLabels()) + var annotations map[string]string + + customOptions := solrCloud.Spec.CustomSolrKubeOptions.ConfigMapOptions + if nil != customOptions { + labels = MergeLabelsOrAnnotations(labels, customOptions.Labels) + annotations = MergeLabelsOrAnnotations(annotations, customOptions.Annotations) + } + + username := solrCloud.BasicAuthUsername() + + blockUnknown := true + anonymousPaths := "" + if solrCloud.Spec.SolrSecurity.InitAnonymousEndpoints != nil && len(solrCloud.Spec.SolrSecurity.InitAnonymousEndpoints) > 0 { + blockUnknown = false // to allow anonymous access to query endpoints + + for i, path := range solrCloud.Spec.SolrSecurity.InitAnonymousEndpoints { + fromPath := strings.ReplaceAll(strings.ReplaceAll(path, "/", "_"), "*", "_") + name := fmt.Sprintf("anonymous%d%s", i, fromPath) + anonymousPaths += fmt.Sprintf(", { \"name\": \"%s\", \"path\": \"%s\", \"collection\": \"*\", \"role\": null }", name, path) + } + } + + // create a security.json with the same passwords from our secret + // hashed with random salt, just as Solr's hashing works + adminPasswordHash := solrPasswordHash(basicAuthSecret.Data["admin"]) + operPasswordHash := solrPasswordHash(basicAuthSecret.Data[username]) + solrPasswordHash := solrPasswordHash(basicAuthSecret.Data["solr"]) + + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: solrCloud.SecurityJsonConfigMapName(), + Namespace: solrCloud.GetNamespace(), + Labels: labels, + Annotations: annotations, + }, + Data: map[string]string{ + SecurityJsonFile: fmt.Sprintf(`{ + "authentication":{ + "blockUnknown": %t, + "class":"solr.BasicAuthPlugin", + "credentials": { + "admin": "%s", + "%s": "%s", + "solr": "%s" + }, + "realm":"Solr Basic Auth", + "forwardCredentials": false + }, + "authorization": { + "class": "solr.RuleBasedAuthorizationPlugin", + "user-role": { + "admin": ["admin", "probe"], + "%s": ["probe"], + "solr": ["users", "probe"] + }, + "permissions": [ + { "name": "k8s-probes", "role":"probe", "collection": null, "path":"/admin/info/system" }, + { "name": "k8s-status", "role":"probe", "collection": null, "path":"/admin/collections" }, + { "name": "all", "role":["admin","users"] }, + { "name": "read", "role":["admin","users"] }, + { "name": "update", "role":["admin"] }, + { "name": "security-read", "role": "admin"}, + { "name": "security-edit", "role": "admin"}%s + ] + } + }`, blockUnknown, adminPasswordHash, username, operPasswordHash, solrPasswordHash, username, anonymousPaths), + }, + } + return configMap +} + +func GenerateBasicAuthSecret(solrCloud *solr.SolrCloud) *corev1.Secret { + labels := solrCloud.SharedLabelsWith(solrCloud.GetLabels()) + var annotations map[string]string + + username := solrCloud.BasicAuthUsername() + + // setup a secret with random passwords + adminPassword := randomPassword() + operPassword := randomPassword() + solrPassword := randomPassword() + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: solrCloud.BasicAuthSecretName(), + Namespace: solrCloud.GetNamespace(), + Labels: labels, + Annotations: annotations, + }, + Data: map[string][]byte{ + "admin": adminPassword, + username: operPassword, + "solr": solrPassword, + }, + Type: "Opaque", + } +} + +func randomPassword() []byte { + rand.Seed(time.Now().UnixNano()) + lower := "abcdefghijklmnpqrstuvwxyz" // no 'o' + upper := strings.ToUpper(lower) + digits := "0123456789" + chars := lower + upper + digits + "()[]%#@-()[]%#@-" + pass := make([]byte, 16) + // start with a lower char and end with an upper + pass[0] = lower[rand.Intn(len(lower))] + pass[len(pass)-1] = upper[rand.Intn(len(upper))] + perm := rand.Perm(len(chars)) + for i := 1; i < len(pass)-1; i++ { + pass[i] = chars[perm[i]] + } + return pass +} + +// this mimics the password hash generation approach used by Solr +func solrPasswordHash(passBytes []byte) string { Review comment: See Solr's Sha256AuthenticationProvider: https://github.com/apache/lucene-solr/blob/master/solr/core/src/java/org/apache/solr/security/Sha256AuthenticationProvider.java#L114 ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: issues-unsubscr...@lucene.apache.org For additional commands, e-mail: issues-h...@lucene.apache.org