Skip to content

feat: add configurable namespace for activation job pods#345

Open
amasolov wants to merge 5 commits into
ansible:mainfrom
amasolov:feature/activation-job-namespace
Open

feat: add configurable namespace for activation job pods#345
amasolov wants to merge 5 commits into
ansible:mainfrom
amasolov:feature/activation-job-namespace

Conversation

@amasolov
Copy link
Copy Markdown

@amasolov amasolov commented May 4, 2026

Summary

  • Adds activation_job_namespace field to the activation_worker section of the EDA CRD, allowing activation job pods to run in a separate Kubernetes namespace for security isolation, resource quota management, and NetworkPolicy boundaries.
  • The operator injects EDA_ACTIVATION_JOB_NAMESPACE into the activation worker ConfigMap and creates cross-namespace RBAC so the EDA ServiceAccount can manage Jobs, Pods, Secrets, and Services in the target namespace.

What changed

  • CRD: new optional string field activation_worker.activation_job_namespace.
  • Role defaults: activation_job_namespace defaults to empty string (feature disabled).
  • ConfigMap template: conditionally sets EDA_ACTIVATION_JOB_NAMESPACE env var.
  • New RBAC template: eda-activation-job-namespace-rbac.yaml.j2 creates a Role and RoleBinding in the target namespace.
  • Deploy task: applies cross-namespace RBAC when activation_job_namespace is set; removes it when unset.
  • ClusterRole + ClusterRoleBinding: grants the operator SA permission to manage Roles and RoleBindings in the target namespace.

Why

Operators running EDA on shared clusters need activation job pods (which run user-supplied rulebooks and decision environments) isolated from the EDA control plane. A dedicated namespace enables independent ResourceQuota, LimitRange, and NetworkPolicy controls.

Server-side companion

The eda-server side reads EDA_ACTIVATION_JOB_NAMESPACE as an override in _set_namespace(), falling back to the SA token file. A companion PR will be filed on ansible/eda-server.

How to test

  1. Deploy an EDA CR without activation_job_namespace (default behaviour, no change).
  2. Set activation_worker.activation_job_namespace: "eda-jobs" on the CR.
  3. Verify the operator creates Role + RoleBinding in the eda-jobs namespace.
  4. Verify EDA_ACTIVATION_JOB_NAMESPACE appears in the activation worker ConfigMap.

Breaking changes / dependencies

None. Field is optional; existing CRs are unaffected.

Closes #344.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Allow specifying a custom Kubernetes namespace for activation job execution; operator will provision needed RBAC and expose the setting to the operator via its environment.
    • Operator now creates and cleans up cross-namespace RBAC when the activation-job namespace is added, changed, or removed.
  • Tests

    • Added CI scenario to exercise the activation-job-namespace workflow.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 3849e04d-441a-47e3-8df7-1bd324649813

📥 Commits

Reviewing files that changed from the base of the PR and between 41049e5 and ed5c717.

📒 Files selected for processing (2)
  • config/rbac/activation_job_namespace_role.yaml
  • roles/eda/tasks/deploy_eda.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • roles/eda/tasks/deploy_eda.yml

📝 Walkthrough

Walkthrough

This PR adds operator-side support for directing EDA activation job pods into a configurable Kubernetes namespace, extending the CRD, adding cluster- and namespace-scoped RBAC, wiring an env var into the operator ConfigMap, and updating deployment tasks and CI/workflow.

Changes

Cross-Namespace Activation Job Support

Layer / File(s) Summary
CRD Schema
config/crd/bases/eda.ansible.com_edas.yaml
Added spec.activation_worker.activation_job_namespace field to allow specifying the target Kubernetes namespace for activation job pods.
Operator Permissions
config/rbac/activation_job_namespace_role.yaml, config/rbac/activation_job_namespace_role_binding.yaml, config/rbac/kustomization.yaml
New cluster-scoped ClusterRole eda-activation-job-namespace-manager and ClusterRoleBinding bind the operator (controller-manager SA) to allow managing Roles/RoleBindings in target namespaces; kustomization includes both resources.
Configuration Defaults & ConfigMap
roles/eda/defaults/main.yml, roles/eda/templates/eda.configmap.yaml.j2
Adds _activation_worker.activation_job_namespace default and conditionally injects EDA_ACTIVATION_JOB_NAMESPACE into the operator env ConfigMap when configured.
Deployment Logic & Namespaced RBAC Template
roles/eda/tasks/deploy_eda.yml, roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2
Deploy tasks read prior env, apply or remove the namespaced Role and RoleBinding (via Jinja2 template) in the configured target namespace to grant the operator SA permissions for jobs, pods, secrets, and services.
CI / Workflow
.ci/eda_v1alpha1_eda.activation_job_namespace.ci.yaml, .github/workflows/pr.yml
Adds a CI manifest with activation_job_namespace: "eda-jobs" and a PR workflow matrix scenario plus a conditional step to create the eda-jobs namespace for that scenario.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: adding a configurable namespace for activation job pods, which is the core feature introduced across multiple files (CRD, RBAC, templates, and CI).
Linked Issues check ✅ Passed All operator-side coding objectives from #344 are addressed: CRD field added, environment variable injection implemented, cross-namespace RBAC templates and logic created, and ClusterRole/ClusterRoleBinding for operator permissions added.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the configurable activation job namespace feature. No unrelated modifications detected; changes cover CRD, RBAC, deployment logic, templates, and CI testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@config/rbac/activation_job_namespace_role.yaml`:
- Around line 1-26: The ClusterRole eda-activation-job-namespace-manager
currently allows create/update/patch/delete on resources roles and rolebindings
across all namespaces, which grants the operator ServiceAccount cluster-wide
RBAC management; update the project documentation and operator
security/threat-model notes to explicitly record that
eda-activation-job-namespace-manager grants these cluster-scoped verbs on
resources roles and rolebindings, why this broad scope is required for dynamic
target namespaces, and list mitigation/alternatives (e.g., dynamic ClusterRole
provisioning via an admission webhook or dedicated RBAC controller) so reviewers
and deployers are aware of the elevated privilege and possible hardening paths.

In `@roles/eda/tasks/deploy_eda.yml`:
- Around line 48-61: The cleanup task never deletes RBAC because it uses
combined_activation_worker.activation_job_namespace (which is empty when
cleared) and _previous_activation_job_namespace is never set; fix by first
capturing the existing activation namespace into
_previous_activation_job_namespace (use a set_fact immediately after loading the
CR/ConfigMap where combined_activation_worker.activation_job_namespace is read)
and then change the k8s task's namespace to use
_previous_activation_job_namespace and adjust the when to check
_previous_activation_job_namespace | default('') | length > 0 and
combined_activation_worker.activation_job_namespace | default('') | length == 0
so the Role/RoleBinding deletion runs against the old namespace.

In `@roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2`:
- Around line 11-46: The Role's rules for resources "secrets", "pods",
"pods/log", "services", and "jobs" are missing the "update" verb and will cause
403s when the EDA server performs HTTP PUT updates; modify each corresponding
rule in the template (the rules blocks that list apiGroups: "" for
secrets/pods/pods/log and services, and apiGroups: batch for jobs) to include
"update" in the verbs array so the Role permits update operations.
🪄 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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: daea2dbc-5fd1-4016-94c6-81433770c31f

📥 Commits

Reviewing files that changed from the base of the PR and between 94497a7 and 9f90271.

📒 Files selected for processing (8)
  • config/crd/bases/eda.ansible.com_edas.yaml
  • config/rbac/activation_job_namespace_role.yaml
  • config/rbac/activation_job_namespace_role_binding.yaml
  • config/rbac/kustomization.yaml
  • roles/eda/defaults/main.yml
  • roles/eda/tasks/deploy_eda.yml
  • roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2
  • roles/eda/templates/eda.configmap.yaml.j2

Comment thread config/rbac/activation_job_namespace_role.yaml
Comment thread roles/eda/tasks/deploy_eda.yml Outdated
Comment thread roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2
Add activation_job_namespace field to the activation_worker section of
the EDA CRD.  When set, the operator injects
EDA_ACTIVATION_JOB_NAMESPACE into the activation worker ConfigMap and
creates a Role + RoleBinding in the target namespace so the EDA
ServiceAccount can manage Jobs, Pods, Secrets, and Services there.

Changes:
- CRD: new optional string field activation_worker.activation_job_namespace
- Role defaults: activation_job_namespace defaults to empty string
- ConfigMap template: conditionally sets EDA_ACTIVATION_JOB_NAMESPACE
- New RBAC template for cross-namespace Role and RoleBinding
- Deploy task: applies/removes cross-namespace RBAC conditionally
- ClusterRole + ClusterRoleBinding for operator to manage RBAC in
  the target namespace

Closes ansible#344

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
amasolov added a commit to amasolov/eda-server that referenced this pull request May 4, 2026
Read EDA_ACTIVATION_JOB_NAMESPACE environment variable in
_set_namespace() as an override before falling back to the
ServiceAccount token namespace file.  This allows the eda-server-operator
to direct activation job pods into a separate Kubernetes namespace for
security isolation, resource quotas, and NetworkPolicy boundaries.

Changes:
- _set_namespace() checks EDA_ACTIVATION_JOB_NAMESPACE first
- Unit tests for override, fallback, whitespace handling, and error case

Companion operator PR: ansible/eda-server-operator#345

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@amasolov amasolov force-pushed the feature/activation-job-namespace branch from 9f90271 to 1353abe Compare May 4, 2026 06:52
@ttuffin
Copy link
Copy Markdown
Contributor

ttuffin commented May 18, 2026

@amasolov I think it would be worthwhile adding a new CR (e.g .ci/eda_v1alpha1_eda.activation_job_namespace.ci.yaml) to the CI to test this new parameter.

activation_worker:
  activation_job_namespace: "eda-jobs"

And then add it to the matrix in pr.yml:

- SCENARIO: activation_job_namespace

We'll also need to add a step to ensure the namespace is create before applying the CR:

- name: Create activation job namespace
  run: kubectl create namespace eda-jobs
  if: ${{ matrix.SCENARIO == 'activation_job_namespace' }}

@ttuffin ttuffin requested a review from a team May 18, 2026 11:23
Add a CI test scenario for the new activation_job_namespace parameter.
Creates a dedicated CR fixture and pre-creates the target namespace
before applying the CR.

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
roles/eda/tasks/deploy_eda.yml (1)

22-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Previous namespace is captured too late, and cleanup misses namespace changes.

Line 22 applies the env ConfigMap before Lines 41-56 read _previous_activation_job_namespace, so on unset/change you can lose the old value and skip deletion in the old namespace. Also, Lines 75-76 only clean up when the new value is empty; changing A -> B leaves RBAC orphaned in A.

Suggested fix
+# Move these tasks to run before "Apply ConfigMap resources"
 - name: Look up existing ConfigMap for previous activation_job_namespace
   kubernetes.core.k8s_info:
     api_version: v1
     kind: ConfigMap
     namespace: "{{ ansible_operator_meta.namespace }}"
     name: "{{ ansible_operator_meta.name }}-{{ deployment_type }}-env-properties"
   register: _eda_env_cm

 - name: Record previous activation_job_namespace from ConfigMap
   ansible.builtin.set_fact:
     _previous_activation_job_namespace: >-
       {{ (_eda_env_cm.resources | first).data.EDA_ACTIVATION_JOB_NAMESPACE | default('') }}
   when:
     - _eda_env_cm.resources | length > 0
     - (_eda_env_cm.resources | first).data is defined

 - name: Remove cross-namespace RBAC when activation_job_namespace is unset
   k8s:
     state: absent
     api_version: rbac.authorization.k8s.io/v1
     kind: "{{ item.kind }}"
     name: "{{ ansible_operator_meta.name }}-activation-job-manager"
     namespace: "{{ _previous_activation_job_namespace }}"
   loop:
     - { kind: RoleBinding }
     - { kind: Role }
   when:
-    - combined_activation_worker.activation_job_namespace | default('') | length == 0
     - _previous_activation_job_namespace | default('') | length > 0
+    - combined_activation_worker.activation_job_namespace | default('') != _previous_activation_job_namespace

Also applies to: 41-77

🤖 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 `@roles/eda/tasks/deploy_eda.yml` around lines 22 - 27, The Apply ConfigMap
resources task currently runs before capturing
_previous_activation_job_namespace and the RBAC cleanup only triggers when the
new namespace is empty, which can leave orphaned RBAC in the old namespace; move
or duplicate the lookup/read of _previous_activation_job_namespace so it happens
before the "Apply ConfigMap resources" step (ensure the variable is captured
prior to any namespace-changing actions), and change the RBAC deletion condition
(the logic around the lines that check the new namespace — currently only
deleting when empty) to also delete when the previous namespace differs from the
new one so RBAC is removed from the old namespace when namespace changes from A
to B; ensure you still update/set _previous_activation_job_namespace after
successful apply so future runs have the correct previous value.
🤖 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.

Outside diff comments:
In `@roles/eda/tasks/deploy_eda.yml`:
- Around line 22-27: The Apply ConfigMap resources task currently runs before
capturing _previous_activation_job_namespace and the RBAC cleanup only triggers
when the new namespace is empty, which can leave orphaned RBAC in the old
namespace; move or duplicate the lookup/read of
_previous_activation_job_namespace so it happens before the "Apply ConfigMap
resources" step (ensure the variable is captured prior to any namespace-changing
actions), and change the RBAC deletion condition (the logic around the lines
that check the new namespace — currently only deleting when empty) to also
delete when the previous namespace differs from the new one so RBAC is removed
from the old namespace when namespace changes from A to B; ensure you still
update/set _previous_activation_job_namespace after successful apply so future
runs have the correct previous value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 428b68ab-1f1e-4185-aebe-0d8374f73ae9

📥 Commits

Reviewing files that changed from the base of the PR and between 9f90271 and 41049e5.

📒 Files selected for processing (10)
  • .ci/eda_v1alpha1_eda.activation_job_namespace.ci.yaml
  • .github/workflows/pr.yml
  • config/crd/bases/eda.ansible.com_edas.yaml
  • config/rbac/activation_job_namespace_role.yaml
  • config/rbac/activation_job_namespace_role_binding.yaml
  • config/rbac/kustomization.yaml
  • roles/eda/defaults/main.yml
  • roles/eda/tasks/deploy_eda.yml
  • roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2
  • roles/eda/templates/eda.configmap.yaml.j2
✅ Files skipped from review due to trivial changes (3)
  • .ci/eda_v1alpha1_eda.activation_job_namespace.ci.yaml
  • config/rbac/activation_job_namespace_role.yaml
  • config/rbac/kustomization.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
  • roles/eda/defaults/main.yml
  • config/crd/bases/eda.ansible.com_edas.yaml
  • roles/eda/templates/eda.configmap.yaml.j2
  • roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2

amasolov and others added 3 commits May 18, 2026 22:11
…espace changes

Move the lookup of _previous_activation_job_namespace to run before
the ConfigMap is applied, so the old value is read before it gets
overwritten.

Also widen the RBAC cleanup condition to trigger whenever the
previous namespace differs from the new one (not just when the new
value is empty), so changing from namespace A to B correctly removes
orphaned Role and RoleBinding from A.

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add the escalate verb on the roles resource in the
eda-activation-job-namespace-manager ClusterRole. Kubernetes RBAC
escalation prevention blocks creating a Role that grants permissions
the creator doesn't hold. The escalate verb is the standard mechanism
to permit this without granting the operator broad cluster-wide
access to pods, secrets, services, and jobs.

Also moves the _previous_activation_job_namespace lookup to run
before the ConfigMap is applied (so the old value is captured before
overwrite) and widens the RBAC cleanup condition to trigger on any
namespace change, not just removal.

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The escalate verb fixed Role creation, but creating a RoleBinding
that references a Role with elevated permissions also requires the
bind verb on the roles resource. Without it, Kubernetes RBAC
escalation prevention blocks the RoleBinding creation.

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud
Copy link
Copy Markdown

@amasolov
Copy link
Copy Markdown
Author

@amasolov I think it would be worthwhile adding a new CR

Agreed and done!

ttuffin pushed a commit to ansible/eda-server that referenced this pull request May 19, 2026
- Adds `EDA_ACTIVATION_JOB_NAMESPACE` environment variable support to
`_set_namespace()` in the Kubernetes engine, allowing activation job
pods to be directed into a separate namespace.

Companion PR: ansible/eda-server-operator#345
Related: ansible/eda-server-operator#344

Made with [Cursor](https://cursor.com)

Signed-off-by: Alexey Masolov <amasolov@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: support configurable namespace for activation job pods

2 participants