Skip to content
Merged
6 changes: 1 addition & 5 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,10 @@ rules:
- update
- watch
- apiGroups:
- apps
- networking.k8s.io
resources:
- deployments
- daemonsets
- replicasets
- statefulsets
- ingresses
- networkpolicies
verbs:
- get
- list
Expand Down
79 changes: 75 additions & 4 deletions molecule/default/tasks/eda_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,78 @@
vars:
cr_file: 'eda_v1alpha1_eda.yaml'

- name: Add assertions here
assert:
that: false
fail_msg: FIXME Add real assertions for your operator
- name: Set EDA resource name from sample CR
ansible.builtin.set_fact:
eda_cr_name: "{{ lookup('file', samples_dir + '/eda_v1alpha1_eda.yaml') | from_yaml | json_query('metadata.name') }}"

- name: Verify default-deny NetworkPolicy exists
kubernetes.core.k8s_info:
api_version: networking.k8s.io/v1
kind: NetworkPolicy
namespace: '{{ namespace }}'
name: '{{ eda_cr_name }}-default-deny'
register: np_default_deny
until: np_default_deny.resources | length > 0
retries: 10
delay: 5

- name: Assert default-deny selects eda-operator managed pods and denies all traffic
ansible.builtin.assert:
that:
- np_default_deny.resources[0].spec.podSelector.matchExpressions | length == 1
- np_default_deny.resources[0].spec.podSelector.matchExpressions[0].key == 'app.kubernetes.io/managed-by'
- np_default_deny.resources[0].spec.podSelector.matchExpressions[0].operator == 'In'
- np_default_deny.resources[0].spec.podSelector.matchExpressions[0].values | length == 1
- np_default_deny.resources[0].spec.podSelector.matchExpressions[0].values[0] == deployment_type + '-operator'
- "'Ingress' in np_default_deny.resources[0].spec.policyTypes"
- "'Egress' in np_default_deny.resources[0].spec.policyTypes"
- np_default_deny.resources[0].spec.ingress is not defined or np_default_deny.resources[0].spec.ingress | length == 0
- np_default_deny.resources[0].spec.egress is not defined or np_default_deny.resources[0].spec.egress | length == 0
fail_msg: "default-deny NetworkPolicy does not match expected spec: {{ np_default_deny.resources }}"

- name: Verify postgres NetworkPolicy exists
kubernetes.core.k8s_info:
api_version: networking.k8s.io/v1
kind: NetworkPolicy
namespace: '{{ namespace }}'
name: '{{ eda_cr_name }}-postgres-{{ supported_pg_version }}'
register: np_postgres
until: np_postgres.resources | length > 0
retries: 10
delay: 5

- name: Assert postgres NetworkPolicy allows app=eda ingress for activation Job pod pg_notify connectivity
ansible.builtin.assert:
that:
- np_postgres.resources[0].spec.podSelector.matchLabels['app.kubernetes.io/component'] == 'database'
- np_postgres.resources[0].spec.ingress | length > 0
- np_postgres.resources[0].spec.ingress[0].from | selectattr('podSelector.matchLabels.app', 'defined') | selectattr('podSelector.matchLabels.app', 'equalto', 'eda') | list | length > 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
fail_msg: "Postgres NetworkPolicy missing app=eda ingress rule: {{ np_postgres.resources }}"

- name: Verify per-workload NetworkPolicies exist
kubernetes.core.k8s_info:
api_version: networking.k8s.io/v1
kind: NetworkPolicy
namespace: '{{ namespace }}'
name: '{{ eda_cr_name }}-{{ item }}'
register: np_workload
until: np_workload.resources | length > 0
retries: 10
delay: 5
loop: "{{ ['api', 'default-worker', 'activation-worker', 'event-stream', 'db-management'] + ([] if ui_disabled | bool else ['ui']) }}"

- name: Assert UI NetworkPolicy is absent when ui_disabled
kubernetes.core.k8s_info:
api_version: networking.k8s.io/v1
kind: NetworkPolicy
namespace: '{{ namespace }}'
name: '{{ eda_cr_name }}-ui'
register: np_ui_absent
when: ui_disabled | bool

- name: Assert UI NetworkPolicy is absent when ui_disabled
ansible.builtin.assert:
that:
- np_ui_absent.resources | length == 0
fail_msg: "UI NetworkPolicy should be absent when ui_disabled=true"
when: ui_disabled | bool
3 changes: 3 additions & 0 deletions roles/eda/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
- ingress_type | lower == 'route'
- route_tls_secret | length

- name: Apply NetworkPolicies for EDA operand pods
include_tasks: networkpolicy.yml

- name: Deploy EDA
include_tasks: deploy_eda.yml

Expand Down
46 changes: 46 additions & 0 deletions roles/eda/tasks/networkpolicy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
- name: Load postgres role vars for supported_pg_version
ansible.builtin.include_vars:
file: "{{ role_path }}/../postgres/vars/main.yml"

- name: Apply default deny NetworkPolicy for EDA operand pods
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'default-deny.networkpolicy.yaml.j2') }}"

- name: Apply EDA API NetworkPolicy
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'eda-api.networkpolicy.yaml.j2') }}"

- name: Apply EDA UI NetworkPolicy
Comment thread
ttuffin marked this conversation as resolved.
kubernetes.core.k8s:
state: "{{ 'present' if not ui_disabled else 'absent' }}"
Comment thread
ttuffin marked this conversation as resolved.
apply: true
definition: "{{ lookup('template', 'eda-ui.networkpolicy.yaml.j2') }}"

- name: Apply EDA default-worker NetworkPolicy
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'eda-default-worker.networkpolicy.yaml.j2') }}"

- name: Apply EDA activation-worker NetworkPolicy
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'eda-activation-worker.networkpolicy.yaml.j2') }}"

- name: Apply EDA event-stream NetworkPolicy
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'eda-event-stream.networkpolicy.yaml.j2') }}"

- name: Apply db-management NetworkPolicy for backup and restore pods
kubernetes.core.k8s:
state: present
apply: true
definition: "{{ lookup('template', 'db-management.networkpolicy.yaml.j2') }}"
43 changes: 43 additions & 0 deletions roles/eda/templates/db-management.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: '{{ ansible_operator_meta.name }}-db-management'
namespace: '{{ ansible_operator_meta.namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(4) | trim }}
spec:
podSelector:
matchLabels:
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
app.kubernetes.io/component: '{{ deployment_type }}'
policyTypes:
- Ingress
- Egress

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should be policyTypes: [Ingress, Egress] with no ingress: rules. Declaring only Egress leaves ingress governance entirely to the catch-all default-deny NP. If the default-deny is ever absent — maintenance window, namespace migration, disaster recovery — this pod would have no ingress protection at all. Each NP should be self-contained in what it governs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added Ingress

egress:
# Allow DNS resolution via OpenShift DNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: TCP
port: 5353
- protocol: UDP
port: 5353
# Allow egress to managed PostgreSQL for pg_dump / pg_restore
{% if managed_database | bool %}
- to:
- podSelector:
matchLabels:
app.kubernetes.io/component: database
app.kubernetes.io/instance: 'postgres-{{ supported_pg_version }}-{{ ansible_operator_meta.name }}'
ports:
- protocol: TCP
port: {{ eda_postgres_port | default('5432') }}
{% else %}
# External database — destination is user-configured, allow on the port
- ports:
- protocol: TCP
port: {{ eda_postgres_port | default('5432') }}
{% endif %}
18 changes: 18 additions & 0 deletions roles/eda/templates/default-deny.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: '{{ ansible_operator_meta.name }}-default-deny'
namespace: '{{ ansible_operator_meta.namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(4) | trim }}
spec:
podSelector:
matchExpressions:
- key: app.kubernetes.io/managed-by
operator: In
values:
- '{{ deployment_type }}-operator'
policyTypes:
- Ingress
- Egress
33 changes: 33 additions & 0 deletions roles/eda/templates/eda-activation-worker.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: '{{ ansible_operator_meta.name }}-activation-worker'
namespace: '{{ ansible_operator_meta.namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(4) | trim }}
app.kubernetes.io/component: '{{ deployment_type }}-activation-worker'
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: '{{ ansible_operator_meta.name }}'
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
app.kubernetes.io/component: '{{ deployment_type }}-activation-worker'
policyTypes:
- Egress
egress:
# Allow DNS resolution via OpenShift DNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: TCP
port: 5353
- protocol: UDP
port: 5353
# Unrestricted egress required: activation workers create and manage Job
# pods via the Kubernetes API, connect to user-defined event source
# destinations, and may call external SMS. Destinations cannot be
# enumerated at policy creation time.
- {}
77 changes: 77 additions & 0 deletions roles/eda/templates/eda-api.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: '{{ ansible_operator_meta.name }}-api'
namespace: '{{ ansible_operator_meta.namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(4) | trim }}
app.kubernetes.io/component: '{{ deployment_type }}-api'
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: '{{ ansible_operator_meta.name }}'
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
app.kubernetes.io/component: '{{ deployment_type }}-api'
policyTypes:
- Ingress
- Egress
ingress:
# Allow traffic from the OpenShift router (Routes) and ingress controllers
- from:
- namespaceSelector:
matchLabels:
policy-group.network.openshift.io/ingress: ""
- namespaceSelector:
matchLabels:
network.openshift.io/policy-group: ingress
ports:
- protocol: TCP
port: {{ api_nginx_port }}
# Allow traffic from the gateway operator (reverse proxy) and other AAP
# component pods that call the EDA API
- from:
- podSelector:
matchExpressions:
- key: app.kubernetes.io/managed-by
operator: In
values:
- '{{ deployment_type }}-operator'
- 'aap-operator'
- podSelector:
matchLabels:
control-plane: controller-manager
ports:
- protocol: TCP
port: {{ api_nginx_port }}
- protocol: TCP
port: {{ websocket_port }}
# Allow traffic from activation Job pods (created at runtime by activation
# workers, not operator-managed — carry only app: eda).
# ansible_rulebook connects to daphne (websocket_port) for rulebook
# execution and to the API (api_nginx_port) for token refresh.
- from:
- podSelector:
matchLabels:
app: eda
ports:
- protocol: TCP
port: {{ websocket_port }}
- protocol: TCP
port: {{ api_nginx_port }}
egress:
# Allow DNS resolution via OpenShift DNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: TCP
port: 5353
- protocol: UDP
port: 5353
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Unrestricted egress required for user-configured external services
# (external SMS such as HashiCorp Vault, fetched by daphne during websocket
# handshake; gateway JWT key fetch; postgres). Destinations are
# user-defined and cannot be enumerated at policy creation time.
- {}
33 changes: 33 additions & 0 deletions roles/eda/templates/eda-default-worker.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: '{{ ansible_operator_meta.name }}-default-worker'
namespace: '{{ ansible_operator_meta.namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(4) | trim }}
app.kubernetes.io/component: '{{ deployment_type }}-default-worker'
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: '{{ ansible_operator_meta.name }}'
app.kubernetes.io/managed-by: '{{ deployment_type }}-operator'
app.kubernetes.io/component: '{{ deployment_type }}-default-worker'
policyTypes:
- Egress
egress:
# Allow DNS resolution via OpenShift DNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: TCP
port: 5353
- protocol: UDP
port: 5353
# Unrestricted egress required: default-worker executes user-defined tasks
# (git clones, SCM syncs, webhook calls) and may call external SMS.
# Destinations are user-configured and cannot be enumerated at policy
# creation time.
- {}
Loading
Loading