Access Policy

Access policies is only enabled in our in-cloud clusters.

If you are running your app in a cluster with access policies enabled you can define the access rules for your application. If you define none, the default policy will deny all incoming and outgoing traffic for your application.

This means that you have to know what other services your app is consuming and consumed by.

Inbound rules

Inbound rules specifies what other applications in the same cluster your application receives traffic from.

Receive requests from other app in the same namespace

For app app-a to be able to receive incoming requests from app-b in the same cluster and the same namespace, this specification is needed for app-a:

apiVersion: "nais.io/v1alpha1"
kind: "Application"
metadata:
name: app-a
...
spec:
...
accessPolicy:
inbound:
rules:
application: app-b

Receive requests from other app in the another namespace

For app app-a to be able to receive incoming requests from app-b in the same cluster but another namespace (othernamespace), this specification is needed for app-a:

apiVersion: "nais.io/v1alpha1"
kind: "Application"
metadata:
name: app-a
...
spec:
...
accessPolicy:
inbound:
rules:
application: app-b
namespace: othernamespace

Outbound rules

Inbound rules specifies what other applications your application receives traffic from. spec.accessPolicy.outbound.rules specifies which applications in the same cluster to open for. To open for external applications, use the field spec.accessPolicy.outbound.external.

Send requests to other app in the same namespace

For app app-a to be able to send requests to app-b in the same cluster and the same namespace, this specification is needed for app-a:

apiVersion: "nais.io/v1alpha1"
kind: "Application"
metadata:
name: app-a
...
spec:
...
accessPolicy:
outbound:
rules:
application: app-b

Send requests to other app in the another namespace

For app app-a to be able to send requests requests to app-b in the same cluster but in another namespace (othernamespace), this specification is needed for app-a:

apiVersion: "nais.io/v1alpha1"
kind: "Application"
metadata:
name: app-a
...
spec:
...
accessPolicy:
outbound:
rules:
application: app-b
namespace: othernamespace

External services

In order to send requests to services outside of the cluster, external.host is needed:

apiVersion: "nais.io/v1alpha1"
kind: "Application"
metadata:
name: app-a
...
spec:
...
accessPolicy:
outbound:
external:
- host: www.external-application.com

Advanced: Resources created by Naiserator

The previous application manifest examples will create both Kubernetes Network Policies and Istio resources.

Prerequisites

These requirements must be met for access policies to be working as expected:

  • The cluster must have Istio installed

  • The cluster must have network policies enabled

  • Naiserator must run with the flag --access-policies=true

Kubernetes Network Policy

Default policy

Every app created will have this default network policy that allows traffic from Istio pilot and mixer, as well as kube-dns. This policy will be created for every app, also those who don't have any access policies specified.

apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
labels:
app: appname
team: teamname
name: appname
namespace: teamname
spec:
egress:
- to:
- namespaceSelector:
matchLabels:
name: istio-system
podSelector:
matchLabels:
istio: pilot
- namespaceSelector:
matchLabels:
name: istio-system
podSelector:
matchLabels:
istio: mixer
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
podSelector:
matchLabels:
app: appname
policyTypes:
- Egress

Kubernetes network policies

The applications specified in spec.accessPolicy.inbound.rules and spec.accessPolicy.outbound.rules will append these fields to the default Network Policy:

apiVersion: extensions/v1beta1
kind: NetworkPolicy
...
spec:
egress:
- to:
...
- namespaceSelector:
matchLabels:
name: othernamespace
podSelector:
matchLabels:
app: app-b
- podSelector:
matchLabels:
app: app-b
- from:
- namespaceSelector:
matchLabels:
name: othernamespace
podSelector:
matchLabels:
app: app-b
- podSelector:
matchLabels:
app: app-b
podSelector:
matchLabels:
app: appname
policyTypes:
- Egress
- Ingress

Note that for namespace match labels to work, the namespaces must be labeled with name: namespacename.

kube-system should be labeled accordingly for the default rule that allows traffic to kube-dns, but in GCP, the label is removed by some job in regular intervals...

Istio Resources

The policies from spec.accessPolicy will in addition create these Istio-resources:

ServiceRole and ServiceRoleBinding

For Istio to allow request from app-b in the same namespace and in othernamespace, these resources will be created:

apiVersion: rbac.istio.io/v1alpha1
kind: ServiceRole
metadata:
labels:
app: app-a
team: my-team
name: app-a
namespace: my-team
spec:
rules:
- methods:
- '*'
paths:
- '*'
services:
- app-a.my-team.svc.cluster.local
apiVersion: rbac.istio.io/v1alpha1
kind: ServiceRoleBinding
metadata:
labels:
app: app-a
team: my-team
name: app-a
namespace: my-team
spec:
roleRef:
kind: ServiceRole
name: app-a
subjects:
- user: cluster.local/ns/my-team/sa/app-b
- user: cluster.local/ns/othernamespace/sa/app-b

ServiceEntry

spec.accessRules.outbound.external will create ServiceEntry:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
labels:
app: app-a
team: my-team
name: app-a
namespace: my-team
spec:
hosts:
- www.external-application.com
location: MESH_EXTERNAL
ports:
- name: https
number: 443
protocol: HTTPS
resolution: DNS

VirtualService

In the cloud spec.ingresses will create VirtualService instead of Ingress objects:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
labels:
app: app-a
team: my-team
name: app-a-app-a-dev-gcp-nais-io
namespace: my-team
spec:
gateways:
- istio-system/ingress-gateway-nais-io
hosts:
- my-app.dev-gcp.nais.io
http:
- route:
- destination:
host: app-a
port:
number: 80
subset: ""
weight: 100