Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(reports): add auth proxy protecting report generators #206

Merged
merged 18 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions charts/cryostat/README.md

Large diffs are not rendered by default.

20 changes: 19 additions & 1 deletion charts/cryostat/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,24 @@ Get or generate a default secret key for object storage.
{{- end -}}
{{- end -}}

{{/*
Get or generate a default secret password key for report generators.
*/}}
{{- define "cryostat.reportsPassSecretKey" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-reports-secret" .Release.Name)) -}}
{{- if $secret -}}
{{/*
Use current secret. Do not regenerate.
*/}}
{{- $secret.data.REPORTS_PASS -}}
{{- else -}}
{{/*
Generate new secret
*/}}
{{- (randAlphaNum 32) -}}
{{- end -}}
{{- end -}}

{{/*
Get or generate a default secret key for auth proxy cookies.
*/}}
Expand All @@ -130,7 +148,7 @@ Get or generate a default secret key for auth proxy cookies.
{{/*
Generate new secret
*/}}
{{- (randAlphaNum 32) | b64enc | quote -}}
{{- (randAlphaNum 32) | b64enc -}}
{{- end -}}
{{- end -}}

Expand Down
2 changes: 1 addition & 1 deletion charts/cryostat/templates/_openshiftOauthProxy.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Create OpenShift OAuth Proxy container.
- --pass-basic-auth=false
- --upstream=http://localhost:8181/
- --upstream=http://localhost:3000/grafana/
- --cookie-secret="$(COOKIE_SECRET)"
- --cookie-secret=$(COOKIE_SECRET)
- --openshift-service-account={{ include "cryostat.serviceAccountName" . }}
- --proxy-websockets=true
- --http-address=0.0.0.0:4180
Expand Down
92 changes: 92 additions & 0 deletions charts/cryostat/templates/_reports_authproxy.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{{- define "cryostat.reportsAuthProxy" -}}
{{- if (.Values.authentication.openshift).enabled }}
- name: {{ printf "%s-reports-%s" .Chart.Name "authproxy" }}
securityContext:
{{- toYaml .Values.openshiftOauthProxy.securityContext | nindent 4 }}
image: "{{ .Values.openshiftOauthProxy.image.repository }}:{{ .Values.openshiftOauthProxy.image.tag }}"
env:
- name: COOKIE_SECRET
valueFrom:
secretKeyRef:
name: {{ default (printf "%s-cookie-secret" .Release.Name) .Values.authentication.cookieSecretName }}
key: COOKIE_SECRET
optional: false
args:
- --pass-access-token=false
- --pass-user-bearer-token=false
- --pass-basic-auth=false
- --htpasswd-file=/etc/oauth2_proxy/basicauth/htpasswd
- --upstream=http://localhost:10001/
- --cookie-secret=$(COOKIE_SECRET)
- --request-logging=true
- --openshift-service-account={{ include "cryostat.serviceAccountName" . }}
- --proxy-websockets=true
- --http-address=0.0.0.0:4180
- --https-address=:8443
- --tls-cert=/etc/tls/private/tls.crt
- --tls-key=/etc/tls/private/tls.key
- --proxy-prefix=/oauth2
- --bypass-auth-for=^/health?$
ebaron marked this conversation as resolved.
Show resolved Hide resolved
imagePullPolicy: {{ .Values.openshiftOauthProxy.image.pullPolicy }}
ports:
- containerPort: 4180
name: http
protocol: TCP
- containerPort: 8443
name: https
protocol: TCP
resources:
{{- toYaml .Values.openshiftOauthProxy.resources | nindent 4 }}
volumeMounts:
- name: {{ .Release.Name }}-proxy-tls
mountPath: /etc/tls/private
- name: {{ .Release.Name }}-reports-secret
mountPath: /etc/oauth2_proxy/basicauth
readOnly: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
{{- else }}
- name: {{ printf "%s-reports-%s" .Chart.Name "authproxy" }}
securityContext:
{{- toYaml (.Values.oauth2Proxy).securityContext | nindent 4 }}
image: "{{ (.Values.oauth2Proxy).image.repository }}:{{ (.Values.oauth2Proxy).image.tag }}"
imagePullPolicy: {{ (.Values.oauth2Proxy).image.pullPolicy }}
env:
- name: OAUTH2_PROXY_CLIENT_ID
value: dummy
- name: OAUTH2_PROXY_CLIENT_SECRET
value: none
- name: OAUTH2_PROXY_HTTP_ADDRESS
value: 0.0.0.0:4180
- name: OAUTH2_PROXY_UPSTREAMS
value: http://localhost:10001/
- name: OAUTH2_PROXY_REDIRECT_URL
value: "http://localhost:4180/oauth2/callback"
- name: OAUTH2_PROXY_COOKIE_SECRET
valueFrom:
secretKeyRef:
name: {{ default (printf "%s-cookie-secret" .Release.Name) .Values.authentication.cookieSecretName }}
key: COOKIE_SECRET
optional: false
- name: OAUTH2_PROXY_EMAIL_DOMAINS
value: "*"
- name: OAUTH2_PROXY_HTPASSWD_USER_GROUP
value: write
- name: OAUTH2_PROXY_HTPASSWD_FILE
value: /etc/oauth2_proxy/basicauth/htpasswd
- name: OAUTH2_PROXY_SKIP_AUTH_ROUTES
value: "^/health?$"
- name: OAUTH2_PROXY_PROXY_WEBSOCKETS
value: "false"
ports:
- containerPort: 4180
name: http
protocol: TCP
resources:
{{- toYaml .Values.oauth2Proxy.resources | nindent 4 }}
volumeMounts:
- name: {{ .Release.Name }}-reports-secret
mountPath: /etc/oauth2_proxy/basicauth
readOnly: true
{{- end }}
{{- end}}
13 changes: 12 additions & 1 deletion charts/cryostat/templates/cryostat_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,19 @@ spec:
- name: QUARKUS_HIBERNATE_ORM_SQL_LOAD_SCRIPT
value: no-file
{{- if gt (int (.Values.reports).replicas) 0 }}
- name: REPORTS_PASS_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ default (printf "%s-reports-secret" .Release.Name) .Values.reports.reportsSecretName }}
key: REPORTS_PASS
optional: false
# TODO TLS trust
- name: QUARKUS_TLS_TRUST_ALL
value: "true"
- name: QUARKUS_REST_CLIENT_EXTENSIONS_API_VERIFY_HOST
value: "false"
- name: QUARKUS_REST_CLIENT_REPORTS_URL
value: {{ printf "http://%s-reports:%d" $fullName (int .Values.reports.service.httpPort) }}
value: {{ printf "%s://cryostat:$(REPORTS_PASS_SECRET_KEY)@%s-reports.%s.svc:%d" (ternary "https" "http" (.Values.authentication.openshift).enabled) $fullName $.Release.Namespace (int .Values.reports.service.httpPort) }}
{{- end }}
- name: QUARKUS_DATASOURCE_USERNAME
value: cryostat
Expand Down
13 changes: 13 additions & 0 deletions charts/cryostat/templates/reports_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ spec:
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
{{- include "cryostat.reportsAuthProxy" . | nindent 8 }}
- name: {{ printf "%s-%s" .Chart.Name "reports" }}
securityContext:
{{- toYaml (.Values.reports).securityContext | nindent 12 }}
Expand All @@ -42,6 +43,8 @@ spec:
env:
- name: QUARKUS_HTTP_PORT
value: "{{ .Values.reports.service.httpPort }}"
- name: QUARKUS_LOG_LEVEL
value: {{ .Values.reports.debug.log.level }}
ports:
- containerPort: {{ .Values.reports.service.httpPort }}
protocol: TCP
Expand Down Expand Up @@ -71,4 +74,14 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: {{ .Release.Name }}-reports-secret
secret:
defaultMode: 0440
secretName: {{ .Release.Name }}-reports-secret
{{- if (.Values.authentication.openshift).enabled }}
- name: {{ .Release.Name }}-proxy-tls
secret:
secretName: {{ .Release.Name }}-proxy-tls
{{- end }}
{{- end -}}
13 changes: 13 additions & 0 deletions charts/cryostat/templates/reports_secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{- if empty .Values.reports.reportsSecretName -}}
{{- $secretKey := include "cryostat.reportsPassSecretKey" . -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-reports-secret
labels:
{{- include "cryostat.labels" $ | nindent 4 }}
type: Opaque
data:
REPORTS_PASS: {{ $secretKey | b64enc }}
htpasswd: {{ htpasswd "cryostat" $secretKey | b64enc }}
{{- end -}}
4 changes: 2 additions & 2 deletions charts/cryostat/templates/reports_service.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{- $fullName := include "cryostat.fullname" . -}}
---
{{- if gt (int (.Values.reports).replicas) 0 -}}
{{- $fullName := include "cryostat.fullname" . -}}
apiVersion: v1
kind: Service
metadata:
Expand All @@ -12,6 +11,7 @@ spec:
type: {{ .Values.reports.service.type }}
ports:
- port: {{ .Values.reports.service.httpPort }}
targetPort: {{ ternary "https" "http" (.Values.authentication.openshift).enabled }}
selector:
{{- include "cryostat.selectorLabels" $ | nindent 4 }}
app.kubernetes.io/component: reports
Expand Down
14 changes: 13 additions & 1 deletion charts/cryostat/tests/cryostat_deployment_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,19 @@ tests:
asserts:
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_REST_CLIENT_REPORTS_URL')].value
value: http://RELEASE-NAME-cryostat-reports:10001
value: http://cryostat:$(REPORTS_PASS_SECRET_KEY)@RELEASE-NAME-cryostat-reports.NAMESPACE.svc:10001

- it: should set environment variable if sidecar report generator is enabled in OpenShift with HTTPS
set:
reports:
replicas: 1
authentication:
openshift:
enabled: true
asserts:
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat')].env[?(@.name=='QUARKUS_REST_CLIENT_REPORTS_URL')].value
value: https://cryostat:$(REPORTS_PASS_SECRET_KEY)@RELEASE-NAME-cryostat-reports.NAMESPACE.svc:10001

- it: should set oauth2proxy resource overrides
set:
Expand Down
34 changes: 34 additions & 0 deletions charts/cryostat/tests/reports_deployment_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ tests:
reports:
replicas: 1
asserts:
- exists:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')]
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')].image
value: "quay.io/oauth2-proxy/oauth2-proxy:latest"
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')].ports
value:
- containerPort: 4180
name: http
protocol: TCP
- exists:
path: spec.template.spec.containers[?(@.name=='cryostat-reports')]
- equal:
Expand All @@ -73,6 +84,29 @@ tests:
path: spec.template.spec.containers[?(@.name=='cryostat-reports')].env[?(@.name=='QUARKUS_HTTP_PORT')].value
value: "10001"

- it: should validate authproxy settings when deployed in OpenShift
set:
reports:
replicas: 1
authentication:
openshift:
enabled: true
asserts:
- exists:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')]
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')].image
value: "quay.io/cryostat/openshift-oauth-proxy:cryostat-v3.0"
- equal:
path: spec.template.spec.containers[?(@.name=='cryostat-reports-authproxy')].ports
value:
- containerPort: 4180
name: http
protocol: TCP
- containerPort: 8443
name: https
protocol: TCP

- it: should apply Kubernetes specific settings when configured
set:
reports:
Expand Down
40 changes: 40 additions & 0 deletions charts/cryostat/tests/reports_secret_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
suite: test reports_secret.yaml
templates:
- reports_secret.yaml

tests:
- it: should create a reports secret if core.reportsSecretName is not set
set:
core.reportsSecretName: ""
asserts:
- hasDocuments:
count: 1
- equal:
path: kind
value: Secret
- equal:
path: metadata.name
value: RELEASE-NAME-reports-secret
- equal:
path: type
value: Opaque
- exists:
path: data.htpasswd
- exists:
path: data.REPORTS_PASS
- equal:
path: metadata.labels
value:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: cryostat
app.kubernetes.io/part-of: cryostat
app.kubernetes.io/version: 4.0.0-dev
helm.sh/chart: cryostat-2.0.0-dev

- it: should not create a database secret if reports.reportsSecretName is set
set:
reports.reportsSecretName: "custom-reports-secret"
asserts:
- hasDocuments:
count: 0
Loading