<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Network on TechBlog about OpenShift/Ansible/Satellite and much more</title><link>https://blog.stderr.at/categories/network/</link><description>TechBlog about OpenShift/Ansible/Satellite and much more</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Toni Schmidbauer &amp; Thomas Jungbauer</copyright><lastBuildDate>Wed, 06 Nov 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.stderr.at/categories/network/index.xml" rel="self" type="application/rss+xml"/><item><title>Introducing AdminNetworkPolicies</title><link>https://blog.stderr.at/openshift-platform/security/network-policies/2024-11-06-using-adminnetworkpolicies-and-baselineadminnetworkpolicies/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/security/network-policies/2024-11-06-using-adminnetworkpolicies-and-baselineadminnetworkpolicies/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Classic Kubernetes/OpenShift offer a feature called NetworkPolicy that allows users to control the traffic to and from their assigned Namespace.
NetworkPolicies are designed to give project owners or tenants the ability to protect their own namespace. Sometimes, however, I worked with customers where the
cluster administrators or a dedicated (network) team need to enforce these policies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Since the NetworkPolicy API is namespace-scoped, it is not possible to enforce policies across namespaces. The only solution was to create custom (project) admin and edit
roles, and remove the ability of creating, modifying or deleting NetworkPolicy objects. Technically, this is possible and easily done. But shifts the whole network security to cluster administrators.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Luckily, this is where &lt;strong&gt;AdminNetworkPolicy&lt;/strong&gt; (ANP) and &lt;strong&gt;BaselineAdminNetworkPolicy&lt;/strong&gt; (BANP) comes into play.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_adminnetworkpolicy_anp_and_baselineadminnetworkpolicy_banp"&gt;AdminNetworkPolicy (ANP) and BaselineAdminNetworkPolicy (BANP)&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
This article demonstrates the configuration of the new AdminNetworkPolicy and BaselineAdminNetworkPolicy objects using the Helm Chart &lt;a href="https://github.com/tjungbauer/helm-charts/tree/main/charts/admin-networkpolicies" target="_blank" rel="noopener"&gt;admin-networkpolicies&lt;/a&gt;. The NetworkPolicy object is not covered in this article.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;ANP and BANP are designed for cluster administrators to protect the entire cluster by creating &lt;strong&gt;cluster-scoped policies&lt;/strong&gt;. They are not replacing NetworkPolicies,
but instead create a tier model and can be used together. Administrators can use ANPs to enforce non-overridable policies that take precedence over NetworkPolicy objects.
Administrators can use BANP to set up and enforce optional cluster-scoped network policy rules that are overridable by users using NetworkPolicy objects when necessary.
When used together, ANP, BANP, and network policy can achieve full multi-tenant isolation that administrators can use to secure their cluster.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The three resources create a 3-Tier Access Control List (ACL) that is evaluated in descending order:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Tier 1 - AdminNetworkPolicy (ANP): If the traffic matches an &lt;strong&gt;allow&lt;/strong&gt; or &lt;strong&gt;deny&lt;/strong&gt; rule, then any existing
NetworkPolicy and BaselineAdminNetworkPolicy (BANP) objects in the cluster are skipped from evaluation. If a &lt;strong&gt;pass&lt;/strong&gt; rule is matched, then the evaluation is handed over to
the next tier (NetworkPolicy). This means, that Cluster Administrators can enforce policies that cannot be overwritten by users (allow/deny rules) or pass the evaluation to the Network Policy,
where the project owners can decide further.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tier 2 - NetworkPolicy (NP): If the traffic passed the ANP then the NetworkPolicy is evaluating the traffic. The NetworkPolicy resources are controlled by the project owners by default.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tier 3 - BaselineAdminNetworkPolicy (BANP): If the traffic passed the ANP and the NetworkPolicy, then the BANP is evaluating the traffic.
These objects are controlled by the cluster administrators again and are cluster scoped. There can only be one BANP (named &amp;#34;default&amp;#34;) configured on the cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_adminnetworkpolicy"&gt;AdminNetworkPolicy&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;An AdminNetworkPolicy (ANP) is a cluster-scoped resource, that allow cluster administrators to secure the network traffic &lt;strong&gt;before&lt;/strong&gt; NetworkPolicies in the namespaces are evaluated.
These rules cannot be overwritten by project owners or developers and allow the administrators to enforce the security. Use cases could be, for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You want to enforce only specific egress endpoints (e.g. only allow traffic to the specific database servers)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You want to be sure that traffic from OpenShift monitoring is always allowed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You want to allow the management of NetworkPolicies to project owners and do not want to take care for them or during the onboarding.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The ANP allows cluster administrators to define:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A priority value that determines the order of its evaluation. The lower the value the higher the precedence.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A set of pods that consists of a set of namespaces or namespace on which the policy is applied.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A list of ingress rules to be applied for all ingress traffic towards the subject.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A list of egress rules to be applied for all egress traffic from the subject.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_adminnetworkpolicy_actions_for_rules"&gt;AdminNetworkPolicy Actions for Rules&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The AdminNetworkPolicy allows three actions for the rules:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Allow&lt;/strong&gt;: The traffic is allowed, and no further rules are evaluated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deny&lt;/strong&gt;: The traffic is denied, and no further rules are evaluated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pass&lt;/strong&gt;: The traffic is passed to the next tier (NetworkPolicy).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_subject_of_a_policy"&gt;Subject of a Policy&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In any ANP (or BANP) a &lt;strong&gt;subject&lt;/strong&gt; can be defined and they specify the pods to which this AdminNetworkPolicy applies. (Note that host-networked pods are not included in subject.selection.) There are two ways to define the subject:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;namespaces&lt;/strong&gt;: The namespaces block is used to select pods via namespace selectors. Here, &lt;strong&gt;matchLabels&lt;/strong&gt; or &lt;strong&gt;matchExpressions&lt;/strong&gt; can be used to limit the namespaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;pods&lt;/strong&gt;: The Pods-Array is used to select pods via namespace AND pod selectors. Here &lt;strong&gt;namespaceSelector&lt;/strong&gt; and &lt;strong&gt;podSelector&lt;/strong&gt; can be set to limit the Pods.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If &lt;strong&gt;subject&lt;/strong&gt; is not defined, the policy applies to all pods and namespaces in the cluster.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In my Helm chart the options are supported like the following snippets show:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_select_namespaces_with_matchexpressions"&gt;Select Namespaces with matchExpressions&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Values in the Helm Chart:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;anp:
- name: sample-anp-rule-1
enabled: true
priority: 50
subject:
matchNamespaces: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
matchExpressions: &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
- key: kubernetes.io/metadata.name
operator: NotIn
values:
- kube-system
- openshift*
- default
- kubde-info&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;matchNamespaces is used to select namespaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;matchExpressions is used to select namespaces with &lt;strong&gt;matchExpressions&lt;/strong&gt;. In this example all namespaces that do not match (operator == NotIn) the values, so all namespaces except &amp;#34;kube-system, kube-info, default and openshift*&amp;#34; are selected.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will result in the following AdminNetworkPolicy snippet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; subject:
namespaces:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values:
- &amp;#34;kube-system&amp;#34;
- &amp;#34;openshift*&amp;#34;
- &amp;#34;default&amp;#34;
- &amp;#34;kubde-info&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_select_namespaces_with_matchlabels"&gt;Select Namespaces with matchLabels&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Values in the Helm Chart:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;anp:
- name: sample-anp-rule-1
enabled: true
priority: 5
subject:
matchNamespaces: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
matchLabels: &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
apps: my-apps
tenant: my-tenant&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;matchNamespaces is used to select namespaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;matchLabels&lt;/strong&gt; is used to select namespaces based on labels. In this example, all namespaces that have the labels &amp;#34;apps: my-apps&amp;#34; and &amp;#34;tenant: my-tenant&amp;#34; are selected.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will result in the following AdminNetworkPolicy snippet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;spec:
priority: 5
subject:
namespaces:
matchLabels:
apps: &amp;#34;my-apps&amp;#34;
tenant: &amp;#34;my-tenant&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_select_pods_with_podselectors_and_namespaceselectors"&gt;Select Pods with podSelectors and namespaceSelectors&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Values in the Helm Chart:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;anp:
- name: sample-anp-rule-1
enabled: true
priority: 5
subject:
matchPods:
- pods: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
namespaceSelector: &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
labels:
kubernetes.io/metadata.name: openshift-dns
podSelector: &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
labels:
app: dns&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;matchPods is used to select pods. Here a list of pods can be defined.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;namespaceSelector&lt;/strong&gt; is used to select namespaces based on labels. In this example all namespaces that have the label &amp;#34;kubernetes.io/metadata.name: openshift-dns&amp;#34; are selected.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;podSelector&lt;/strong&gt; is used to select pods based on labels. In this example all pods that have the label &amp;#34;app: dns&amp;#34; are selected.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will result in the following AdminNetworkPolicy snippet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; subject:
- pods:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
podSelector:
matchLabels:
app: dns&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_baselineadminnetworkpolicy"&gt;BaselineAdminNetworkPolicy&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;BaselineAdminNetworkPolicy (BANP) is a cluster-scoped resource, that allow cluster administrators to secure the network traffic &lt;strong&gt;after&lt;/strong&gt; NetworkPolicies in the namespaces have been evaluated. These rules can be overwritten by project owners or developers using NetworkPolicies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock caution"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-caution" title="Caution"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
BANP is a singleton resource, meaning it can be defined only one time. Therefore, its name must be &lt;strong&gt;default&lt;/strong&gt;. Moreover, the &lt;strong&gt;priority&lt;/strong&gt; field is not required here.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Use cases could be, for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Creating default rules, such as blocking any intra-cluster traffic by default. Users will need to explicitly use NetworkPolicy objects to allow known traffic.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;A BANP allows administrators to specify:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A subject that consists of a set of namespaces or namespace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A list of ingress rules to be applied for all ingress traffic towards the subject.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A list of egress rules to be applied for all egress traffic from the subject.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_baselineadminnetworkpolicy_actions_for_rules"&gt;BaselineAdminNetworkPolicy Actions for Rules&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The BaselineAdminNetworkPolicy allows two actions for the rules. They are like the AdminNetworkPolicy, except for the &lt;strong&gt;pass&lt;/strong&gt; action, which does not make sense here as BANP is the last tier (nowhere to pass).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Allow&lt;/strong&gt;: The traffic is allowed, and no further rules are evaluated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deny&lt;/strong&gt;: The traffic is denied, and no further rules are evaluated.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_examples_examples_examples"&gt;Examples Examples Examples&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The following examples are taken directly from &lt;a href="https://network-policy-api.sigs.k8s.io/blog/2024/01/30/getting-started-with-the-adminnetworkpolicy-api/" target="_blank" rel="noopener"&gt;Kubernetes Blog: Getting started with the AdminNetworkPolicy API&lt;/a&gt; and &lt;a href="https://docs.openshift.com/container-platform/4.16/networking/network_security/network-policy-apis.html" target="_blank" rel="noopener"&gt;Official OpenShift Documentation&lt;/a&gt;. Verify the values-file of the &lt;a href="https://github.com/tjungbauer/helm-charts/tree/main/charts/admin-networkpolicies" target="_blank" rel="noopener"&gt;Helm Chart&lt;/a&gt; for the further examples.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock warning"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-warning" title="Warning"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
I will show, how to configure them using the Helm Chart &lt;a href="https://github.com/tjungbauer/helm-charts/tree/main/charts/admin-networkpolicies" target="_blank" rel="noopener"&gt;admin-networkpolicies&lt;/a&gt; and the actual result. The chart is already configured with these examples and prepared to be used with GitOps/Argo CD.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_example_1_allow_all_traffic_from_the_openshift_monitoring_namespace"&gt;Example 1: Allow all traffic from the OpenShift monitoring namespace&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Typically, it makes sense to allow the traffic from OpenShift Monitoring to all namespaces. After all, monitoring is useful :)
The following example shows the possible configuration for the Helm Chart, which will render a valid ANP resource for us. It will allow ALL (including OpenShift internal Namespaces) traffic from the OpenShift monitoring namespace (labeled as &lt;code&gt;kubernetes.io/metadata.name: monitoring&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
anp:
- name: sample-anp-rule-1 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
enabled: true &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
syncwave: 10
priority: 5 &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
subject: {} &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
ingress: &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
- name: allow-ingress-from-monitoring &lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
enabled: true &lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;(7)&lt;/b&gt;
action: Allow &lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;(8)&lt;/b&gt;
peers: &lt;i class="conum" data-value="9"&gt;&lt;/i&gt;&lt;b&gt;(9)&lt;/b&gt;
- type: namespaces
labels:
kubernetes.io/metadata.name: monitoring&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the ANP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Enable or disable the ANP. If disabled, the ANP will not be created. (Default is &lt;code&gt;false&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Priority of the ANP. The lower the value the higher the precedence. (Default is &lt;code&gt;50&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Subject of the ANP. In this case, it is empty, which means all namespaces including OpenShift internal namespaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Ingress rules of the ANP. Here a list of ingress rules for this ANP can be defined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name of the ingress rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="7"&gt;&lt;/i&gt;&lt;b&gt;7&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Enable or disable the ingress rule. If disabled, the particular ingress rule will not be created. (Default is &lt;code&gt;false&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="8"&gt;&lt;/i&gt;&lt;b&gt;8&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Action of the ingress rule. In this case, it is &lt;code&gt;Allow&lt;/code&gt;, which means all traffic from the OpenShift monitoring namespace will be allowed. Other options are described at &lt;a href="#_adminnetworkpolicy_actions_for_rules"&gt;AdminNetworkPolicy Actions for Rules&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="9"&gt;&lt;/i&gt;&lt;b&gt;9&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Peers of the ingress rule. In this case, all namespaces labeled as &lt;code&gt;kubernetes.io/metadata.name: monitoring&lt;/code&gt; are allowed to access all namespaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The ANP that will be created is the following. It is a valid ANP resource and can be applied to the cluster. (Typically applied by Argo CD)
As described above it will allow incoming access from the OpenShift monitoring namespace to all namespaces.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: &amp;#34;sample-anp-rule-1&amp;#34;
labels:
helm.sh/chart: admin-networkpolicies-1.0.2
app.kubernetes.io/name: admin-networkpolicies
app.kubernetes.io/instance: release-name
app.kubernetes.io/managed-by: Helm
annotations:
argocd.argoproj.io/sync-wave: &amp;#34;10&amp;#34;
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
priority: 5
subject:
namespaces: {}
ingress:
- name: &amp;#34;allow-ingress-from-monitoring&amp;#34;
action: &amp;#34;Allow&amp;#34;
from:
- namespaces:
matchLabels:
kubernetes.io/metadata.name: &amp;#34;monitoring&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_example_2_allow_all_traffic_from_labeled_namespaces"&gt;Example 2: Allow all traffic from labeled namespaces&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As a second example, we want to allow all traffic from namespaces that are labeled with &lt;code&gt;tenant: restricted&lt;/code&gt; to all namespaces that are labeled with &lt;code&gt;anp: cluster-control-anp&lt;/code&gt;.
This is useful, if you want to restrict access to certain namespaces. However, the rule action is configured as &lt;strong&gt;Pass&lt;/strong&gt; which means that the traffic will be allowed but might be further restricted by a NetworkPolicy in the tenant namespace.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
anp:
- name: sample-anp-rule-2
enabled: true
priority: 5
subject:
matchNamespaces: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
matchLabels:
anp: cluster-control-anp &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
ingress:
- name: pass-from-restricted-tenants
enabled: true
action: Pass &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
peers:
- type: namespaces &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
labels:
tenant: restricted&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Subject of the ANP. In this case, we select based on labels.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Label selector for the namespaces. In this case, all namespaces that are labeled with &lt;code&gt;anp: cluster-control-anp&lt;/code&gt; are subject of this ANP.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Action of the ingress rule. In this case, it is &lt;code&gt;Pass&lt;/code&gt;, which means the traffic is allowed, but might be restricted by NetworkPolicies in the tenant namespace. Other options are described at &lt;a href="#_adminnetworkpolicy_actions_for_rules"&gt;AdminNetworkPolicy Actions for Rules&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Peers of the ingress rule. In this case, all namespaces labeled as &lt;code&gt;tenant: restricted&lt;/code&gt; are allowed to access all namespaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: &amp;#34;sample-anp-rule-2&amp;#34;
labels:
helm.sh/chart: admin-networkpolicies-1.0.2
app.kubernetes.io/name: admin-networkpolicies
app.kubernetes.io/instance: release-name
app.kubernetes.io/managed-by: Helm
annotations:
argocd.argoproj.io/sync-wave: &amp;#34;10&amp;#34;
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
priority: 5
subject:
namespaces:
matchLabels:
anp: &amp;#34;cluster-control-anp&amp;#34;
ingress:
- name: &amp;#34;pass-from-restricted-tenants&amp;#34;
action: &amp;#34;Pass&amp;#34;
from:
- namespaces:
matchLabels:
tenant: &amp;#34;restricted&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_example_3_show_possible_peers_settings"&gt;Example 3: Show possible peers settings&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The most important settings for the rules are the &lt;code&gt;peers&lt;/code&gt; settings. The following examples show the snippets of possible peers.
For further information, please refer to the example in the values file: &lt;a href="https://github.com/tjungbauer/helm-charts/blob/main/charts/admin-networkpolicies/values.yaml" target="_blank" rel="noopener"&gt;Helm Chart Values with further examples&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
The following rules are examples of &lt;strong&gt;EGRESS&lt;/strong&gt; rules.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Allow egress traffic &lt;strong&gt;to namespaces labeled&lt;/strong&gt; splunk on ports 80 and 443:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; peers:
- type: namespaces
labels:
tenant: splunk
ports:
- protocol: TCP
portNumber: 80
- portName: https&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic" start="2"&gt;
&lt;li&gt;
&lt;p&gt;Allow egress traffic &lt;strong&gt;to nodes&lt;/strong&gt; where the key &amp;#34;node-role.kubernetes.io/control-plane&amp;#34; exists &lt;strong&gt;on the port 6443&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; peers:
- type: nodes
expr:
- key: node-role.kubernetes.io/control-plane
operator: Exists
ports:
- protocol: TCP
portNumber: 6443&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic" start="3"&gt;
&lt;li&gt;
&lt;p&gt;Allow egress traffic &lt;strong&gt;to pods&lt;/strong&gt; labeled &amp;#34;app: dns&amp;#34; &lt;strong&gt;in the namespace&lt;/strong&gt; openshift-dns &lt;strong&gt;on the port 53 and 5353&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; peers:
- type: pods
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
podSelector:
matchLabels:
app: dns
ports:
- protocol: TCP
port: 5353
- protocol: TCP
port: 53
- protocol: UDP
port: 53
- protocol: UDP
port: 5353&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic" start="4"&gt;
&lt;li&gt;
&lt;p&gt;Allow egress traffic &lt;strong&gt;to a list of IPs&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; peers:
- type: networks
ips:
- 172.29.0.0/30
- 10.0.54.0/19
- 10.0.56.38/32
- 10.0.69.0/24&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic" start="5"&gt;
&lt;li&gt;
&lt;p&gt;Allows egress traffic &lt;strong&gt;to a list of domain names&lt;/strong&gt; (*.kubernetes.io and kubernetes.io)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; peers:
- type: domainNames
domains:
- &amp;#39;*.kubernetes.io&amp;#39;
- kubernetes.io&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic" start="6"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deny all egress traffic&lt;/strong&gt;. This should be the last rule when full egress traffic shall be disabled. This might also be put into the BANP.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt; - name: default-deny
enabled: true
action: Deny
peers:
- type: networks
ips:
- 0.0.0.0/0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_example_4_baselineadminnetworkpolicy"&gt;Example 4: BaselineAdminNetworkPolicy&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The BANP is more or less identical to ANP, except that you cannot define a &amp;#34;name&amp;#34; and a &amp;#34;priority&amp;#34;. The following example creates a BANP that allows incoming and outgoing traffic to namespaces labeled &amp;#34;tenant-1&amp;#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;banp: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
- enabled: true &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
syncwave: 10
subject:
matchNamespaces:
matchLabels:
kubernetes.io/metadata.name: example.name
ingress:
- name: &amp;#34;deny-all-ingress-from-tenant-1&amp;#34;
enabled: true
action: Deny
peers:
- type: pods
namespaceSelector:
matchLabels:
custom-banp: tenant-1
podSelector:
matchLabels:
custom-banp: tenant-1
egress:
- name: allow-all-egress-to-tenant-1
enabled: true
action: Allow
peers:
- type: pods
namespaceSelector:
matchLabels:
custom-banp: tenant-1
podSelector:
matchLabels:
custom-banp: tenant-1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Using the key &lt;strong&gt;banp&lt;/strong&gt; (instead of &lt;strong&gt;anp&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;No &lt;strong&gt;name&lt;/strong&gt; or &lt;strong&gt;priority&lt;/strong&gt; are defined here.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_further_information"&gt;Further Information&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/tjungbauer/helm-charts/blob/main/charts/admin-networkpolicies/values.yaml" target="_blank" rel="noopener"&gt;Helm Chart Values with further examples&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://docs.openshift.com/container-platform/4.16/networking/network_security/network-policy-apis.html" target="_blank" rel="noopener"&gt;Official OpenShift Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://network-policy-api.sigs.k8s.io/blog/2024/01/30/getting-started-with-the-adminnetworkpolicy-api/" target="_blank" rel="noopener"&gt;Kubernetes Blog: Getting started with the AdminNetworkPolicy API&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://network-policy-api.sigs.k8s.io/reference/spec/#policy.networking.k8s.io/v1alpha1.AdminNetworkPolicyEgressPeer" target="_blank" rel="noopener"&gt;Kubernetes API Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>