Skip to content

Commit 02137de

Browse files
authored
Merge pull request #20 from NetApp/fix-scc
Adding OpenShift SCC fix and bumping charts to 4.1.2
2 parents 595ebee + 6346d56 commit 02137de

12 files changed

Lines changed: 450 additions & 14 deletions

charts/netapp-neo/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ description: NetApp Neo v4.x — context lake microservice architecture for AI s
44
type: application
55
keywords: ["NetApp", "Neo", "MCP", "AI", "context lake"]
66
home: "https://netapp.github.io/Innovation-Labs/"
7-
version: 26.4.3
8-
appVersion: "4.1.0"
7+
version: 26.4.4
8+
appVersion: "4.1.2"

charts/netapp-neo/OPENSHIFT.MD

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Deploy NetApp Neo on OpenShift
2+
3+
This guide describes how to deploy this chart on OpenShift with the new security model:
4+
5+
- Restricted-v2 baseline for the application
6+
- Mandatory privileged exceptions for `worker` and `extractor` to access remote file systems
7+
- Helm validation enforces this mode during render/install
8+
9+
## 1. Prerequisites
10+
11+
- OpenShift cluster access (`oc`)
12+
- Helm 3
13+
- Cluster admin support for SCC binding (required for privileged worker/extractor mode)
14+
- Target namespace exists, example: `neo-poc`
15+
16+
Select your target namespace:
17+
18+
```bash
19+
oc project neo-poc
20+
```
21+
22+
Prepare OpenShift values override file:
23+
24+
```bash
25+
cat > values-openshift.yaml <<'EOF'
26+
openshift:
27+
restrictedV2:
28+
enabled: true
29+
api:
30+
serviceAccount:
31+
create: true
32+
name: ""
33+
annotations: {}
34+
ui:
35+
serviceAccount:
36+
create: true
37+
name: ""
38+
annotations: {}
39+
privilegedWorkloads:
40+
worker:
41+
enabled: true
42+
serviceAccount:
43+
create: true
44+
name: ""
45+
annotations: {}
46+
extractor:
47+
enabled: true
48+
serviceAccount:
49+
create: true
50+
name: ""
51+
annotations: {}
52+
EOF
53+
```
54+
55+
## 2. Deployment Mode
56+
57+
### Restricted-v2 + privileged exceptions (worker/extractor)
58+
59+
This is the required deployment mode for this application because `worker` and `extractor`
60+
must mount filesystems inside the pod.
61+
62+
Required chart behavior:
63+
64+
- `openshift.restrictedV2.enabled=true`
65+
- `openshift.privilegedWorkloads.worker.enabled=true`
66+
- `openshift.privilegedWorkloads.extractor.enabled=true`
67+
68+
These are enforced by chart validation. Helm will fail if any are set to `false`.
69+
70+
Deploy:
71+
72+
```bash
73+
helm upgrade --install netapp-neo innovation-labs/netapp-neo \
74+
-n neo-poc \
75+
-f ./netapp-neo/values.yaml \
76+
-f ./values-openshift.yaml \
77+
--wait --timeout 10m --rollback-on-failure
78+
```
79+
80+
If you maintain a platform-specific values file, keep this OpenShift block there.
81+
82+
## 3. Bind SCC for Privileged Exception Service Accounts
83+
84+
In this mode, the chart creates service accounts:
85+
86+
- `netapp-neo-netapp-neo-api`
87+
- `netapp-neo-netapp-neo-ui`
88+
- `netapp-neo-netapp-neo-worker-privileged`
89+
- `netapp-neo-netapp-neo-extractor-privileged`
90+
91+
Bind an SCC that permits required behavior (example shown with `privileged`; use a narrower custom SCC if possible):
92+
93+
```bash
94+
oc adm policy add-scc-to-user privileged \
95+
-z netapp-neo-netapp-neo-worker-privileged \
96+
-n neo-poc
97+
98+
oc adm policy add-scc-to-user privileged \
99+
-z netapp-neo-netapp-neo-extractor-privileged \
100+
-n neo-poc
101+
```
102+
103+
If you set custom service account names in values:
104+
105+
- `openshift.api.serviceAccount.name`
106+
- `openshift.ui.serviceAccount.name`
107+
- `openshift.privilegedWorkloads.worker.serviceAccount.name`
108+
- `openshift.privilegedWorkloads.extractor.serviceAccount.name`
109+
110+
use those names in the `oc adm policy` commands.
111+
112+
If you set `serviceAccount.create=false`, ensure those service accounts already exist in the namespace.
113+
114+
## 4. Verify Deployment
115+
116+
Check pods:
117+
118+
```bash
119+
oc get pods -n neo-poc
120+
```
121+
122+
Check service account used by api/ui/worker/extractor:
123+
124+
```bash
125+
oc get deploy netapp-neo-netapp-neo-api -n neo-poc -o jsonpath='{.spec.template.spec.serviceAccountName}{"\n"}'
126+
oc get deploy netapp-neo-netapp-neo-ui -n neo-poc -o jsonpath='{.spec.template.spec.serviceAccountName}{"\n"}'
127+
oc get deploy netapp-neo-netapp-neo-worker -n neo-poc -o jsonpath='{.spec.template.spec.serviceAccountName}{"\n"}'
128+
oc get deploy netapp-neo-netapp-neo-extractor -n neo-poc -o jsonpath='{.spec.template.spec.serviceAccountName}{"\n"}'
129+
```
130+
131+
Check events for SCC admission issues:
132+
133+
```bash
134+
oc get events -n neo-poc --sort-by=.lastTimestamp | tail -n 50
135+
```
136+
137+
Confirm API deployment does not render forbidden fixed IDs or explicit seccomp:
138+
139+
```bash
140+
oc get deploy netapp-neo-netapp-neo-api -n neo-poc -o yaml | grep -E "runAsUser|runAsGroup|fsGroup|seccompProfile" -n
141+
```
142+
143+
## 5. Troubleshooting
144+
145+
If pods are blocked by SCC:
146+
147+
- Confirm privileged exception flags are enabled as required.
148+
- Confirm SCC binding exists for the exact service account names.
149+
- Confirm namespace in `oc adm policy` matches deployment namespace.
150+
- Confirm api/ui/worker/extractor serviceAccountName values in the live deployment are the expected service accounts.
151+
- Confirm worker/extractor service accounts are the ones bound to SCC.
152+
- Re-run Helm with `--wait --rollback-on-failure` to catch rollout failures clearly.
153+
154+
Example inspection:
155+
156+
```bash
157+
oc describe rs -n neo-poc | grep -E "forbidden|security context constraint|SCC|restricted-v2" -i
158+
```
159+
160+
## 6. Recommended Operational Practice
161+
162+
- Keep this single enforced mode for OpenShift deployments.
163+
- Keep API and UI on dedicated non-privileged service accounts.
164+
- Grant elevated SCC only to `worker` and `extractor` service accounts.
165+
- Prefer a custom least-privilege SCC over broad `privileged` SCC when feasible.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# OpenShift profile with privileged exceptions for worker/extractor.
2+
# This is the required mode for this chart on OpenShift because these workloads mount filesystems in the pod.
3+
# The three enabled flags below are chart-enforced by templates/validations.yaml.
4+
# Usage:
5+
# git clone --branch fix-scc https://github.com/NetApp/Innovation-Labs.git
6+
# cd Innovation-Labs/charts/netapp-neo
7+
# helm upgrade --install netapp-neo . -n neo-poc -f values.yaml -f _temp/values-openshift-privileged.yaml --wait --timeout 10m --rollback-on-failure
8+
9+
openshift:
10+
restrictedV2:
11+
enabled: true
12+
api:
13+
serviceAccount:
14+
create: true
15+
# If create=false, service account must already exist in the namespace.
16+
# Leave empty to use generated name:
17+
# <release>-netapp-neo-api
18+
name: ""
19+
annotations: {}
20+
ui:
21+
serviceAccount:
22+
create: true
23+
# If create=false, service account must already exist in the namespace.
24+
# Leave empty to use generated name:
25+
# <release>-netapp-neo-ui
26+
name: ""
27+
annotations: {}
28+
privilegedWorkloads:
29+
worker:
30+
enabled: true
31+
serviceAccount:
32+
create: true
33+
# If create=false, service account must already exist in the namespace.
34+
# Leave empty to use generated name:
35+
# <release>-netapp-neo-worker-privileged
36+
name: ""
37+
annotations: {}
38+
extractor:
39+
enabled: true
40+
serviceAccount:
41+
create: true
42+
# If create=false, service account must already exist in the namespace.
43+
# Leave empty to use generated name:
44+
# <release>-netapp-neo-extractor-privileged
45+
name: ""
46+
annotations: {}

charts/netapp-neo/templates/NOTES.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,17 @@ To access the API locally:
3737

3838
To access the UI locally:
3939
kubectl -n {{ .Release.Namespace}} port-forward svc/{{ include "netapp-neo.fullname" . }}-ui 8080:{{ .Values.ui.service.port }}
40+
41+
{{- if .Values.openshift.privilegedWorkloads.worker.enabled }}
42+
43+
OpenShift setup required for worker privileged mode:
44+
- Bind an SCC that allows the required mount behavior to service account:
45+
{{ include "netapp-neo.workerPrivilegedServiceAccountName" . }}
46+
{{- end }}
47+
48+
{{- if .Values.openshift.privilegedWorkloads.extractor.enabled }}
49+
50+
OpenShift setup required for extractor privileged mode:
51+
- Bind an SCC that allows the required mount behavior to service account:
52+
{{ include "netapp-neo.extractorPrivilegedServiceAccountName" . }}
53+
{{- end }}

charts/netapp-neo/templates/_helpers.tpl

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ Only useful when postgresql.enabled is true.
8888
securityContext:
8989
allowPrivilegeEscalation: false
9090
runAsNonRoot: true
91-
seccompProfile:
92-
type: RuntimeDefault
9391
capabilities:
9492
drop:
9593
- ALL
@@ -121,3 +119,38 @@ Usage: include "netapp-neo.imageTag" (dict "imageTag" .Values.api.image.tag "app
121119
{{- define "netapp-neo.imageTag" -}}
122120
{{- default .appVersion .imageTag -}}
123121
{{- end -}}
122+
123+
{{/*
124+
Service account names used by workloads in OpenShift mode.
125+
*/}}
126+
{{- define "netapp-neo.apiServiceAccountName" -}}
127+
{{- if .Values.openshift.api.serviceAccount.name -}}
128+
{{- .Values.openshift.api.serviceAccount.name -}}
129+
{{- else -}}
130+
{{- printf "%s-api" (include "netapp-neo.fullname" .) -}}
131+
{{- end -}}
132+
{{- end -}}
133+
134+
{{- define "netapp-neo.uiServiceAccountName" -}}
135+
{{- if .Values.openshift.ui.serviceAccount.name -}}
136+
{{- .Values.openshift.ui.serviceAccount.name -}}
137+
{{- else -}}
138+
{{- printf "%s-ui" (include "netapp-neo.fullname" .) -}}
139+
{{- end -}}
140+
{{- end -}}
141+
142+
{{- define "netapp-neo.workerPrivilegedServiceAccountName" -}}
143+
{{- if .Values.openshift.privilegedWorkloads.worker.serviceAccount.name -}}
144+
{{- .Values.openshift.privilegedWorkloads.worker.serviceAccount.name -}}
145+
{{- else -}}
146+
{{- printf "%s-worker-privileged" (include "netapp-neo.fullname" .) -}}
147+
{{- end -}}
148+
{{- end -}}
149+
150+
{{- define "netapp-neo.extractorPrivilegedServiceAccountName" -}}
151+
{{- if .Values.openshift.privilegedWorkloads.extractor.serviceAccount.name -}}
152+
{{- .Values.openshift.privilegedWorkloads.extractor.serviceAccount.name -}}
153+
{{- else -}}
154+
{{- printf "%s-extractor-privileged" (include "netapp-neo.fullname" .) -}}
155+
{{- end -}}
156+
{{- end -}}

charts/netapp-neo/templates/api-deployment.yaml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,9 @@ spec:
2020
imagePullSecrets:
2121
{{- toYaml . | nindent 8 }}
2222
{{- end }}
23+
serviceAccountName: {{ include "netapp-neo.apiServiceAccountName" . }}
2324
securityContext:
24-
runAsUser: 1000
25-
runAsGroup: 1000
26-
fsGroup: 1000
2725
runAsNonRoot: true
28-
seccompProfile:
29-
type: RuntimeDefault
3026
{{- if .Values.postgresql.enabled }}
3127
initContainers:
3228
{{- include "netapp-neo.waitForDb" . | nindent 8 }}
@@ -51,8 +47,6 @@ spec:
5147
securityContext:
5248
allowPrivilegeEscalation: false
5349
runAsNonRoot: true
54-
seccompProfile:
55-
type: RuntimeDefault
5650
capabilities:
5751
drop:
5852
- ALL

charts/netapp-neo/templates/extractor-deployment.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,23 @@ spec:
2020
imagePullSecrets:
2121
{{- toYaml . | nindent 8 }}
2222
{{- end }}
23+
{{- if .Values.openshift.privilegedWorkloads.extractor.enabled }}
24+
serviceAccountName: {{ include "netapp-neo.extractorPrivilegedServiceAccountName" . }}
25+
{{- end }}
26+
{{- if .Values.openshift.privilegedWorkloads.extractor.enabled }}
27+
securityContext:
28+
{{- toYaml .Values.openshift.privilegedWorkloads.extractor.podSecurityContext | nindent 8 }}
29+
{{- else if .Values.openshift.restrictedV2.enabled }}
30+
securityContext:
31+
runAsNonRoot: true
32+
seccompProfile:
33+
type: RuntimeDefault
34+
{{- else }}
2335
securityContext:
2436
runAsUser: 1000
2537
runAsGroup: 1000
2638
fsGroup: 1000
39+
{{- end }}
2740
{{- if .Values.postgresql.enabled }}
2841
initContainers:
2942
{{- include "netapp-neo.waitForDb" . | nindent 8 }}
@@ -42,6 +55,19 @@ spec:
4255
secretKeyRef:
4356
name: {{ include "netapp-neo.fullname" . }}-db
4457
key: DATABASE_URL
58+
{{- if .Values.openshift.privilegedWorkloads.extractor.enabled }}
59+
securityContext:
60+
{{- toYaml .Values.openshift.privilegedWorkloads.extractor.containerSecurityContext | nindent 12 }}
61+
{{- else if .Values.openshift.restrictedV2.enabled }}
62+
securityContext:
63+
allowPrivilegeEscalation: false
64+
runAsNonRoot: true
65+
seccompProfile:
66+
type: RuntimeDefault
67+
capabilities:
68+
drop:
69+
- ALL
70+
{{- else }}
4571
securityContext:
4672
runAsUser: 1000
4773
runAsGroup: 1000
@@ -50,6 +76,7 @@ spec:
5076
runAsNonRoot: false
5177
appArmorProfile:
5278
type: Unconfined
79+
{{- end }}
5380
{{- with .Values.extractor.resources }}
5481
resources:
5582
{{- toYaml . | nindent 12 }}

0 commit comments

Comments
 (0)