Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add access control policy #1028

Merged
merged 3 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions deployments/common/policy-definition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.k8s.nginx.org
spec:
group: k8s.nginx.org
versions:
- name: v1alpha1
served: true
storage: true
scope: Namespaced
names:
plural: policies
singular: policy
kind: Policy
shortNames:
- pol
preserveUnknownFields: false
validation:
openAPIV3Schema:
description: Policy defines a Policy for VirtualServer and VirtualServerRoute
resources.
type: object
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: 'PolicySpec is the spec of the Policy resource. The spec includes
multiple fields, where each field represents a different policy. Note:
currently we have only one policy -- AccessControl, but we will support
more in the future. Only one policy (field) is allowed.'
type: object
properties:
accessControl:
description: AccessControl defines an access policy based on the source
IP of a request.
type: object
properties:
allow:
type: array
items:
type: string
deny:
type: array
items:
type: string
11 changes: 11 additions & 0 deletions deployments/common/vs-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ spec:
type: string
ingressClassName:
type: string
policies:
type: array
items:
description: PolicyReference references a policy by name and an optional
namespace.
type: object
properties:
name:
type: string
namespace:
type: string
routes:
type: array
items:
Expand Down
60 changes: 60 additions & 0 deletions deployments/helm-chart/crds/policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.k8s.nginx.org
labels:
app.kubernetes.io/name: "nginx-ingress"
annotations:
"helm.sh/hook": crd-install
spec:
group: k8s.nginx.org
versions:
- name: v1alpha1
served: true
storage: true
scope: Namespaced
names:
plural: policies
singular: policy
kind: Policy
shortNames:
- pol
preserveUnknownFields: false
validation:
openAPIV3Schema:
description: Policy defines a Policy for VirtualServer and VirtualServerRoute
resources.
type: object
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: 'PolicySpec is the spec of the Policy resource. The spec includes
multiple fields, where each field represents a different policy. Note:
currently we have only one policy -- AccessControl, but we will support
more in the future. Only one policy (field) is allowed.'
type: object
properties:
accessControl:
description: AccessControl defines an access policy based on the source
IP of a request.
type: object
properties:
allow:
type: array
items:
type: string
deny:
type: array
items:
type: string
11 changes: 11 additions & 0 deletions deployments/helm-chart/crds/virtualserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ spec:
type: string
ingressClassName:
type: string
policies:
type: array
items:
description: PolicyReference references a policy by name and an optional
namespace.
type: object
properties:
name:
type: string
namespace:
type: string
routes:
type: array
items:
Expand Down
1 change: 1 addition & 0 deletions deployments/helm-chart/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ rules:
- virtualservers
- virtualserverroutes
- transportservers
- policies
verbs:
- list
- watch
Expand Down
1 change: 1 addition & 0 deletions deployments/rbac/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ rules:
- virtualserverroutes
- globalconfigurations
- transportservers
- policies
verbs:
- list
- watch
Expand Down
1 change: 1 addition & 0 deletions docs-web/configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ Configuration
global-configuration/index
ingress-resources/index
virtualserver-and-virtualserverroute-resources
policy-resource
transportserver-resource
configuration-examples
181 changes: 181 additions & 0 deletions docs-web/configuration/policy-resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Policy Resource

The Policy resource allows you to configure features like authentication, rate-limiting, and WAF, which you can add to your [VirtualServer resources](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/). In the initial release, we are introducing support for access control based on the client IP address.

The resource is implemented as a [Custom Resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/).

This document is the reference documentation for the Policy resource. An example of a Policy for access control is available in our [GitHub repo](https://github.com/nginxinc/kubernetes-ingress/blob/master/examples-of-custom-resources/access-control).

> **Feature Status**: The Policy resource is available as a preview feature: it is suitable for experimenting and testing; however, it must be used with caution in production environments. Additionally, while the feature is in preview, we might introduce some backward-incompatible changes to the resource specification in the next releases.

## Contents

- [Policy Resource](#policy-resource)
- [Contents](#contents)
- [Prerequisites](#prerequisites)
- [Policy Specification](#policy-specification)
- [AccessControl](#accesscontrol)
- [AccessControl Merging Behavior](#accesscontrol-merging-behavior)
- [Using Policy](#using-policy)
- [Validation](#validation)
- [Structural Validation](#structural-validation)
- [Comprehensive Validation](#comprehensive-validation)

## Prerequisites

Policies work together with [VirtualServer resources](/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/), which you need to create separately.

## Policy Specification

Below is an example of a policy that allows access for clients from the subnet `10.0.0.0/8` and denies access for any other clients:
```yaml
apiVersion: k8s.nginx.org/v1alpha1
kind: Policy
metadata:
name: allow-localhost
spec:
accessControl:
allow:
- 10.0.0.0/8
```

```eval_rst
.. list-table::
:header-rows: 1

* - Field
- Description
- Type
- Required
* - ``accessControl``
- The access control policy based on the client IP address.
- `accessControl <#accesscontrol>`_
- Yes
```

### AccessControl

The access control policy configures NGINX to deny or allow requests from clients with the specified IP addresses/subnets.

For example, the following policy allows access for clients from the subnet `10.0.0.0/8` and denies access for any other clients:
```yaml
accessControl:
allow:
- 10.0.0.0/8
```

In contrast, the policy below does the opposite: denies access for clients from `10.0.0.0/8` and allows access for any other clients:
```yaml
accessControl:
deny:
- 10.0.0.0/8
```

> Note: The feature is implemented using the NGINX [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html). The Ingress Controller access control policy supports either allow or deny rules, but not both (as the module does).

```eval_rst
.. list-table::
:header-rows: 1

* - Field
- Description
- Type
- Required
* - ``allow``
- Allows access for the specified networks or addresses. For example, ``192.168.1.1`` or ``10.1.1.0/16``.
- ``[]string``
- No*
* - ``deny``
- Denies access for the specified networks or addresses. For example, ``192.168.1.1`` or ``10.1.1.0/16``.
- ``[]string``
- No*
```
\* an accessControl must include either `allow` or `deny`.

#### AccessControl Merging Behavior

A VirtualServer can reference multiple access control policies. For example, here we reference two policies, each with configured allow lists:
```yaml
policies:
- name: allow-policy-one
- name: allow-policy-two
```
When you reference more than one access control policy, the Ingress Controller will merge the contents into a single allow list or a single deny list.

Referencing both allow and deny policies, as shown in the example below, is not supported. If both allow and deny lists are referenced, the Ingress Controller uses just the allow list policies.
```yaml
- name: deny-policy
- name: allow-policy-one
- name: allow-policy-two
```

## Using Policy

You can use the usual `kubectl` commands to work with Policy resources, just as with built-in Kubernetes resources.

For example, the following command creates a Policy resource defined in `access-control-policy-allow.yaml` with the name `webapp-policy`:
```
$ kubectl apply -f access-control-policy-allow.yaml
policy.k8s.nginx.org/webapp-policy configured
```

You can get the resource by running:
```
$ kubectl get policy webapp-policy
NAME AGE
webapp-policy 27m
```

For `kubectl get` and similar commands, you can also use the short name `pol` instead of `policy`.

### Validation

Two types of validation are available for the Policy resource:
* *Structural validation*, done by `kubectl` and the Kubernetes API server.
* *Comprehensive validation*, done by the Ingress Controller.

#### Structural Validation

The custom resource definition for the Policy includes a structural OpenAPI schema, which describes the type of every field of the resource.

If you try to create (or update) a resource that violates the structural schema -- for example, the resource uses a string value instead of an array of strings in the `allow` field -- `kubectl` and the Kubernetes API server will reject the resource.
* Example of `kubectl` validation:
```
$ kubectl apply -f access-control-policy-allow.yaml
error: error validating "access-control-policy-allow.yaml": error validating data: ValidationError(Policy.spec.accessControl.allow): invalid type for org.nginx.k8s.v1alpha1.Policy.spec.accessControl.allow: got "string", expected "array"; if you choose to ignore these errors, turn validation off with --validate=false
```
* Example of Kubernetes API server validation:
```
$ kubectl apply -f access-control-policy-allow.yaml --validate=false
The Policy "webapp-policy" is invalid: spec.accessControl.allow: Invalid value: "string": spec.accessControl.allow in body must be of type array: "string"
```

If a resource passes structural validation, then the Ingress Controller's comprehensive validation runs.

#### Comprehensive Validation

The Ingress Controller validates the fields of a Policy resource. If a resource is invalid, the Ingress Controller will reject it. The resource will continue to exist in the cluster, but the Ingress Controller will ignore it.

You can use `kubectl` to check whether or not the Ingress Controller successfully applied a Policy configuration. For our example `webapp-policy` Policy, we can run:
```
$ kubectl describe pol webapp-policy
. . .
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal AddedOrUpdated 11s nginx-ingress-controller Policy default/webapp-policy was added or updated
```
Note how the events section includes a Normal event with the AddedOrUpdated reason that informs us that the configuration was successfully applied.

If you create an invalid resource, the Ingress Controller will reject it and emit a Rejected event. For example, if you create a Policy `webapp-policy` with an invalid IP `10.0.0.` in the `allow` field, you will get:
```
$ kubectl describe policy webapp-policy
. . .
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Rejected 7s nginx-ingress-controller Policy default/webapp-policy is invalid and was rejected: spec.accessControl.allow[0]: Invalid value: "10.0.0.": must be a CIDR or IP
```
Note how the events section includes a Warning event with the Rejected reason.

**Note**: If you make an existing resource invalid, the Ingress Controller will reject it.
Loading