UNCLASSIFIED

Commit 60eb7754 authored by Grant Duncklee's avatar Grant Duncklee
Browse files

Merge branch 'bb-103/bigbang-nexus-iq' into 'master'

Bb 103/bigbang nexus iq

See merge request !2
parents 406b8cbc 2a2248a9
# Changelog
* @grant.duncklee
# Contributing
Thanks for contributing to this repository!
This repository follows the following conventions:
* [Semantic Versioning](https://semver.org/)
* [Keep a Changelog](https://keepachangelog.com/)
* [Conventional Commits](https://www.conventionalcommits.org/)
Development requires the Kubernetes CLI tool as well as a local Kubernetes cluster. [k3d](https://k3d.io) is recommended as a lightweight local option for standing up Kubernetes clusters.
To contribute a change:
1. Create a branch on the cloned repository
2. Make the changes in code.
3. Write tests using [cypress](https://www.cypress.io) and [Conftest](https://conftest.dev)
4. Make commits using the [Conventional Commits](https://www.conventionalcommits.org/) format. This helps with automation for changelog. Update `CHANGELOG.md` in the same commit using the [Keep a Changelog](https://keepachangelog.com). Depending on tooling maturity, this step may be automated.
5. Open a merge request using one of the provided templates. If this merge request is solving a preexisting issue, add the issue reference into the description of the MR.
6. During this time, ensure that all new commits are rebased into your branch so that it remains up to date with the `main` branch.
7. Wait for a maintainer of the repository (see CODEOWNERS) to approve.
8. If you have permissions to merge, you are responsible for merging. Otherwise, a CODEOWNER will merge the commit.
# nexus-iq # Sonatype Nexus IQ
Monitoring and notifications of open source vulnerabilities
This chart was sourced from
[Sonatype's Helm Charts.](https://github.com/sonatype/helm3-charts) with
minimal changes.
## Prerequisites
- Kubernetes Cluster deployed
- Kubernetes config installed in ~/.kube/config
- Helm installed
- Keycloak (Optional - SSO)
- Sonatype NXIQ License. Required for SAML integration
## Iron Bank
You can `pull` the Iron Bank image [here](https://registry1.dso.mil/harbor/projects/3/repositories/sonatype%2Fnexus-iq-server%2Fnexus-iq-server) and view the container approval [here](https://ironbank.dso.mil/repomap/sonatype/nexus-iq-server).
## Helm
Please reference complete list of providable variables
[here](https://github.com/sonatype/helm3-charts/tree/master/charts/nexus-iq#chart-configuration-options)
```bash
git clone https://repo1.dso.mil/platform-one/big-bang/apps/third-party/nexus-iq.git
helm install nexus-iq chart
```
## BigBang Additions, Comments, and Important Information
### SAML/SSO Integration
BigBang requires/prefers SAML/SSO integration out of the box, unfortunately, the upstream Helm chart did not have a
solution at the drafting of this integration. To achieve our goal, we added a Kubernetes job that handles the SAML/SSO
integration. To enable this functionality, ensure `sso.enabled` is set to `true`; you will additionally require a
Keycloak instance, the IDP metadata file, along with the other parameters you may define in the `values.yaml`. Our
implementation closely followed [Sonatype's API](https://help.sonatype.com/iqserver/automating/rest-apis/saml-rest-api---v2#SAMLRESTAPI-v2-ConfigureSAMLIntegration).
### Default Admin Password
Sonatype's API prevents the changing of a user's password via API. It was deemed more feature-breaking to introduce a
viable workaround. Please change your admin password immediately.
Sonatype is tracking this issue with an internal ticket.
### License
We expect you to secure your license; the license will be provided as a binary. Encode the binary file as a base64
encoded string, secure with sops, and place in `.Values.addons.nexusRepositoryManager.license_key`. The `_helpers.tpl`
will create a named template and generate the appropriate secret within the namespace. The chart will reference the
license via a secret volumeMount to ensure the application starts licensed.
apiVersion: v2
name: nexus-iq-server
version: 103.0.1-bb.0
appVersion: 1.103.0
type: application
keywords:
- sonatype
- nexus
- lifecycle
- iq
- remediate
- vulnerabilities
- policy
home: https://www.sonatype.com/product-nexus-lifecycle
icon: https://sonatype.github.io/helm3-charts/NexusIQServer_Vertical.svg
maintainers:
- email: support@sonatype.com
name: Sonatype
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "iqserver.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "iqserver.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "iqserver.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.appliocationPort }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "iqserver.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8070 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8070:8070
{{- end }}
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "iqserver.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "iqserver.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "iqserver.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common labels
*/}}
{{- define "iqserver.labels" -}}
app.kubernetes.io/name: {{ include "iqserver.name" . }}
helm.sh/chart: {{ include "iqserver.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Selector labels
*/}}
{{- define "iqserver.selectorLabels" -}}
app.kubernetes.io/name: {{ include "iqserver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "iq.licenseKey" -}}
{{- if .Values.license_key }}
sonatype-license.lic: {{ .Values.license_key }}
{{- end }}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "iqserver.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "iqserver.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
{{- if .Values.sso.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "iqserver.fullname" . }}-sso
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
data:
idpmetadata.xml: {{ .Values.sso.idp_metadata }}
sso_data: {{ .Values.sso.attributes | toJson | quote }}
{{- end -}}
{{- if .Values.license_key }}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "iqserver.fullname" . }}-license
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
data:
{{ include "iq.licenseKey" . | indent 2 }}
{{- end }}
{{- if and .Values.sso.enabled .Values.license_key }}
apiVersion: batch/v1
kind: Job
metadata:
annotations:
"helm.sh/hook": post-install
name: post-install
spec:
template:
metadata:
creationTimestamp: null
spec:
activeDeadlineSeconds: 60
volumes:
{{- if .Values.sso.enabled }}
- name: idp
configMap:
name: {{ template "iqserver.fullname" . }}-sso
items:
- key: idpmetadata.xml
path: idpmetadata.xml
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- image: "{{ .Values.job_image.repository }}:{{ .Values.job_image.tag }}"
imagePullPolicy: {{ .Values.job_image.pullPolicy }}
name: post-install
volumeMounts:
- mountPath: /tmp/
name: idp
command:
- sh
args:
- -c
- |-
BASE_URL="http://{{ template "iqserver.fullname" . }}.{{ template "iqserver.fullname" . }}-server.svc.cluster.local:{{ .Values.iq.applicationPort }}";
until curl --head localhost:15000; do echo "Waiting for Sidercar"; sleep 10; done; echo "Sidecar available";
while [ "$(curl -s "${BASE_URL}/rest/product/license")" == "No valid product license installed." ]; do echo "Waiting for License"; sleep 5; done;
curl -X PUT \
-u admin:admin123 \
"${BASE_URL}/api/v2/config/saml" \
-F identityProviderXml=@/tmp/idpmetadata.xml \
-F samlConfiguration='{{ .Values.sso.samlConfiguration | toJson }}';
curl -fsI -X POST http://localhost:15020/quitquitquit;
exit
resources: {}
restartPolicy: Never
status: {}
{{- end }}
{{- if .Values.istio.enabled -}}
{{- $serviceName := include "iqserver.fullname" . -}}
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: {{ template "iqserver.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "iqserver.name" . }}
helm.sh/chart: {{ include "iqserver.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: nexus-iq-server
app.kubernetes.io/component: {{ include "iqserver.name" . }}
spec:
gateways:
- main.istio-system.svc.cluster.local
hosts:
- "{{ .Values.hostname }}.{{ .Values.domain }}"
http:
- route:
- destination:
port:
number: {{ .Values.iq.applicationPort }}
host: {{ $serviceName }}
- route:
- destination:
port:
number: {{ .Values.iq.adminPort }}
host: {{ $serviceName }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "iqserver.fullname" . }}-conf
labels:
{{ include "iqserver.labels" . | indent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
data:
config.yml: |
{{ toYaml .Values.configYaml | indent 4 }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "iqserver.fullname" . }}
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
type: {{ .Values.deploymentStrategy }}
selector:
matchLabels:
{{- include "iqserver.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "iqserver.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "iqserver.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
{{ toYaml .Values.iq.env | indent 12 }}
ports:
- name: application
containerPort: {{ .Values.iq.applicationPort }}
protocol: TCP
- name: admin
containerPort: {{ .Values.iq.adminPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /ping
port: admin
failureThreshold: 5
initialDelaySeconds: 60
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: application
failureThreshold: 5
initialDelaySeconds: 60
periodSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- mountPath: /sonatype-work
name: nxiq-pv-data
- mountPath: /etc/nexus-iq-server
name: config-volume
{{- if .Values.license_key }}
- mountPath: /etc/nexus-iq-license
name: license-volume
{{- end }}
volumes:
- name: nxiq-pv-data
persistentVolumeClaim:
claimName: {{ template "iqserver.fullname" . }}-data
- name: config-volume
configMap:
name: {{ template "iqserver.fullname" . }}-conf
items:
- key: config.yml
path: config.yml
{{- if .Values.license_key }}
- name: license-volume
secret:
secretName: {{ template "iqserver.fullname" . }}-license
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.iq.imagePullSecret -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "iqserver.fullname" . }}-imagepull
data:
.dockerconfigjson: {{ .Values.iq.imagePullSecret }}
type: kubernetes.io/dockerconfigjson
{{- end }}
\ No newline at end of file
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "iqserver.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- $ingressPath := .Values.ingress.path -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
- host: {{ .Values.ingress.hostUI }}
http:
paths:
- path: {{ .Values.ingress.hostUIPath }}
backend:
serviceName: {{ $fullName }}
servicePort: 8070
- host: {{ .Values.ingress.hostAdmin }}
http:
paths:
- path: {{ .Values.ingress.hostAdminPath }}
backend:
serviceName: {{ $fullName }}
servicePort: 8071
{{- end }}
{{- if .Values.iq.licenseSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "iqserver.fullname" . }}-license
data:
license_lic: {{ .Values.iq.licenseSecret }}
{{- end }}
{{- if .Values.persistence.volumeConfiguration -}}
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ template "iqserver.fullname" . }}-data
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
capacity:
storage: {{ .Values.persistence.storageSize }}
persistentVolumeReclaimPolicy: Recycle
{{ toYaml .Values.persistence.volumeConfiguration | indent 2 }}
{{- end }}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ template "iqserver.fullname" . }}-data
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
{{- if .Values.persistence.annotations }}
annotations:
{{ toYaml .Values.persistence.annotations | indent 2 }}
{{- end }}
spec:
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.storageSize | quote }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "iqserver.fullname" . }}
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: 8070
targetPort: application
protocol: TCP
name: application
- port: 8071
targetPort: admin
protocol: TCP
name: admin
selector:
{{- include "iqserver.selectorLabels" . | nindent 4 }}
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "iqserver.serviceAccountName" . }}
labels:
{{- include "iqserver.labels" . | nindent 4 }}
{{- if .Values.iq.extraLabels }}
{{- with .Values.iq.extraLabels }}
{{ toYaml . | indent 4 }}
{{- end }}
{{- end }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end -}}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment