Skip to content

Add activation_job_namespace for workload isolation#357

Open
TheRealHaoLiu wants to merge 2 commits into
ansible:mainfrom
TheRealHaoLiu:worktree-activation-job-namespace
Open

Add activation_job_namespace for workload isolation#357
TheRealHaoLiu wants to merge 2 commits into
ansible:mainfrom
TheRealHaoLiu:worktree-activation-job-namespace

Conversation

@TheRealHaoLiu

@TheRealHaoLiu TheRealHaoLiu commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds an optional activation_job_namespace field to the EDA CR that isolates activation job pods in a dedicated namespace
  • When set, pod/job/secret/service permissions are moved from the EDA namespace Role to a new Role in the dedicated namespace, following the principle of least privilege
  • The operator automatically creates the namespace, Role, and RoleBinding, and passes EDA_ACTIVATION_JOB_NAMESPACE to the activation-worker container
  • When not set, behavior is unchanged (fully backwards compatible)

Follows the same pattern as awx-operator#2122.

Changes

File Change
config/crd/bases/eda.ansible.com_edas.yaml Add activation_job_namespace string field to CRD spec
roles/eda/defaults/main.yml Add activation_job_namespace: '' default
roles/common/templates/service_account.yaml.j2 Conditionally scope RBAC: remove pod/job/secret/service/ingress perms from EDA namespace when set; create Namespace + Role + RoleBinding in dedicated namespace
config/rbac/role.yaml Grant operator namespaces (get, create) permission
roles/eda/templates/eda-activation-worker.deployment.yaml.j2 Pass EDA_ACTIVATION_JOB_NAMESPACE env var to activation-worker when set

Test plan

  • Deploy EDA without activation_job_namespace set — verify existing behavior is unchanged
  • Deploy EDA with activation_job_namespace: eda-jobs — verify:
    • Namespace eda-jobs is created
    • Role and RoleBinding exist in eda-jobs namespace with correct permissions
    • EDA namespace Role no longer has pod/job/secret/service permissions
    • Activation worker pod has EDA_ACTIVATION_JOB_NAMESPACE=eda-jobs env var
    • Activation jobs run in the eda-jobs namespace

Summary by CodeRabbit

  • New Features

    • Added spec.activation_job_namespace to specify the namespace where activation job pods run.
    • When set, activation job namespace permissions are created/granted automatically.
    • The activation worker now receives EDA_ACTIVATION_JOB_NAMESPACE when activation_job_namespace is provided.
  • RBAC & Security

    • Updated RBAC to conditionally scope activation job permissions based on activation_job_namespace.
    • Added permissions needed to create/access namespaces as part of the activation workflow.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Introduces activation_job_namespace as a new optional string field in the EDA operator. When set, the operator creates the specified namespace, provisions a scoped job-execution Role and RoleBinding for its service account in that namespace, and injects the value as EDA_ACTIVATION_JOB_NAMESPACE into the activation worker container.

Changes

activation_job_namespace cross-namespace support

Layer / File(s) Summary
CRD schema and configuration defaults
config/crd/bases/eda.ansible.com_edas.yaml, roles/eda/defaults/main.yml
Adds spec.activation_job_namespace as a string field to the EDA CRD schema and defaults it to an empty string.
Namespace provisioning and RBAC rules
config/rbac/role.yaml, roles/common/templates/service_account.yaml.j2
Grants get/create on namespaces to the operator's cluster Role. Conditionally restructures the primary Role's RBAC rules; when activation_job_namespace is set, emits a target Namespace, a scoped {{ ansible_operator_meta.name }}-job-execution Role with pod/job/secret/service permissions, and a matching RoleBinding.
Activation worker environment injection
roles/eda/templates/eda-activation-worker.deployment.yaml.j2
Conditionally injects EDA_ACTIVATION_JOB_NAMESPACE into the activation worker container environment when activation_job_namespace is defined.

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 captures the main objective of the PR: adding an activation_job_namespace feature for workload isolation, which is reflected across all modified files.
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.

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

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

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

When set, activation job pods run in a dedicated namespace with their
own RBAC, reducing the permissions granted in the EDA control plane
namespace. Follows the same pattern as awx-operator PR #2122.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@TheRealHaoLiu TheRealHaoLiu force-pushed the worktree-activation-job-namespace branch from fd8356c to e13ac0c Compare June 18, 2026 14:39

@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 `@config/crd/bases/eda.ansible.com_edas.yaml`:
- Around line 1441-1443: The activation_job_namespace field lacks input
validation, which allows invalid Kubernetes namespace names to be accepted and
cause runtime failures during reconciliation. Add schema validation constraints
to the activation_job_namespace field definition by including a pattern
constraint that enforces DNS-1123 subdomain format (allowing lowercase letters,
numbers, and hyphens), set maxLength to 253 to match Kubernetes namespace naming
limits, and ensure the pattern allows empty strings to preserve the default
behavior when the field is not specified.

In `@config/rbac/role.yaml`:
- Around line 7-13: The namespaces resource is cluster-scoped and cannot be
managed through a namespaced Role. Create a separate ClusterRole (instead of
using the existing namespaced Role) with the apiGroups, resources, and verbs for
the namespaces permission block. Then create a corresponding ClusterRoleBinding
that binds this new ClusterRole to the operator's service account. Remove the
namespaces resource rules from the current namespaced Role definition.
🪄 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: 3d1b4524-1d82-436d-b115-c1e7cc133040

📥 Commits

Reviewing files that changed from the base of the PR and between e368ffb and fd8356c.

📒 Files selected for processing (5)
  • config/crd/bases/eda.ansible.com_edas.yaml
  • config/rbac/role.yaml
  • roles/common/templates/service_account.yaml.j2
  • roles/eda/defaults/main.yml
  • roles/eda/templates/eda-activation-worker.deployment.yaml.j2

Comment on lines +1441 to +1443
activation_job_namespace:
description: Namespace where activation job pods will run. Creates the namespace and grants required permissions automatically.
type: string

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

🧩 Analysis chain

🏁 Script executed:

# First, check the CRD file to see the field definition and surrounding context
head -n 1450 config/crd/bases/eda.ansible.com_edas.yaml | tail -n 30

Repository: ansible/eda-server-operator

Length of output: 2425


🏁 Script executed:

# Also get more context around the field to understand its full definition
sed -n '1430,1460p' config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 2517


🏁 Script executed:

# Find and examine the template file mentioned in the review
find . -name "service_account.yaml.j2" -type f

Repository: ansible/eda-server-operator

Length of output: 120


🏁 Script executed:

# Search for how activation_job_namespace is used in the codebase
rg "activation_job_namespace" -B 2 -A 2

Repository: ansible/eda-server-operator

Length of output: 3571


🏁 Script executed:

# Check if there are any validation rules defined for this field or similar namespace fields in the CRD
rg "pattern|maxLength|minLength" config/crd/bases/eda.ansible.com_edas.yaml | head -20

Repository: ansible/eda-server-operator

Length of output: 2557


🏁 Script executed:

# Get the exact section of the CRD for activation_job_namespace with surrounding context
sed -n '1440,1450p' config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 991


🏁 Script executed:

# Search for the full definition of activation_job_namespace field in the CRD including any validation
rg -A 10 "activation_job_namespace:" config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 638


🏁 Script executed:

# Check if there are other namespace-type fields in the CRD that might have validation patterns we should follow
rg -B 2 -A 5 "metadata.name|namespace.*name|DNS.*label" config/crd/bases/eda.ansible.com_edas.yaml | head -50

Repository: ansible/eda-server-operator

Length of output: 53


🏁 Script executed:

# Let's verify Kubernetes namespace naming requirements and check if there's any validation happening elsewhere
# Search for any validationRules or CEL validations in the CRD
rg -i "validationRules|x-kubernetes" config/crd/bases/eda.ansible.com_edas.yaml | head -10

Repository: ansible/eda-server-operator

Length of output: 618


🏁 Script executed:

# Check the full context around where activation_job_namespace is defined to be sure there's no validation
sed -n '1435,1455p' config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 1654


🏁 Script executed:

# Get the exact lines around 1441-1443 to see the field definition
sed -n '1440,1450p' config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 991


🏁 Script executed:

# Look for the activation_job_namespace field definition to see if there are any pattern or validation constraints right after type: string
awk '/activation_job_namespace:/{p=1} p{print} /type: string/&&p{if(++count==1) exit}' config/crd/bases/eda.ansible.com_edas.yaml

Repository: ansible/eda-server-operator

Length of output: 284


🏁 Script executed:

# Check if there are any webhook validators or admission controllers in the repo
find . -type f \( -name "*webhook*" -o -name "*validation*" -o -name "*admission*" \) ! -path "*/node_modules/*" ! -path "*/.git/*" | head -20

Repository: ansible/eda-server-operator

Length of output: 53


🏁 Script executed:

# Look at the template more carefully to understand how activation_job_namespace is used
cat roles/common/templates/service_account.yaml.j2 | grep -A 5 -B 5 "activation_job_namespace"

Repository: ansible/eda-server-operator

Length of output: 1452


Add schema validation for activation_job_namespace to enforce Kubernetes namespace naming rules.

This field is rendered directly into Namespace.metadata.name and RBAC namespace fields without validation. Invalid values will cause reconciliation failures at runtime instead of being rejected at admission time. Add a pattern constraint for DNS-1123 subdomain format with maxLength: 253, while allowing empty string for the default behavior.

🤖 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 `@config/crd/bases/eda.ansible.com_edas.yaml` around lines 1441 - 1443, The
activation_job_namespace field lacks input validation, which allows invalid
Kubernetes namespace names to be accepted and cause runtime failures during
reconciliation. Add schema validation constraints to the
activation_job_namespace field definition by including a pattern constraint that
enforces DNS-1123 subdomain format (allowing lowercase letters, numbers, and
hyphens), set maxLength to 253 to match Kubernetes namespace naming limits, and
ensure the pattern allows empty strings to preserve the default behavior when
the field is not specified.

Comment thread config/rbac/role.yaml
Comment on lines +7 to +13
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- create

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

Move namespaces resource rules to a ClusterRole with ClusterRoleBinding.

namespaces is cluster-scoped and cannot be authorized through a namespaced Role. This prevents the activation_job_namespace feature from creating namespaces. Create a separate ClusterRole with the namespace permissions and bind it to the operator's service account.

🤖 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 `@config/rbac/role.yaml` around lines 7 - 13, The namespaces resource is
cluster-scoped and cannot be managed through a namespaced Role. Create a
separate ClusterRole (instead of using the existing namespaced Role) with the
apiGroups, resources, and verbs for the namespaces permission block. Then create
a corresponding ClusterRoleBinding that binds this new ClusterRole to the
operator's service account. Remove the namespaces resource rules from the
current namespaced Role definition.

Remove batch/extensions jobs from EDA namespace Role when
activation_job_namespace is set, and restore the ingress rule
for the unset case to keep the Role identical to the original.

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

Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (1)
roles/common/templates/service_account.yaml.j2 (1)

21-32: ⚠️ Potential issue | 🟠 Major

Empty rules block produces invalid YAML when activation_job_namespace is set.

When activation_job_namespace is set, the main Role template outputs rules: followed by no value, which YAML parses as rules: null. Kubernetes RBAC validation expects an array, not null, which will cause API validation failures.

Additionally, the job-execution Role (used when activation_job_namespace is set) lacks ingress permissions that are present in the main Role. This creates a permissions gap: ingress access is available only when activation_job_namespace is NOT set.

Suggested fix: emit empty array instead of null
 rules:
-{% if not activation_job_namespace %}
+{% if activation_job_namespace %}
+[]
+{% else %}
 - apiGroups: [""]
   resources: ["pods", "pods/log", "jobs", "secrets", "services"]
   verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
 - apiGroups: ["batch", "extensions"]
   resources: ["jobs"]
   verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
 - apiGroups: ["networking.k8s.io"]
   resources: ["ingresses"]
   verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
 {% endif %}

Note: The missing ingress permissions in the job-execution Role also need to be addressed to maintain consistent access across both RBAC configurations.

🤖 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/common/templates/service_account.yaml.j2` around lines 21 - 32, The
rules block in the service_account.yaml.j2 template outputs null (invalid YAML)
when activation_job_namespace is set because the conditional {% if not
activation_job_namespace %} wraps all the rules. To fix this, ensure the rules
key always has a value by either providing an empty array [] when the condition
is false, or restructuring the template so rules always contains valid content.
Additionally, the job-execution Role template (used when
activation_job_namespace is set) is missing the networking.k8s.io ingresses
permissions that exist in the main Role. Add the ingresses rule block with the
same verbs (get, list, watch, create, update, patch, delete) to the
job-execution Role to maintain consistent permissions across both RBAC
configurations.
🤖 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/common/templates/service_account.yaml.j2`:
- Around line 21-32: The rules block in the service_account.yaml.j2 template
outputs null (invalid YAML) when activation_job_namespace is set because the
conditional {% if not activation_job_namespace %} wraps all the rules. To fix
this, ensure the rules key always has a value by either providing an empty array
[] when the condition is false, or restructuring the template so rules always
contains valid content. Additionally, the job-execution Role template (used when
activation_job_namespace is set) is missing the networking.k8s.io ingresses
permissions that exist in the main Role. Add the ingresses rule block with the
same verbs (get, list, watch, create, update, patch, delete) to the
job-execution Role to maintain consistent permissions across both RBAC
configurations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 4568efd9-4b11-4c9e-889f-9409f477c782

📥 Commits

Reviewing files that changed from the base of the PR and between e13ac0c and bb077fa.

📒 Files selected for processing (1)
  • roles/common/templates/service_account.yaml.j2

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.

1 participant