An open API service indexing awesome lists of open source software.

https://github.com/adevinta/ingress-allowlisting-controller

A k8s controller that configures ingress whitelisting based on a custom CRD
https://github.com/adevinta/ingress-allowlisting-controller

allowlist allowlisting gateway-api ingress k8s kubernetes operator whitelist whitelisting

Last synced: about 2 months ago
JSON representation

A k8s controller that configures ingress whitelisting based on a custom CRD

Awesome Lists containing this project

README

          

# Ingress Allowlisting Controller
The Ingress Allowlisting Controller is a Kubernetes controller designed to manage allowlisting rules for Kubernetes Ingress resources. It ensures that only trusted IPs or ranges can access specific ingress endpoints, enhancing security and compliance.
This k8s controller configures ingress allowlisting based on a custom CRD

## Installation

### Helm Installation (Using Local Chart)
To install the ingress-allowlisting-controller using the Helm chart provided in the repository, follow these steps:

1. Clone the Repository
Clone the repository to your local machine:
```bash
git clone https://github.com/adevinta/ingress-allowlisting-controller.git
cd ingress-allowlisting-controller/helm-charts/ingress-allowlisting-controller
```
2. Install the Chart
Install the controller using the local Helm chart. Customize the installation by specifying the namespace and configuration if needed:

```bash
helm install ingress-allowlisting-controller ./ --namespace ingress-allowlisting --create-namespace
```
3. Verify the Installation
Ensure the controller is running in your cluster:

```bash
kubectl get pods -n ingress-allowlisting
```
You should see a pod named ingress-allowlisting-controller running.

## Usage

Once installed, the ingress-allowlisting-controller will monitor and apply allowlisting rules to Kubernetes Ingress resources.

### Example Ingress Resource
Below are examples of an Ingress resource with allowlisting annotations, using both the namespace level CIDR CRD as well
as the cluster level CRD

Namespaced version of CIDRs object
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ipam.adevinta.com/allowlist-group: MyCidrsObject
```

Cluster version of the CIDRs object

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ipam.adevinta.com/cluster-allowlist-group: MyCidrsObject
```

The content of the annotations can be a comma-separated list:

`MyCidrsObject,MyCidrsObject2,MyCidrsObject3`

### Example NetworkPolicy Resource
Below are examples of NetworkPolicy resources with different `policyTypes` (Ingress or Egress).

NetworkPolicy with `ingress` with namespaced version of CIDRs object
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-allow-myips
annotations:
ipam.adevinta.com/allowlist-group: MyCidrsObject
spec:
podSelector: {} # Applies to all pods in namespace
policyTypes:
- Ingress
# Controller will populate spec.ingress[0] with ipBlock rules here
```
NetworkPolicy with `egress` using a cluster-scoped CIDRs object and predefined ports:

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-allow-http
annotations:
ipam.adevinta.com/cluster-allowlist-group: http-allowed
spec:
podSelector: {} # Applies to all pods in namespace
policyTypes:
- Egress
# Controller will populate spec.egress[0] with ipBlock rules here respecting the ports
egress:
- ports:
- port: 443
- port: 80
```

##### Key Points:

* You define: `podSelector` and `policyTypes`
* Controller manages: Automatically populates and maintains the `spec.ingress` or `spec.egress` sections with `ipBlock` rules
* Overwrite behavior: Any existing `ipBlock` rules in these sections will be overwritten by the controller
* Dual policyTypes: If both `Ingress` and `Egress` are specified, the controller will populate both sections

```yaml
spec:
ingress: # For Ingress policies
- from:
- ipBlock:
cidr: x.x.x.x/y
egress: # For Egress policies
- to:
- ipBlock:
cidr: x.x.x.x/y
```

### Example CIDR and ClusterCIDR CRDs

```yaml
apiVersion: ipam.adevinta.com/v1alpha1
kind: CIDRs
metadata:
name: MyCidrsObject
spec:
cidrs:
- 1.1.1.1/32
- 2.2.2.2/32
```

```yaml
apiVersion: ipam.adevinta.com/v1alpha1
kind: ClusterCIDRs
metadata:
name: Cloudfront
spec:
cidrs:
- 120.52.22.96/27
- 205.251.249.0/24
- 180.163.57.128/26
```

### Fetching CIDRs from remote sources

Ingress-allowlister supports synchronizing CIDRs from remote http sources.
To use this feature, configure the CIDRs or ClusterCIDRs object as follows

```yaml
apiVersion: ipam.adevinta.com/v1alpha1
kind: CIDRs
metadata:
name: ec2
namespace: test
spec:
requeueAfter: 30m # Re-evaluate the remote URL every 30 minutes
location:
cel: 'data.prefixes.filter(p, p.service == "EC2" && has(p.ip_prefix)).map(p, p.ip_prefix)' # transform the AWS response into a list of strings using CEL expression
uri: https://ip-ranges.amazonaws.com/ip-ranges.json # the remote URL responding all IPs
headersFrom: # optional: inject CIDRs to the HTTP request (if the request needs to be authenticated)
secretRef: # optional: inject all keys
name: aws-authentication-headers # all aws-authentication-headers data will be used as http headers in the http request
namespace: test # optional. For CIDRs, it must match the CIDRs namespace when not empty.
configMapRef:
name: aws-headers # all aws-headers data will be used as http headers in the http request
namespace: test # optional. For CIDRs, it must match the CIDRs namespace when not empty.
---
# optional
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-headers
namespace: test
data:
My-Header: some-value
---
# optional
apiVersion: v1
kind: Secret
metadata:
name: aws-authentication-headers
namespace: test
data:
Authentication: $(echo "Bearer $token" | base64)
```

#### Fetching CIDRs from github

To fetch CIDRs stored in github repositories, you can use the github API endpoint:

```yaml
apiVersion: ipam.adevinta.com/v1alpha1
kind: CIDRs
metadata:
name: my-cidrs
namespace: test
spec:
requeueAfter: 30m
location:
uri: https://api.github.com/repos/my-org/my-repo/contents/path/to/cidrs/file.json
```

## Metrics
The operator exposes a single metric `namespace_ingress_IpAllowlistingGroup_missing` that, when operated appropiately, it offer several information:

```
# HELP namespace_ingress_IpAllowlistingGroup_missing Number of missing IpAllowlistingGroup objects. >0 implies expected objects were not found
# TYPE namespace_ingress_IpAllowlistingGroup_missing gauge
namespace_ingress_IpAllowlistingGroup_missing{cidrs_name="alvarocidr",ingress="kube-nurse-kubenurse",namespace="cre-system"} 0
```
When the metric exists and equals 0, it means that there are no errors; the given object in the given namespace associated to the given ingress exists and has been resolved adequately.

When the metric exists and equals 1 means that there was an error resolving the `cidr_name`, probably, because the object didn't exist in the namespace.

### Common operations:
#### number of ingresses with allowlistGroup annotations:
`count(sum(namespace_ingress_IpAllowlistingGroup_missing) by (ingress))`
#### number of ingresses with failed annotations:
`count(sum(namespace_ingress_IpAllowlistingGroup_missing) by (ingress) > 0)`