Skip to content

Commit

Permalink
Closes #3: Add an option to not generate a random password for admin …
Browse files Browse the repository at this point in the history
…users

Signed-off-by: Ricardo Zanini <[email protected]>
  • Loading branch information
ricardozanini committed May 18, 2020
1 parent faf5a5d commit ca47c66
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 17 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Table of Contents
* [Persistence](#persistence)
* [Minikube](#minikube)
* [Service Account](#service-account)
* [Control random admin password generation](#control-random-admin-password-generation)
* [Red Hat Certified Images](#red-hat-certified-images)

# Nexus Operator
Expand Down Expand Up @@ -182,6 +183,18 @@ It is possible to use a custom [`ServiceAccount`](https://kubernetes.io/docs/ref

**Important**: the Operator handles the creation of default resources necessary to run. If you choose to use a custom ServiceAccount be sure to also configure [`Role`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole) and [`RoleBinding`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) resources.

## Control random admin password generation

By default, from version 0.3.0 the Nexus Operator **does not** generate a random password for the `admin` user. This means that you can login in the server right away with the default administrator credentials (admin/admin123). **Comes in handy for development purposes, but consider changing this password right away on production environments**.

To enable random password generation, you can set the attribute `generateRandomAdminPassword` in the Nexus CR spec to `true`. Then the Nexus service will create a random password in the file system. You have to grab the password from a file inside the Nexus Server container in order to login in the web console:

```
$ kubectl exec <nexus server pod name> -- cat /nexus-data/admin.password
```

Use this password to login into the web console with the username `admin`.

## Red Hat Certified Images

If you have access to [Red Hat Catalog](https://access.redhat.com/containers/#/registry.connect.redhat.com/sonatype/nexus-repository-manager), you might change the flag `spec.useRedHatImage` to `true`.
Expand Down
15 changes: 13 additions & 2 deletions deploy/crds/apps.m88i.io_nexus_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ spec:
spec:
description: NexusSpec defines the desired state of Nexus
properties:
generateRandomAdminPassword:
description: 'GenerateRandomAdminPassword enables the random password
generation. Default to ''false'': the default password for a newly
created instance is ''admin123'', which must be changed in the first
login. If set to ''true'', you must grab the generated ''admin'' password.
To read this password, you have to ssh into the container and read
an auto generated file located at `/nexus-data/admin.password`. Use
`cat` to read the file and view the password. Use it to login for
the first time and follow the on screen instructions to have the Nexus
server ready for use.'
type: boolean
image:
description: 'Full image tag name for this specific deployment Default:
docker.io/sonatype/nexus3:latest'
Expand All @@ -46,7 +57,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down Expand Up @@ -138,7 +149,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ spec:
spec:
description: NexusSpec defines the desired state of Nexus
properties:
generateRandomAdminPassword:
description: 'GenerateRandomAdminPassword enables the random password
generation. Default to ''false'': the default password for a newly
created instance is ''admin123'', which must be changed in the first
login. If set to ''true'', you must grab the generated ''admin'' password.
To read this password, you have to ssh into the container and read
an auto generated file located at `/nexus-data/admin.password`. Use
`cat` to read the file and view the password. Use it to login for
the first time and follow the on screen instructions to have the Nexus
server ready for use.'
type: boolean
image:
description: 'Full image tag name for this specific deployment Default:
docker.io/sonatype/nexus3:latest'
Expand All @@ -46,7 +57,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down Expand Up @@ -138,7 +149,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ spec:
name: A Kubernetes Service
version: v1
specDescriptors:
- description: 'GenerateRandomAdminPassword enables the random password generation.
Default to ''false'': the default password for a newly created instance
is ''admin123'', which must be changed in the first login. If set to ''true'',
you must grab the generated ''admin'' password. To read this password, you
have to ssh into the container and read an auto generated file located at
`/nexus-data/admin.password`. Use `cat` to read the file and view the password.
Use it to login for the first time and follow the on screen instructions
to have the Nexus server ready for use.'
displayName: Generate Random Admin Password
path: generateRandomAdminPassword
- description: 'Full image tag name for this specific deployment Default: docker.io/sonatype/nexus3:latest'
displayName: Image
path: image
Expand Down Expand Up @@ -98,8 +108,7 @@ spec:
* Creates an [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress/) in Kubernetes (1.14+) environments to expose the application to the world
* On OpenShift, creates a Route to expose the service outside the cluster
After installing it, you will have to grab the `admin` user password from the deployed container. There's a file auto generated in `/nexus-data/admin.password`.
Use `cat` to read the file and view the password. Use it to login for the first time and follow the on screen instructions to have the Nexus server ready for use.
[See our documentation](https://github.com/m88i/nexus-operator/blob/master/README.md) for more installation and usage scenarios.
If you experience any issues or have any ideas for new features, please [file an issue in our Github repository](https://github.com/m88i/nexus-operator/issues) or send an email to our maillist: [[email protected]](mailto:[email protected])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ spec:
spec:
description: NexusSpec defines the desired state of Nexus
properties:
generateRandomAdminPassword:
description: 'GenerateRandomAdminPassword enables the random password
generation. Default to ''false'': the default password for a newly
created instance is ''admin123'', which must be changed in the first
login. If set to ''true'', you must grab the generated ''admin'' password.
To read this password, you have to ssh into the container and read
an auto generated file located at `/nexus-data/admin.password`. Use
`cat` to read the file and view the password. Use it to login for
the first time and follow the on screen instructions to have the Nexus
server ready for use.'
type: boolean
image:
description: 'Full image tag name for this specific deployment Default:
docker.io/sonatype/nexus3:latest'
Expand All @@ -46,7 +57,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down Expand Up @@ -138,7 +149,7 @@ spec:
type: integer
initialDelaySeconds:
description: Number of seconds after the container has started before
liveness probes are initiated.
probes are initiated.
format: int32
type: integer
periodSeconds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ spec:
name: A Kubernetes Service
version: v1
specDescriptors:
- description: 'GenerateRandomAdminPassword enables the random password generation.
Default to ''false'': the default password for a newly created instance
is ''admin123'', which must be changed in the first login. If set to ''true'',
you must grab the generated ''admin'' password. To read this password, you
have to ssh into the container and read an auto generated file located at
`/nexus-data/admin.password`. Use `cat` to read the file and view the password.
Use it to login for the first time and follow the on screen instructions
to have the Nexus server ready for use.'
displayName: Generate Random Admin Password
path: generateRandomAdminPassword
- description: 'Full image tag name for this specific deployment Default: docker.io/sonatype/nexus3:latest'
displayName: Image
path: image
Expand Down Expand Up @@ -98,8 +108,7 @@ spec:
* Creates an [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress/) in Kubernetes (1.14+) environments to expose the application to the world
* On OpenShift, creates a Route to expose the service outside the cluster
After installing it, you will have to grab the `admin` user password from the deployed container. There's a file auto generated in `/nexus-data/admin.password`.
Use `cat` to read the file and view the password. Use it to login for the first time and follow the on screen instructions to have the Nexus server ready for use.
[See our documentation](https://github.com/m88i/nexus-operator/blob/master/README.md) for more installation and usage scenarios.
If you experience any issues or have any ideas for new features, please [file an issue in our Github repository](https://github.com/m88i/nexus-operator/issues) or send an email to our maillist: [[email protected]](mailto:[email protected])
Expand Down
2 changes: 1 addition & 1 deletion examples/nexus3-centos-no-volume.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spec:
memory: "2Gi"
# Data persistence details
persistence:
# Should we persist Nexus data? Yes, please. (turn this to false only if you're evaluating this resource)
# Should we persist Nexus data? (turn this to false only if you're evaluating this resource)
persistent: false
# details regarding networking
networking:
Expand Down
11 changes: 11 additions & 0 deletions pkg/apis/apps/v1alpha1/nexus_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ type NexusSpec struct {
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.x-descriptors="urn:alm:descriptor:com.tectonic.ui:booleanSwitch"
UseRedHatImage bool `json:"useRedHatImage"`

// GenerateRandomAdminPassword enables the random password generation.
// Default to 'false': the default password for a newly created instance is 'admin123', which must be changed in the first login.
// If set to 'true', you must grab the generated 'admin' password.
// To read this password, you have to ssh into the container and read an auto generated file located at `/nexus-data/admin.password`.
// Use `cat` to read the file and view the password.
// Use it to login for the first time and follow the on screen instructions to have the Nexus server ready for use.
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Generate Random Admin Password"
// +optional
GenerateRandomAdminPassword bool `json:"generateRandomAdminPassword,omitempty"`

// Networking definition
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=false
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Networking"
Expand Down
9 changes: 8 additions & 1 deletion pkg/apis/apps/v1alpha1/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 43 additions & 5 deletions pkg/controller/nexus/resource/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package resource

import (
"fmt"
"sort"
"strconv"
"strings"

"github.com/m88i/nexus-operator/pkg/apis/apps/v1alpha1"
"github.com/m88i/nexus-operator/pkg/util"
Expand All @@ -36,13 +39,25 @@ const (
2. Xmx
3. MaxDirectMemorySize
*/
jvmArgsEnvValueFormat = "-Xms%s -Xmx%s -XX:MaxDirectMemorySize=%s -Djava.util.prefs.userRoot=${NEXUS_DATA}/javaprefs"
jvmArgsXms = "-Xms"
jvmArgsXmx = "-Xmx"
jvmArgsMaxMemSize = "-XX:MaxDirectMemorySize"
jvmArgsUserRoot = "-Djava.util.prefs.userRoot"
jvmArgRandomPassword = "-Dnexus.security.randompassword"
heapSizeDefault = "1200m"
maxDirectMemorySizeDefault = "2g"
probeInitialDelaySeconds = int32(120)
probeInitialDelaySeconds = int32(240)
probeTimeoutSeconds = int32(15)
)

var jvmArgsMap = map[string]string{
jvmArgsXms: heapSizeDefault,
jvmArgsXmx: heapSizeDefault,
jvmArgsMaxMemSize: maxDirectMemorySizeDefault,
jvmArgsUserRoot: "${NEXUS_DATA}/javaprefs",
jvmArgRandomPassword: "false",
}

func newDeployment(nexus *v1alpha1.Nexus, pvc *v1.PersistentVolumeClaim) *appsv1.Deployment {
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -85,7 +100,7 @@ func newDeployment(nexus *v1alpha1.Nexus, pvc *v1.PersistentVolumeClaim) *appsv1
applyDefaultResourceReqs(nexus, deployment)
addVolume(nexus, pvc, deployment)
addProbes(nexus, deployment)
applyJVMArgs(deployment)
applyJVMArgs(nexus, deployment)
addServiceAccount(nexus, deployment)

return deployment
Expand Down Expand Up @@ -176,13 +191,36 @@ func addVolume(nexus *v1alpha1.Nexus, pvc *v1.PersistentVolumeClaim, deployment
}
}

func applyJVMArgs(deployment *appsv1.Deployment) {
func applyJVMArgs(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
jvmMemory, directMemSize := calculateJVMMemory(deployment.Spec.Template.Spec.Containers[0].Resources.Limits)
jvmArgsMap[jvmArgsXms] = jvmMemory
jvmArgsMap[jvmArgsXmx] = jvmMemory
jvmArgsMap[jvmArgsMaxMemSize] = directMemSize
jvmArgsMap[jvmArgRandomPassword] = strconv.FormatBool(nexus.Spec.GenerateRandomAdminPassword)

// we cannot guarantee the key order when transforming the map into a single string.
// this might create different strings across the reconciliation loop, causing the comparator to accuse the deployment to be different
// that's why we have to sort the map every time.
var jvmArgs strings.Builder
var jvmArgsKeys []string
for key := range jvmArgsMap {
jvmArgsKeys = append(jvmArgsKeys, key)
}
sort.Strings(jvmArgsKeys)
for _, key := range jvmArgsKeys {
jvmArgs.WriteString(key)
if key != jvmArgsXms && key != jvmArgsXmx {
jvmArgs.WriteString("=")
}
jvmArgs.WriteString(jvmArgsMap[key])
jvmArgs.WriteString(" ")
}

deployment.Spec.Template.Spec.Containers[0].Env =
append(deployment.Spec.Template.Spec.Containers[0].Env,
v1.EnvVar{
Name: jvmArgsEnvKey,
Value: fmt.Sprintf(jvmArgsEnvValueFormat, jvmMemory, jvmMemory, directMemSize),
Value: jvmArgs.String(),
})
}

Expand Down
46 changes: 46 additions & 0 deletions pkg/controller/nexus/resource/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package resource

import (
"strings"
"testing"

"github.com/m88i/nexus-operator/pkg/apis/apps/v1alpha1"
Expand Down Expand Up @@ -159,3 +160,48 @@ func Test_customProbes(t *testing.T) {
assert.Equal(t, int32(0), deployment.Spec.Template.Spec.Containers[0].LivenessProbe.InitialDelaySeconds)
assert.Equal(t, int32(probeInitialDelaySeconds), deployment.Spec.Template.Spec.Containers[0].ReadinessProbe.InitialDelaySeconds)
}

func Test_applyJVMArgs_withRandomPassword(t *testing.T) {
appName := "nexus3"
nexus := &v1alpha1.Nexus{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: t.Name(),
},
Spec: v1alpha1.NexusSpec{
Replicas: 1,
Persistence: v1alpha1.NexusPersistence{
Persistent: true,
},
GenerateRandomAdminPassword: true,
},
}
pvc := newPVC(nexus)
deployment := newDeployment(nexus, pvc)

assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgRandomPassword, "true"}, "="))
assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgsXms, heapSizeDefault}, ""))
assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgsXmx, heapSizeDefault}, ""))
}

func Test_applyJVMArgs_withDefaultValues(t *testing.T) {
appName := "nexus3"
nexus := &v1alpha1.Nexus{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: t.Name(),
},
Spec: v1alpha1.NexusSpec{
Replicas: 1,
Persistence: v1alpha1.NexusPersistence{
Persistent: true,
},
},
}
pvc := newPVC(nexus)
deployment := newDeployment(nexus, pvc)

assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgRandomPassword, "false"}, "="))
assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgsXms, heapSizeDefault}, ""))
assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env[0].Value, strings.Join([]string{jvmArgsXmx, heapSizeDefault}, ""))
}

0 comments on commit ca47c66

Please sign in to comment.