Skip to content

[WIP] OCPCLOUD-3557: split capi-controllers and machine-api-migration#622

Open
stefanonardo wants to merge 1 commit into
openshift:mainfrom
stefanonardo:OCPCLOUD-3557
Open

[WIP] OCPCLOUD-3557: split capi-controllers and machine-api-migration#622
stefanonardo wants to merge 1 commit into
openshift:mainfrom
stefanonardo:OCPCLOUD-3557

Conversation

@stefanonardo

@stefanonardo stefanonardo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Split the single capi-controllers Deployment (two containers sharing one SA) into two independent Deployments with dedicated ServiceAccounts and least-privilege RBAC
  • Aligned machine-api-migration metrics port to :8443 (matching all other binaries)

Test plan

  • make build passes
  • make lint passes (0 issues)
  • make unit passes (pre-existing crdcompatibility failures excluded)
  • CI e2e tests pass with both pods running under separate SAs
  • Run audit2rbac on CI job audit logs to confirm zero 403s for both SAs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Split machine API migration into its own workload, with dedicated service account, permissions, deployment, metrics service, and monitoring setup.
    • Updated access and bindings so the new workload has the scoped permissions it needs.
  • Bug Fixes
    • Tightened existing controller permissions and removed now-unneeded metrics and sidecar references.
    • Aligned metrics and network access with the new service layout.
  • Documentation
    • Revised RBAC docs to reflect the separate controller responsibilities and bindings.

Separate the two binaries into independent Deployments with dedicated
ServiceAccounts and least-privilege RBAC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 9, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 9, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 9, 2026

Copy link
Copy Markdown

@stefanonardo: This pull request references OCPCLOUD-3557 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Split the single capi-controllers Deployment (two containers sharing one SA) into two independent Deployments with dedicated ServiceAccounts and least-privilege RBAC
  • Aligned machine-api-migration metrics port to :8443 (matching all other binaries)

Test plan

  • make build passes
  • make lint passes (0 issues)
  • make unit passes (pre-existing crdcompatibility failures excluded)
  • CI e2e tests pass with both pods running under separate SAs
  • Run audit2rbac on CI job audit logs to confirm zero 403s for both SAs

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Walkthrough

This PR separates the machine-api-migration functionality from capi-controllers into its own ServiceAccount, RBAC roles/bindings, Deployment, metrics Service, and ServiceMonitor. capi-controllers RBAC is narrowed accordingly, its Deployment loses the migration container, ports are renamed, and the NetworkPolicy/metrics-service/ServiceMonitor configurations are updated. Documentation reflects the new split.

Changes

machine-api-migration separation

Layer / File(s) Summary
RBAC documentation split
docs/rbac.md
Documents separate capi-controllers and machine-api-migration ServiceAccounts and their respective RBAC bindings/scopes.
New ServiceAccount
manifests/0000_30_cluster-api_02_machine-api-migration-service-account.yaml
Adds machine-api-migration ServiceAccount gated by the ClusterAPIMachineManagement feature gate.
New RBAC roles
manifests/0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml
Adds ClusterRole and two namespaced Roles granting migration-specific permissions for machines/machinesets, secrets, events, and infrastructure resources.
New RBAC bindings
manifests/0000_30_cluster-api_04_machine-api-migration-rbac-bindings.yaml
Adds ClusterRoleBindings and RoleBindings connecting the machine-api-migration ServiceAccount to its roles and the shared read-tls-configuration ClusterRole.
capi-controllers RBAC narrowing
manifests/0000_30_cluster-api_03_rbac_roles.yaml
Removes machines/machinesets status/finalizer and provider-specific infrastructure permissions from capi-controllers roles, plus a stray events rule.
Deployment split
manifests/0000_30_cluster-api_17_machine-api-migration-deployment.yaml, manifests/0000_30_cluster-api_17_deployment.yaml
Adds new machine-api-migration Deployment and removes the migration container/ports from capi-controllers Deployment, renaming remaining webhook ports.
Metrics and network updates
manifests/0000_30_cluster-api_10_machine-api-migration-metrics-service.yaml, manifests/0000_30_cluster-api_10_machine-api-migration-servicemonitor.yaml, manifests/0000_30_cluster-api_10_metrics-service.yaml, manifests/0000_30_cluster-api_10_capi-controllers-servicemonitor.yaml, manifests/0000_30_cluster-api_12_allow-ingress-to-metrics-operators.yaml
Adds a dedicated metrics Service and ServiceMonitor for machine-api-migration, updates capi-controllers Service/ServiceMonitor port references, and extends the NetworkPolicy selector while removing the separate migration ingress rule.

Estimated code review effort: 4 (Complex) | ~50 minutes

Sequence Diagram(s)

sequenceDiagram
    participant Prometheus
    participant MachineAPIMigrationSvc as machine-api-migration-metrics Service
    participant MachineAPIMigrationPod as machine-api-migration Deployment
    participant K8sAPI as Kubernetes API Server

    MachineAPIMigrationPod->>K8sAPI: Authenticate via machine-api-migration ServiceAccount
    K8sAPI-->>MachineAPIMigrationPod: Authorize using Role/ClusterRole bindings
    Prometheus->>MachineAPIMigrationSvc: Scrape metrics (HTTPS, bearer token, TLS)
    MachineAPIMigrationSvc->>MachineAPIMigrationPod: Route to diagnostics port
    MachineAPIMigrationPod-->>Prometheus: Return metrics
Loading

Possibly related PRs

  • openshift/cluster-capi-operator#585: Modifies the same manifests/0000_30_cluster-api_03_rbac_roles.yaml to enforce least-privilege RBAC for capi-controllers, overlapping directly with this PR's RBAC narrowing.
🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: splitting capi-controllers and machine-api-migration into separate components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed PR changes only docs/manifests; no Ginkgo test definitions or titles were added or modified in the touched files.
Test Structure And Quality ✅ Passed PR changes only docs/manifests; no Ginkgo test code was added or modified, so the test-quality check is not applicable.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added or modified in this diff; only docs/manifests changed, so the MicroShift check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added or modified; the PR only changes docs and manifests, so SNO test compatibility is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PASS: The new deployment targets control-plane nodes but is excluded from internal-hosted, with no anti-affinity, spread constraints, or worker-node assumptions.
Ote Binary Stdout Contract ✅ Passed PASS: PR only touches docs/manifests; targeted entrypoints have no stdout prints, and shared init sets klog.LogToStderr(true), so no JSON-stdout contract violation is introduced.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Only docs and YAML manifests changed; no new Ginkgo e2e tests or external network calls were added.
No-Weak-Crypto ✅ Passed Diff is limited to docs/manifests; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons were added.
Container-Privileges ✅ Passed No changed manifest sets privileged/host* or allowPrivilegeEscalation; no SYS_ADMIN capability or explicit root setting was added.
No-Sensitive-Data-In-Logs ✅ Passed Touched files are docs/manifests only, and searches found no log/print statements or debug output exposing sensitive data.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@stefanonardo

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-capi-techpreview

@openshift-ci openshift-ci Bot requested review from RadekManak and mdbooth July 9, 2026 11:18
@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign mdbooth for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with 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.

Inline comments:
In `@docs/rbac.md`:
- Around line 41-43: The RBAC summary for the `machine-api-migration` Role in
`openshift-cluster-api` is mislabeled as “(read)” even though the manifest
grants both read and write verbs. Update the description in `docs/rbac.md` to
reflect the actual permissions from
`0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml`, using the
`machine-api-migration` Role entry and its Machine/MachineSet permissions as the
reference point.

In `@manifests/0000_30_cluster-api_17_machine-api-migration-deployment.yaml`:
- Around line 26-69: The machine-api-migration Deployment container spec is
missing required hardening and health settings. Update the machine-api-migration
pod/container spec to add an explicit securityContext with
readOnlyRootFilesystem, allowPrivilegeEscalation disabled, and capabilities
dropping all, and set automountServiceAccountToken to false if the controller
does not need the token. Also add resource limits alongside the existing
requests, and define livenessProbe and readinessProbe for the healthz endpoint
exposed by the machine-api-migration container on port 9440.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: af553a64-1e21-4c5f-92f4-9de4822110af

📥 Commits

Reviewing files that changed from the base of the PR and between f2f0de3 and bd4c791.

📒 Files selected for processing (12)
  • docs/rbac.md
  • manifests/0000_30_cluster-api_02_machine-api-migration-service-account.yaml
  • manifests/0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml
  • manifests/0000_30_cluster-api_03_rbac_roles.yaml
  • manifests/0000_30_cluster-api_04_machine-api-migration-rbac-bindings.yaml
  • manifests/0000_30_cluster-api_10_capi-controllers-servicemonitor.yaml
  • manifests/0000_30_cluster-api_10_machine-api-migration-metrics-service.yaml
  • manifests/0000_30_cluster-api_10_machine-api-migration-servicemonitor.yaml
  • manifests/0000_30_cluster-api_10_metrics-service.yaml
  • manifests/0000_30_cluster-api_12_allow-ingress-to-metrics-operators.yaml
  • manifests/0000_30_cluster-api_17_deployment.yaml
  • manifests/0000_30_cluster-api_17_machine-api-migration-deployment.yaml
💤 Files with no reviewable changes (1)
  • manifests/0000_30_cluster-api_10_capi-controllers-servicemonitor.yaml

Comment thread docs/rbac.md
Comment on lines +41 to +43
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | ClusterRole `openshift-machine-api-migration` | cluster-wide | Cluster-scoped resources: infrastructures, featuregates, clusterversions, CRDs |
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-cluster-api` | CAPI Cluster (read), Machine/MachineSet + infra cluster (read)/machine/machinetemplate resources, secrets, pod self-read, events, leases |
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-machine-api` | MAPI machines, machinesets, controlplanemachinesets, secrets, events |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

"(read)" label inconsistent with actual RBAC verbs.

Line 42 describes the machine-api-migration Role in openshift-cluster-api as granting Machine/MachineSet access with "(read)" only. The referenced manifest (0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml) grants get, list, watch, create, update, patch on cluster.x-k8s.io machines/machinesets — i.e., full read/write, not read-only.

📝 Suggested fix
-| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-cluster-api` | CAPI Cluster (read), Machine/MachineSet + infra cluster (read)/machine/machinetemplate resources, secrets, pod self-read, events, leases |
+| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-cluster-api` | CAPI Cluster (read), Machine/MachineSet (read/write) + infra cluster/machine/machinetemplate resources, secrets, pod self-read, events, leases |
📝 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
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | ClusterRole `openshift-machine-api-migration` | cluster-wide | Cluster-scoped resources: infrastructures, featuregates, clusterversions, CRDs |
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-cluster-api` | CAPI Cluster (read), Machine/MachineSet + infra cluster (read)/machine/machinetemplate resources, secrets, pod self-read, events, leases |
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-machine-api` | MAPI machines, machinesets, controlplanemachinesets, secrets, events |
| `0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml` | Role `machine-api-migration` | `openshift-cluster-api` | CAPI Cluster (read), Machine/MachineSet (read/write) + infra cluster/machine/machinetemplate resources, secrets, pod self-read, events, leases |
🤖 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 `@docs/rbac.md` around lines 41 - 43, The RBAC summary for the
`machine-api-migration` Role in `openshift-cluster-api` is mislabeled as
“(read)” even though the manifest grants both read and write verbs. Update the
description in `docs/rbac.md` to reflect the actual permissions from
`0000_30_cluster-api_03_machine-api-migration-rbac-roles.yaml`, using the
`machine-api-migration` Role entry and its Machine/MachineSet permissions as the
reference point.

Comment on lines +26 to +69
spec:
serviceAccountName: machine-api-migration
containers:
- name: machine-api-migration
image: registry.ci.openshift.org/openshift:cluster-capi-operator
command:
- /machine-api-migration
args:
- --diagnostics-address=:8443
env:
- name: RELEASE_VERSION
value: "0.0.1-snapshot"
ports:
- containerPort: 8443
name: diagnostics
protocol: TCP
- containerPort: 9440
name: healthz
protocol: TCP
resources:
requests:
cpu: 10m
memory: 50Mi
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: metrics-cert
mountPath: /tmp/k8s-metrics-server/serving-certs
readOnly: true
nodeSelector:
node-role.kubernetes.io/control-plane: ""
priorityClassName: system-cluster-critical
restartPolicy: Always
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
volumes:
- name: metrics-cert
secret:
defaultMode: 420
secretName: machine-api-migration-metrics-tls

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Add explicit securityContext, resource limits, and probes to the container spec.

This new Deployment lacks:

  • Pod/container securityContext (readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"]). Note restricted-v2 SCC (referenced via the openshift.io/required-scc: restricted-v2 annotation) already drops all capabilities and disallows privilege escalation by default, but it does not enforce readOnlyRootFilesystem, so this must be set explicitly.
  • resources.limits (only requests are set).
  • livenessProbe/readinessProbe, despite exposing a healthz port on 9440.
  • automountServiceAccountToken: false (unless the controller genuinely needs the projected SA token via the pod itself rather than client libraries).

Static analysis flags the missing root-fs/security-context settings (Checkov CKV_K8S_20/CKV_K8S_23, Trivy KSV-0014/KSV-0118).

As per path instructions: "securityContext: runAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation: false", "Drop ALL capabilities, add only what is required", "Resource limits (cpu, memory) on every container", "Liveness + readiness probes defined", "automountServiceAccountToken: false unless needed".

🛡️ Proposed fix
     spec:
       serviceAccountName: machine-api-migration
+      automountServiceAccountToken: false
       containers:
       - name: machine-api-migration
         image: registry.ci.openshift.org/openshift:cluster-capi-operator
         command:
         - /machine-api-migration
         args:
           - --diagnostics-address=:8443
         env:
         - name: RELEASE_VERSION
           value: "0.0.1-snapshot"
         ports:
         - containerPort: 8443
           name: diagnostics
           protocol: TCP
         - containerPort: 9440
           name: healthz
           protocol: TCP
         resources:
           requests:
             cpu: 10m
             memory: 50Mi
+          limits:
+            cpu: 100m
+            memory: 100Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop:
+              - ALL
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
         terminationMessagePolicy: FallbackToLogsOnError
🧰 Tools
🪛 Checkov (3.3.2)

[medium] 2-69: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 2-69: Minimize the admission of root containers

(CKV_K8S_23)

🪛 Trivy (0.69.3)

[error] 29-53: Root file system is not read-only

Container 'machine-api-migration' of Deployment 'machine-api-migration' should set 'securityContext.readOnlyRootFilesystem' to true

Rule: KSV-0014

Learn more

(IaC/Kubernetes)


[error] 29-53: Default security context configured

container machine-api-migration in openshift-cluster-api namespace is using the default security context

Rule: KSV-0118

Learn more

(IaC/Kubernetes)


[error] 26-69: Default security context configured

deployment machine-api-migration in openshift-cluster-api namespace is using the default security context, which allows root privileges

Rule: KSV-0118

Learn more

(IaC/Kubernetes)

🤖 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 `@manifests/0000_30_cluster-api_17_machine-api-migration-deployment.yaml`
around lines 26 - 69, The machine-api-migration Deployment container spec is
missing required hardening and health settings. Update the machine-api-migration
pod/container spec to add an explicit securityContext with
readOnlyRootFilesystem, allowPrivilegeEscalation disabled, and capabilities
dropping all, and set automountServiceAccountToken to false if the controller
does not need the token. Also add resource limits alongside the existing
requests, and define livenessProbe and readinessProbe for the healthz endpoint
exposed by the machine-api-migration container on port 9440.

Sources: Path instructions, Linters/SAST tools

@stefanonardo

Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@stefanonardo: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-capi-techpreview bd4c791 link true /test e2e-aws-capi-techpreview

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants