Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
15 changes: 15 additions & 0 deletions install/0000_50_cluster-update-console-plugin_10_namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Namespace
metadata:
name: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: The OpenShift cluster-update console plugin provides a web-console interface for managing ClusterVersion updates.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
labels:
openshift.io/cluster-monitoring: "true"
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: cluster-update-console-plugin
namespace: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: The OpenShift cluster-update console plugin provides a web-console interface for managing ClusterVersion updates.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: This NetworkPolicy is used to deny all ingress and egress traffic by default in this namespace, matching all Pods, and serving as a baseline.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Comment on lines +13 to +16

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default-deny policy blocks plugin traffic without companion allow policies.

podSelector: {} + Ingress/Egress with no rules denies all traffic. As-is, backend access to the plugin service (and monitoring ingress) will be blocked unless additional allow policies are added in this namespace.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@install/0000_50_cluster-update-console-plugin_20_networkpolicy.yaml` around
lines 13 - 16, The NetworkPolicy currently uses podSelector: {} with
policyTypes: - Ingress and - Egress which creates a default-deny for all pods;
update the policy to either target specific pods instead of podSelector: {}
(e.g., use a labelSelector matching the console-plugin pods) or add explicit
allow rules for required traffic (ingress rules to permit backend/monitoring
sources and egress rules to permit upstream destinations) so the console plugin
service and monitoring can communicate; reference the podSelector and
policyTypes (Ingress, Egress) in the NetworkPolicy being modified and ensure the
new rules explicitly allow the necessary CIDRs/namespaceSelectors/port/protocols
for plugin traffic.

28 changes: 28 additions & 0 deletions install/0000_50_cluster-update-console-plugin_30_configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-update-console-plugin
namespace: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: Nginx configuration for the cluster-update console plugin.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
data:
nginx.conf: |
error_log /dev/stderr;
events {}
http {
access_log /dev/stdout;
include /etc/nginx/mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
server {
listen 9001 ssl;
listen [::]:9001 ssl;
ssl_certificate /var/cert/tls.crt;
ssl_certificate_key /var/cert/tls.key;
root /usr/share/nginx/html;
}
}
78 changes: 78 additions & 0 deletions install/0000_50_cluster-update-console-plugin_50_deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-update-console-plugin
namespace: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: The OpenShift cluster-update console plugin provides a web-console interface for managing ClusterVersion updates.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
spec:
selector:
matchLabels:
app: cluster-update-console-plugin
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
annotations:
target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}'
openshift.io/required-scc: restricted-v3
labels:
app: cluster-update-console-plugin
spec:
serviceAccountName: cluster-update-console-plugin
automountServiceAccountToken: false
containers:
- name: plugin
image: '{{index .Images "cluster-update-console-plugin"}}'
imagePullPolicy: IfNotPresent
ports:
- name: https
containerPort: 9001
resources:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
requests:
cpu: 20m
memory: 50Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
terminationMessagePolicy: FallbackToLogsOnError
Comment on lines +38 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add container limits and read-only root filesystem.

Container plugin has requests but no limits, and readOnlyRootFilesystem is not set.

Suggested patch
       resources:
         requests:
           cpu: 20m
           memory: 50Mi
+        limits:
+          cpu: 100m
+          memory: 200Mi
       securityContext:
         allowPrivilegeEscalation: false
+        readOnlyRootFilesystem: true
         capabilities:
           drop:
           - ALL

As per coding guidelines, **/*.{yaml,yml} requires readOnlyRootFilesystem and Resource limits (cpu, memory) on every container.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resources:
requests:
cpu: 20m
memory: 50Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
terminationMessagePolicy: FallbackToLogsOnError
resources:
requests:
cpu: 20m
memory: 50Mi
limits:
cpu: 100m
memory: 200Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
terminationMessagePolicy: FallbackToLogsOnError
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@install/0000_50_cluster-update-console-plugin_50_deployment.yaml` around
lines 37 - 46, The plugin container currently defines resources.requests but no
resources.limits and its securityContext lacks readOnlyRootFilesystem; update
the container spec for the container named "plugin" to add a resources.limits
block (set cpu and memory limits equal to or higher than the existing requests,
e.g., cpu and memory) and set securityContext.readOnlyRootFilesystem: true;
ensure you modify the container entry that contains resources.requests and
securityContext so both limits and readOnlyRootFilesystem are present and
compliant.

volumeMounts:
- mountPath: /var/cert
name: cluster-update-console-plugin-cert
readOnly: true
- mountPath: /etc/nginx/nginx.conf
name: nginx-conf
readOnly: true
subPath: nginx.conf
dnsPolicy: ClusterFirst
hostUsers: false
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/infra
operator: Exists
volumes:
- name: cluster-update-console-plugin-cert
secret:
defaultMode: 420
secretName: cluster-update-console-plugin-cert
- name: nginx-conf
configMap:
name: cluster-update-console-plugin
defaultMode: 420
20 changes: 20 additions & 0 deletions install/0000_50_cluster-update-console-plugin_60_service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
kind: Service
metadata:
name: openshift-cluster-update-console-plugin
namespace: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: The OpenShift cluster-update console plugin provides a web-console interface for managing ClusterVersion updates.
service.beta.openshift.io/serving-cert-secret-name: cluster-update-console-plugin-cert
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
spec:
type: ClusterIP
selector:
app: cluster-update-console-plugin
ports:
- name: https
port: 9001
targetPort: https
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: console.openshift.io/v1
kind: ConsolePlugin
metadata:
name: openshift-cluster-update-console-plugin
annotations:
kubernetes.io/description: The OpenShift cluster-update console plugin provides a web-console interface for managing ClusterVersion updates.
capability.openshift.io/name: Console
release.openshift.io/feature-set: TechPreviewNoUpgrade
exclude.release.openshift.io/internal-openshift-hosted: "true"
include.release.openshift.io/self-managed-high-availability: "true"
spec:
displayName: Cluster Updates
i18n:
loadType: Preload
backend:
type: Service
service:
name: openshift-cluster-update-console-plugin
namespace: openshift-cluster-update-console-plugin
port: 9001
basePath: /
8 changes: 8 additions & 0 deletions install/image-references
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: ImageStream
apiVersion: image.openshift.io/v1
spec:
tags:
- name: cluster-update-console-plugin
from:
kind: DockerImage
name: placeholder.url.oc.will.replace.this.example.org:cluster-update-console-plugin
5 changes: 3 additions & 2 deletions pkg/payload/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func LoadUpdate(dir, releaseImage, excludeIdentifier string, requiredFeatureSet
return nil, err
}

tasks := loadPayloadTasks(releaseDir, cvoDir, releaseImage, profile)
tasks := loadPayloadTasks(releaseDir, cvoDir, releaseImage, profile, payload.ImageRef)

var onlyKnownCaps *configv1.ClusterVersionCapabilitiesStatus

Expand Down Expand Up @@ -317,13 +317,14 @@ type payloadTasks struct {
skipFiles sets.Set[string]
}

func loadPayloadTasks(releaseDir, cvoDir, releaseImage, clusterProfile string) []payloadTasks {
func loadPayloadTasks(releaseDir, cvoDir, releaseImage, clusterProfile string, imageRef *imagev1.ImageStream) []payloadTasks {
cjf := filepath.Join(releaseDir, cincinnatiJSONFile)
irf := filepath.Join(releaseDir, imageReferencesFile)

mrc := manifestRenderConfig{
ReleaseImage: releaseImage,
ClusterProfile: clusterProfile,
Images: imagesFromImageRef(imageRef),
}

return []payloadTasks{{
Expand Down
22 changes: 22 additions & 0 deletions pkg/payload/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/openshift/api/config"
configv1 "github.com/openshift/api/config/v1"
imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/library-go/pkg/manifest"
)

Expand All @@ -38,6 +39,12 @@ func Render(outputDir, releaseImage, clusterVersionManifestPath, featureGateMani
}
)

imageRef, err := loadImageReferences(releaseManifestsDir)
if err != nil {
return fmt.Errorf("error loading image references for manifest rendering: %w", err)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
renderConfig.Images = imagesFromImageRef(imageRef)

overrides, err := parseClusterVersionManifest(clusterVersionManifestPath)
if err != nil {
return fmt.Errorf("error parsing cluster version manifest: %w", err)
Expand Down Expand Up @@ -181,6 +188,21 @@ func renderDir(renderConfig manifestRenderConfig, idir, odir string, overrides [
type manifestRenderConfig struct {
ReleaseImage string
ClusterProfile string
Images map[string]string
}

// imagesFromImageRef builds a map from image short names to their resolved URIs.
func imagesFromImageRef(imageRef *imagev1.ImageStream) map[string]string {
images := make(map[string]string)
if imageRef == nil {
return images
}
for _, tag := range imageRef.Spec.Tags {
if tag.From != nil && tag.From.Kind == "DockerImage" {
images[tag.Name] = tag.From.Name
}
}
return images
}

// renderManifest Executes go text template from `manifestBytes` with `config`.
Expand Down
7 changes: 7 additions & 0 deletions pkg/payload/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ func Test_cvoManifests(t *testing.T) {
config := manifestRenderConfig{
ReleaseImage: "quay.io/cvo/release:latest",
ClusterProfile: "some-profile",
Images: map[string]string{
"cluster-update-console-plugin": "quay.io/openshift/cluster-update-console-plugin:latest",
},
}

tests := []struct {
Expand Down Expand Up @@ -341,6 +344,10 @@ func Test_cvoManifests(t *testing.T) {
return nil
}

if _, fileName := filepath.Split(path); fileName == "image-references" {
return nil
}

var manifestsWithoutIncludeAnnotation []manifest.Manifest
data, err := os.ReadFile(path)
if err != nil {
Expand Down