Skip to content

Commit

Permalink
feat: Add SCC RBAC for OpenShift
Browse files Browse the repository at this point in the history
OpenShift by default has very stringent pod security requirements
for containers that often don't neatly align with upstream k8s Pod
Security Standards. The "nonroot-v2" SecurityContextConstraint
aligns most closely with the "restricted" pod security standard,
but must be explicitly granted to a service account in order to be
used. Granting the Jenkins service account permission to use the
"nonroot-v2" SCC allows the StatefulSet to deploy on an OpenShift
cluster.

Note that to grant this SCC to Jenkins, the Helm chart needs to be
deployed by a user with cluster-admin (or similar) permissions.

Signed-off-by: Adam Kaplan <[email protected]>
  • Loading branch information
adambkaplan committed Sep 26, 2024
1 parent d2a1051 commit c5dd9dd
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 18 deletions.
37 changes: 19 additions & 18 deletions charts/jenkins/VALUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ The following tables list the configurable parameters of the Jenkins chart and t
| [agent.workspaceVolume](./values.yaml#L1049) | object | Workspace volume (defaults to EmptyDir) | `{}` |
| [agent.yamlMergeStrategy](./values.yaml#L1138) | string | Defines how the raw yaml field gets merged with yaml definitions from inherited pod templates. Possible values: "merge" or "override" | `"override"` |
| [agent.yamlTemplate](./values.yaml#L1127) | string | The raw yaml of a Pod API Object to merge into the agent spec | `""` |
| [awsSecurityGroupPolicies.enabled](./values.yaml#L1346) | bool | | `false` |
| [awsSecurityGroupPolicies.policies[0].name](./values.yaml#L1348) | string | | `""` |
| [awsSecurityGroupPolicies.policies[0].podSelector](./values.yaml#L1350) | object | | `{}` |
| [awsSecurityGroupPolicies.policies[0].securityGroupIds](./values.yaml#L1349) | list | | `[]` |
| [checkDeprecation](./values.yaml#L1343) | bool | Checks if any deprecated values are used | `true` |
| [awsSecurityGroupPolicies.enabled](./values.yaml#L1348) | bool | | `false` |
| [awsSecurityGroupPolicies.policies[0].name](./values.yaml#L1350) | string | | `""` |
| [awsSecurityGroupPolicies.policies[0].podSelector](./values.yaml#L1352) | object | | `{}` |
| [awsSecurityGroupPolicies.policies[0].securityGroupIds](./values.yaml#L1351) | list | | `[]` |
| [checkDeprecation](./values.yaml#L1345) | bool | Checks if any deprecated values are used | `true` |
| [clusterZone](./values.yaml#L21) | string | Override the cluster name for FQDN resolving | `"cluster.local"` |
| [controller.JCasC.authorizationStrategy](./values.yaml#L539) | string | Jenkins Config as Code Authorization Strategy-section | `"loggedInUsersCanDoAnything:\n allowAnonymousRead: false"` |
| [controller.JCasC.configMapAnnotations](./values.yaml#L544) | object | Annotations for the JCasC ConfigMap | `{}` |
Expand Down Expand Up @@ -278,9 +278,9 @@ The following tables list the configurable parameters of the Jenkins chart and t
| [controller.usePodSecurityContext](./values.yaml#L182) | bool | Enable pod security context (must be `true` if podSecurityContextOverride, runAsUser or fsGroup are set) | `true` |
| [credentialsId](./values.yaml#L27) | string | The Jenkins credentials to access the Kubernetes API server. For the default cluster it is not needed. | `nil` |
| [fullnameOverride](./values.yaml#L13) | string | Override the full resource names | `jenkins-(release-name)` or `jenkins` if the release-name is `jenkins` |
| [helmtest.bats.image.registry](./values.yaml#L1359) | string | Registry of the image used to test the framework | `"docker.io"` |
| [helmtest.bats.image.repository](./values.yaml#L1361) | string | Repository of the image used to test the framework | `"bats/bats"` |
| [helmtest.bats.image.tag](./values.yaml#L1363) | string | Tag of the image to test the framework | `"1.11.0"` |
| [helmtest.bats.image.registry](./values.yaml#L1361) | string | Registry of the image used to test the framework | `"docker.io"` |
| [helmtest.bats.image.repository](./values.yaml#L1363) | string | Repository of the image used to test the framework | `"bats/bats"` |
| [helmtest.bats.image.tag](./values.yaml#L1365) | string | Tag of the image to test the framework | `"1.11.0"` |
| [kubernetesURL](./values.yaml#L24) | string | The URL of the Kubernetes API server | `"https://kubernetes.default"` |
| [nameOverride](./values.yaml#L10) | string | Override the resource name prefix | `Chart.Name` |
| [namespaceOverride](./values.yaml#L16) | string | Override the deployment namespace | `Release.Namespace` |
Expand All @@ -304,14 +304,15 @@ The following tables list the configurable parameters of the Jenkins chart and t
| [persistence.volumes](./values.yaml#L1272) | list | Additional volumes | `[]` |
| [rbac.create](./values.yaml#L1309) | bool | Whether RBAC resources are created | `true` |
| [rbac.readSecrets](./values.yaml#L1311) | bool | Whether the Jenkins service account should be able to read Kubernetes secrets | `false` |
| [rbac.useOpenShiftNonRootSCC](./values.yaml#L1313) | bool | Whether the Jenkins service account should be able to use the OpenShift "nonroot" Security Context Constraints | `false` |
| [renderHelmLabels](./values.yaml#L30) | bool | Enables rendering of the helm.sh/chart label to the annotations | `true` |
| [serviceAccount.annotations](./values.yaml#L1321) | object | Configures annotations for the ServiceAccount | `{}` |
| [serviceAccount.create](./values.yaml#L1315) | bool | Configures if a ServiceAccount with this name should be created | `true` |
| [serviceAccount.extraLabels](./values.yaml#L1323) | object | Configures extra labels for the ServiceAccount | `{}` |
| [serviceAccount.imagePullSecretName](./values.yaml#L1325) | string | Controller ServiceAccount image pull secret | `nil` |
| [serviceAccount.name](./values.yaml#L1319) | string | | `nil` |
| [serviceAccountAgent.annotations](./values.yaml#L1336) | object | Configures annotations for the agent ServiceAccount | `{}` |
| [serviceAccountAgent.create](./values.yaml#L1330) | bool | Configures if an agent ServiceAccount should be created | `false` |
| [serviceAccountAgent.extraLabels](./values.yaml#L1338) | object | Configures extra labels for the agent ServiceAccount | `{}` |
| [serviceAccountAgent.imagePullSecretName](./values.yaml#L1340) | string | Agent ServiceAccount image pull secret | `nil` |
| [serviceAccountAgent.name](./values.yaml#L1334) | string | The name of the agent ServiceAccount to be used by access-controlled resources | `nil` |
| [serviceAccount.annotations](./values.yaml#L1323) | object | Configures annotations for the ServiceAccount | `{}` |
| [serviceAccount.create](./values.yaml#L1317) | bool | Configures if a ServiceAccount with this name should be created | `true` |
| [serviceAccount.extraLabels](./values.yaml#L1325) | object | Configures extra labels for the ServiceAccount | `{}` |
| [serviceAccount.imagePullSecretName](./values.yaml#L1327) | string | Controller ServiceAccount image pull secret | `nil` |
| [serviceAccount.name](./values.yaml#L1321) | string | | `nil` |
| [serviceAccountAgent.annotations](./values.yaml#L1338) | object | Configures annotations for the agent ServiceAccount | `{}` |
| [serviceAccountAgent.create](./values.yaml#L1332) | bool | Configures if an agent ServiceAccount should be created | `false` |
| [serviceAccountAgent.extraLabels](./values.yaml#L1340) | object | Configures extra labels for the agent ServiceAccount | `{}` |
| [serviceAccountAgent.imagePullSecretName](./values.yaml#L1342) | string | Agent ServiceAccount image pull secret | `nil` |
| [serviceAccountAgent.name](./values.yaml#L1336) | string | The name of the agent ServiceAccount to be used by access-controlled resources | `nil` |
49 changes: 49 additions & 0 deletions charts/jenkins/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,55 @@ subjects:
---
{{- end}}

{{- if .Values.rbac.useOpenShiftNonRootSCC }}
# This is needed if you are running on OpenShift and using the default
# containerSecurityContext in the chart. It grants the Jenkins service account
# permission to use the "nonroot" and "nonroot-v2" SecurityContextConstraints.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ $serviceName }}-use-nonroot-scc
namespace: {{ template "jenkins.namespace" . }}
labels:
"app.kubernetes.io/name": '{{ template "jenkins.name" .}}'
{{- if .Values.renderHelmLabels }}
"helm.sh/chart": "{{ template "jenkins.label" .}}"
{{- end }}
"app.kubernetes.io/managed-by": "{{ .Release.Service }}"
"app.kubernetes.io/instance": "{{ .Release.Name }}"
"app.kubernetes.io/component": "{{ .Values.controller.componentName }}"
rules:
- apiGroups: ["security.openshift.io"]
resources: ["securitycontextconstraints"]
resourceNames: ["nonroot", "nonroot-v2"]
verbs: ["use"]
---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ $serviceName }}-use-nonroot-scc
namespace: {{ template "jenkins.namespace" . }}
labels:
"app.kubernetes.io/name": '{{ template "jenkins.name" .}}'
{{- if .Values.renderHelmLabels }}
"helm.sh/chart": "{{ template "jenkins.label" .}}"
{{- end }}
"app.kubernetes.io/managed-by": "{{ .Release.Service }}"
"app.kubernetes.io/instance": "{{ .Release.Name }}"
"app.kubernetes.io/component": "{{ .Values.controller.componentName }}"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "jenkins.fullname" . }}-use-nonroot-scc
subjects:
- kind: ServiceAccount
name: {{ template "jenkins.serviceAccountName" . }}
namespace: {{ template "jenkins.namespace" . }}

---
{{- end}}

{{- if .Values.controller.sidecars.configAutoReload.enabled }}
# The sidecar container which is responsible for reloading configuration changes
# needs permissions to watch ConfigMaps
Expand Down
52 changes: 52 additions & 0 deletions charts/jenkins/unittests/rbac-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,55 @@ tests:
name: my-release-jenkins
namespace: my-namespace

- it: Role use-nonroot-scc
set:
rbac.useOpenShiftNonRootSCC: true
documentIndex: 2
asserts:
- isKind:
of: Role
- equal:
path: apiVersion
value: rbac.authorization.k8s.io/v1
- equal:
path: metadata.name
value: my-release-jenkins-use-nonroot-scc
- equal:
path: metadata.namespace
value: my-namespace
- equal:
path: rules
value:
- apiGroups: ["security.openshift.io"]
resources: ["securitycontextconstraints"]
resourceNames: ["nonroot", "nonroot-v2"]
verbs: ["use"]

- it: RoleBinding use-nonroot-scc
set:
rbac.useOpenShiftNonRootSCC: true
documentIndex: 3
asserts:
- isKind:
of: RoleBinding
- equal:
path: apiVersion
value: rbac.authorization.k8s.io/v1
- equal:
path: metadata.name
value: my-release-jenkins-use-nonroot-scc
- equal:
path: metadata.namespace
value: my-namespace
- equal:
path: roleRef
value:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-release-jenkins-use-nonroot-scc
- equal:
path: subjects
value:
- kind: ServiceAccount
name: my-release-jenkins
namespace: my-namespace
2 changes: 2 additions & 0 deletions charts/jenkins/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,8 @@ rbac:
create: true
# -- Whether the Jenkins service account should be able to read Kubernetes secrets
readSecrets: false
# -- Whether the Jenkins service account should be able to use the OpenShift "nonroot" Security Context Constraints
useOpenShiftNonRootSCC: false

serviceAccount:
# -- Configures if a ServiceAccount with this name should be created
Expand Down

0 comments on commit c5dd9dd

Please sign in to comment.