Restricting Traffic in Appian on Kubernetes

Overview

In Kubernetes, network policies allow restricting traffic flow at the IP address or port level. By default, pods are non-isolated; they accept traffic from any source. The Appian operator supports conditionally restricting inbound traffic to site pods on a site-by-site basis via NetworkPolicy resources. This page details how to configure Appian custom resources to restrict traffic to/from Appian sites. It is aimed at self-managed customers running Appian on Kubernetes.

Enforcement of network policies is implemented by network plugins. To use network policies, you must use a network plugin that supports NetworkPolicy resources such as Calico. Creating a NetworkPolicy resource without a controller that implements it will have no effect.

Restricting inbound traffic

To restrict inbound traffic to a given site's pods, set the .spec.networkPolicies.enabled field to true on the site's Appian custom resource:

1
2
3
4
5
6
7
apiVersion: crd.k8s.appian.com/v1alpha1
kind: Appian
metadata:
  name: appian-k8s-traffic
spec:
  networkPolicies:
    enabled: true

This will instruct the operator to create a variety of NetworkPolicy resources that target the site's pods.

  • First it will create a default, deny-all ingress traffic NetworkPolicy that targets all of the site's pods.
  • Then it creates a NetworkPolicy for each component that allows ingress traffic from other components or from other replicas of the same component to specific ports.

This is done only as needed to restrict inbound traffic as much as possible. The exact specification of each component-specific NetworkPolicy depends on the topology of the site.

Adding network policy ingress rules

Let's say that you've followed the section above to restrict inbound traffic to Appian for security purposes, but also need to allow traffic from specific non-Appian pods or IP blocks.

This situation is common when exposing Appian outside of Kubernetes, so we'll use it as an example. In this case, traffic needs to be allowed to Appian's Webapp pods or its Apache Web Server (httpd) pods (if enabled) from either the cluster's nodes or the in-cluster Ingress controller, depending on whether NodePort or LoadBalancer Services or Ingress is being used.

The Appian operator and Appian custom resource definition support adding network policy ingress rules to the component-specific NetworkPolicy resources described above on a site-by-site basis via the .spec.<COMPONENT>.additionalNetworkPolicyIngressRules fields on Appian custom resources. If httpd is disabled (the default), ingress traffic routes directly to Webapp, so the .spec.webapp.additionalNetworkPolicyIngressRules field should be used. Otherwise, ingress traffic routes to httpd, so the .spec.httpd.additionalNetworkPolicyIngressRules field should be used.

Each field accepts a list of networkingv1.NetworkPolicyIngressRule objects. The specification of each object's from field depends on how Appian is exposed outside of Kubernetes. The specification of each object's ports fields depends on whether or not httpd is enabled and, if disabled, how .spec.service.protocol is set. The subsections below explain the various scenarios in more detail.

Setting the from field

The specification of each object's from field depends on whether NodePort or LoadBalancer Services or Ingress is used to expose Appian outside of Kubernetes.

NodePort and LoadBalancer Services

In Kubernetes, packets sent to NodePort and LoadBalancer Services are source NAT'd by default. This means that from network plugins' perspective, traffic to pods fronted by NodePort and LoadBalancer Services originates from the cluster's nodes.

When running Appian with network policies enabled and .spec.service.type set to either NodePort or LoadBalancer, you'll need to allow traffic to Appian's Webapp pods or its Apache Web Server (httpd) pods (if enabled) from your cluster's nodes. In this case, you'd set each list item's from field in .spec.webapp.additionalNetworkPolicyIngressRules or .spec.httpd.additionalNetworkPolicyIngressRules to the following where <CIDR> is the IP block of your cluster's nodes (for example, 192.168.1.1/24):

1
2
- ipBlock:
    cidr: <CIDR>

Ingress

When running Appian with network policies enabled and exposing Appian via Ingress, you'll need to allow traffic to Appian's Webapp pods or its Apache Web Server (httpd) pods (if enabled) from the in-cluster Ingress controller.

To do so, you'll need to determine how to select the Ingress controller's pods using label selectors for their labels and, optionally, those of their namespace. If the namespaces in your cluster don't have labels, that's okay; you can select pods by labels across all namespaces instead. Imagine that you run NGINX Ingress in the nginx-ingress namespace and the Deployment for the controller is called nginx-ingress-controller. To find the labels for the controller's pods, you'd run the following:

1
2
3
4
5
$ kubectl -n nginx-ingress get deployment nginx-ingress-controller -ojsonpath={.spec.template.metadata.labels}
{
  "app": "nginx-ingress",
  "component":"controller"
}

Here, the controller's pods have the labels app=nginx-ingress and component=controller. To find the labels for the namespace, run the following:

1
2
3
4
$ kubectl get ns nginx-ingress -ojsonpath={.metadata.labels}
{
  "name":"nginx-ingress"
}

Here, the namespace has the label name=nginx-ingress. If the command above doesn't return anything, that's okay; you can select pods by labels across all namespaces instead.

In this case, you'd set each list item's from field in .spec.webapp.additionalNetworkPolicyIngressRules or .spec.httpd.additionalNetworkPolicyIngressRules to the following:

1
2
3
4
5
6
7
8
- podSelector:
    matchLabels:
      app: nginx-ingress
      component: controller
  # Remove if the Ingress controller's namespace isn't labeled
  namespaceSelector:
    matchLabels:
      name: nginx-ingress

Setting the ports field

If Apache Web Server (httpd) is disabled (the default), ingress traffic targets Appian's Webapp pods on one of two ports depending on whether or not .spec.service.protocol is set to http (the default) or ajp. If set to http, traffic targets Webapp's http port (port 8080). In this case, one would set each list item's ports field in .spec.webapp.additionalNetworkPolicyIngressRules to the following:

1
- port: http # Can also be set to 8080

If set to ajp, ingress traffic targets Webapp's ajp port 8009. In this case, one would set each list item's ports field in .spec.webapp.additionalNetworkPolicyIngressRules to the following:

1
- port: ajp # Can also be set to 8009

If httpd is enabled, ingress traffic targets Appian's httpd pods on their http port 8080. In this case, one would set each list item's ports field in .spec.httpd.additionalNetworkPolicyIngressRules to the following:

1
- port: http # Can also be set to 8080

Full example

In order to allow traffic to a site exposed via NGINX Ingress as configured above with network policies enabled, Apache Web Server (httpd) disabled, and .spec.service.protocol set to http, its custom resource should look like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
apiVersion: crd.k8s.appian.com/v1alpha1
kind: Appian
metadata:
  name: appian-k8s-traffic
spec:

  networkPolicies:
    enabled: true

  service:
    protocol: http

  webapp:
    additionalNetworkPolicyIngressRules:
    - from:
      - podSelector:
          matchLabels:
            app: nginx-ingress
            component: controller
        # Set to {} if the ingress controller's namespace isn't labeled
        namespaceSelector:
          matchLabels:
            name: nginx-ingress
        # If the site is exposed via a NodePort or LoadBalancer Service instead of 
        # Ingress, use the following instead of podSelector / namespaceSelector 
        # ipBlock:
        #   cidr: <CIDR>
      ports:
      # Switch to ajp if .spec.service.protocol is set to ajp
      - port: http
Open in Github Built: Tue, Mar 28, 2023 (09:28:18 PM)

On This Page

FEEDBACK