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

feat: bumping to new capsule version #132

Merged
merged 6 commits into from
Aug 21, 2021
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
3 changes: 2 additions & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
name: Kubernetes
strategy:
matrix:
k8s-version: [ 'v1.16.15', 'v1.17.11', 'v1.18.8', 'v1.19.4', 'v1.20.0' ]
k8s-version: [ 'v1.16.15', 'v1.17.11', 'v1.18.8', 'v1.19.4', 'v1.20.7', 'v1.21.2', 'v1.22.0' ]
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
Expand All @@ -20,6 +20,7 @@ jobs:
- uses: engineerd/[email protected]
with:
skipClusterCreation: true
version: v0.11.1
- uses: azure/setup-helm@v1
with:
version: 3.3.4
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ e2e/clean:
e2e/%: docker-build
kind create cluster --name capsule --image kindest/node:$* --config ./e2e/kind.yaml --wait=120s \
&& kubectl taint nodes capsule-worker2 key1=value1:NoSchedule \
&& wget https://github.com/clastix/capsule/archive/refs/tags/v0.1.0-rc5.tar.gz -P hack \
&& tar -C hack/ -xvf hack/v0.1.0-rc5.tar.gz
helm upgrade --install --create-namespace --namespace capsule-system capsule hack/capsule-0.1.0-rc5/charts/capsule \
&& wget https://github.com/clastix/capsule/archive/refs/tags/v0.1.0-rc6.tar.gz -P hack \
&& tar -C hack/ -xvf hack/v0.1.0-rc6.tar.gz
helm upgrade --install --create-namespace --namespace capsule-system capsule hack/capsule-0.1.0-rc6/charts/capsule \
--set "manager.resources=null" \
--set "manager.options.forceTenantPrefix=true" \
--set "manager.image.tag=v0.1.0-rc5"
--set "manager.image.tag=v0.1.0-rc6"
# capsule-proxy certificates
cd hack \
&& mkcert -install && mkcert 127.0.0.1 \
Expand Down
156 changes: 117 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Current implementation filters the following requests:
* `api/v1/nodes{/name}`
* `apis/storage.k8s.io/v1/storageclasses{/name}`
* `apis/networking.k8s.io/{v1,v1beta1}/ingressclasses{/name}`
* `api/scheduling.k8s.io/{v1}/priorityclasses{/name}`

All other requests are proxied transparently to the APIs server, so no side effects are expected. We're planning to add new APIs in the future, so PRs are welcome!

Expand All @@ -53,6 +54,38 @@ An Helm Chart is available [here](./charts/capsule-proxy/README.md).

Yes, it works by intercepting all the requests from the `kubectl` client directed to the APIs server. It works with both users who use the TLS certificate authentication and those who use OIDC.

## How RBAC is put in place?

Each Tenant owner can have their capabilities managed pretty similar to a standard RBAC.

```yaml
apiVersion: capsule.clastix.io/v1beta1
kind: Tenant
metadata:
name: my-tenant
spec:
owners:
- kind: User
name: alice
proxySettings:
- kind: IngressClasses
operations:
- List
```

The proxy setting `kind` is an __enum__ accepting the supported resources:

- `Nodes`
- `StorageClasses`
- `IngressClasses`
- `PriorityClasses`

Each Resource kind can be granted with several verbs, such as:

- `List`
- `Update`
- `Delete`

### Namespaces

As tenant owner `alice`, you can use `kubectl` to create some namespaces:
Expand All @@ -78,16 +111,18 @@ When a Tenant defines a `.spec.nodeSelector`, the nodes matching that labels can
The annotation `capsule.clastix.io/enable-node-listing` allows the ability for the owners to retrieve the node list (useful in shared HW scenarios).

```yaml
apiVersion: capsule.clastix.io/v1alpha1
apiVersion: capsule.clastix.io/v1beta1
kind: Tenant
metadata:
name: oil
annotations:
capsule.clastix.io/enable-node-listing: "true"
spec:
owner:
kind: User
owners:
- kind: User
name: alice
proxySettings:
- kind: Nodes
operations:
- List
nodeSelector:
kubernetes.io/hostname: capsule-gold-qwerty
```
Expand All @@ -98,27 +133,23 @@ NAME STATUS ROLES AGE VERSION
capsule-gold-qwerty Ready <none> 43h v1.19.1
```

> The following Tenant annotations allow a sort of RBAC on the operations of the nodes:
>
> - `capsule.clastix.io/enable-node-listing`: allows listing of nodes and node retrieval
> - `capsule.clastix.io/enable-node-update`: allows the update of the node (cordoning and uncording, node tainting)
> - `capsule.clastix.io/enable-node-deletion`: allows deletion of the node

### Storage Classes

A Tenant may be limited to use a set of allowed Storage Class resources, as follows.

```yaml
apiVersion: capsule.clastix.io/v1alpha1
apiVersion: capsule.clastix.io/v1beta1
kind: Tenant
metadata:
name: oil
annotations:
capsule.clastix.io/enable-storageclass-listing: "true"
spec:
owner:
kind: User
owners:
- kind: User
name: alice
proxySettings:
- kind: StorageClasses
operations:
- List
storageClasses:
allowed:
- custom
Expand Down Expand Up @@ -147,31 +178,28 @@ custom custom.tls/provisioner Delete WaitForFirstConsum
glusterfs rook.io/glusterfs Delete WaitForFirstConsumer false 54m
```

> The following Tenant annotations allow a sort of RBAC on the Storage Class operations:
>
> - `capsule.clastix.io/enable-storageclass-listing`: allows listing of Storage Class and Storage Classes retrieval
> - `capsule.clastix.io/enable-storageclass-update`: allows the update of the Storage Class
> - `capsule.clastix.io/enable-storageclass-deletion`: allows deletion of the Storage Class

### Ingress Classes

As for Storage Class, also Ingress Class can be enforced.

```yaml
apiVersion: capsule.clastix.io/v1alpha1
apiVersion: capsule.clastix.io/v1beta1
kind: Tenant
metadata:
name: oil
annotations:
capsule.clastix.io/enable-ingressclass-listing: "true"
spec:
owner:
kind: User
owners:
- kind: User
name: alice
ingressClasses:
allowed:
- custom
allowedRegex: "\\w+-lb"
proxySettings:
- kind: IngressClasses
operations:
- List
ingressOptions:
allowedClasses:
allowed:
- custom
allowedRegex: "\\w+-lb"
```

In the Kubernetes cluster we could have more Ingress Class resources, some of them forbidden and non-usable by the Tenant owner.
Expand All @@ -189,22 +217,62 @@ nginx nginx.plus/ingress
The expected output using `capsule-proxy` is the retrieval of the `custom` Ingress Class as well the other ones matching the regex `\w+-lb`.

```bash
$ kubectl --context admin@mycluster get ingressclasses
$ kubectl --context alice-oidc@mycluster get ingressclasses
NAME CONTROLLER PARAMETERS AGE
custom example.com/custom IngressParameters.k8s.example.com/custom 24h
external-lb example.com/external IngressParameters.k8s.example.com/external-lb 2s
internal-lb example.com/internal IngressParameters.k8s.example.com/internal-lb 15m
```

> The following Tenant annotations allow a sort of RBAC on the Ingress Class operations:
>
> - `capsule.clastix.io/enable-ingressclass-listing`: allows listing of Ingress Class and Ingress Classes retrieval
> - `capsule.clastix.io/enable-ingressclass-update`: allows the update of the Ingress Class
> - `capsule.clastix.io/enable-ingressclass-deletion`: allows deletion of the Ingress Class
### Priority Classes

### Storage and Ingress class required label
Allowed PriorityClasses assigned to a Tenant Owner can be enforced as follows.

For Storage and Ingress Class resources, the `name` label reflecting the resource name is mandatory, otherwise filtering of resources cannot be put in place.
```yaml
apiVersion: capsule.clastix.io/v1beta1
kind: Tenant
metadata:
name: oil
spec:
owners:
- kind: User
name: alice
proxySettings:
- kind: IngressClasses
operations:
- List
priorityClasses:
allowed:
- best-effort
allowedRegex: "\\w+priority"
```

In the Kubernetes cluster we could have more PriorityClasses resources, some of them forbidden and non-usable by the Tenant owner.

```bash
$ kubectl --context admin@mycluster get priorityclasses.scheduling.k8s.io
NAME VALUE GLOBAL-DEFAULT AGE
custom 1000 false 18s
maxpriority 1000 false 18s
minpriority 1000 false 18s
nonallowed 1000 false 8m54s
system-cluster-critical 2000000000 false 3h40m
system-node-critical 2000001000 false 3h40m
```

The expected output using `capsule-proxy` is the retrieval of the `custom` PriorityClass as well the other ones matching the regex `\w+priority`.

```bash
$ kubectl --context alice-oidc@mycluster get ingressclasses
NAME VALUE GLOBAL-DEFAULT AGE
custom 1000 false 18s
maxpriority 1000 false 18s
minpriority 1000 false 18s
```

### Storage/Ingress class and PriorityClass required label

For Storage Class, Ingress Class and Priority Class resources, the `name` label reflecting the resource name is mandatory, otherwise filtering of resources cannot be put in place.

```yaml
---
Expand All @@ -228,6 +296,16 @@ spec:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
labels:
name: best-effort
name: best-effort
value: 1000
globalDefault: false
description: "Priority class for best-effort Tenants"
```

## Does it work with my preferred Kubernetes dashboard?
Expand Down
8 changes: 4 additions & 4 deletions e2e/tests/ingressclasses/delete.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ load "$BATS_TEST_DIRNAME/../../libs/serviceaccount_utils.bash"

setup() {
create_tenant ingressclassuser alice User
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/1", "value": {"kind": "ServiceAccount", "name": "system:serviceaccount:ingressclassuser-namespace:sa"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/2", "value": {"kind": "Group", "name": "foo.clastix.io"}}]'
create_namespace alice ingressclassuser-namespace
create_serviceaccount sa ingressclassuser-namespace

create_tenant ingressclassgroup foo.clastix.io Group
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom2"]}}]'
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom2"]}}}]'

if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -gt 17 ]]; then
local version="v1"
Expand Down Expand Up @@ -44,7 +44,7 @@ teardown() {
@test "Delete ingressClass without permissions" {
if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -lt 18 ]]; then
kubectl version
skip "IngressClass resources is not suported on Kubernetes < 1.18"
skip "IngressClass resources is not supported on Kubernetes < 1.18"
fi

echo "Delete ingressClass without List and Delete operations" >&3
Expand Down Expand Up @@ -72,7 +72,7 @@ teardown() {
@test "Delete ingressClass with List and Delete operations" {
if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -lt 18 ]]; then
kubectl version
skip "IngressClass resources is not suported on Kubernetes < 1.18"
skip "IngressClass resources is not supported on Kubernetes < 1.18"
fi

kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/0/proxySettings","value":[{"kind": "IngressClasses", "operations": ["List", "Delete"]}]}]'
Expand Down
6 changes: 3 additions & 3 deletions e2e/tests/ingressclasses/get.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ load "$BATS_TEST_DIRNAME/../../libs/serviceaccount_utils.bash"

setup() {
create_tenant ingressclassuser alice User
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/1", "value": {"kind": "ServiceAccount", "name": "system:serviceaccount:ingressclassuser-namespace:sa"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/2", "value": {"kind": "Group", "name": "foo.clastix.io"}}]'
create_namespace alice ingressclassuser-namespace
create_serviceaccount sa ingressclassuser-namespace

create_tenant ingressclassgroup foo.clastix.io Group
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom2"]}}]'
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom2"]}}}]'

if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -gt 17 ]]; then
local version="v1"
Expand Down Expand Up @@ -44,7 +44,7 @@ teardown() {
@test "Get ingressClass without permissions" {
if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -lt 18 ]]; then
kubectl version
skip "IngressClass resources is not suported on Kubernetes < 1.18"
skip "IngressClass resources is not supported on Kubernetes < 1.18"
fi

poll_until_equals "User" "" "kubectl --kubeconfig=${HACK_DIR}/alice.kubeconfig get ingressclasses.networking.k8s.io custom --output=name" 3 5
Expand Down
4 changes: 2 additions & 2 deletions e2e/tests/ingressclasses/list.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ load "$BATS_TEST_DIRNAME/../../libs/serviceaccount_utils.bash"

setup() {
create_tenant ingressclassuser alice User
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/1", "value": {"kind": "ServiceAccount", "name": "system:serviceaccount:ingressclassuser-namespace:sa"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/2", "value": {"kind": "Group", "name": "foo.clastix.io"}}]'
create_namespace alice ingressclassuser-namespace
create_serviceaccount sa ingressclassuser-namespace

create_tenant ingressclassgroup foo.clastix.io Group
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom2"]}}]'
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom2"]}}}]'

if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -gt 17 ]]; then
local version="v1"
Expand Down
8 changes: 4 additions & 4 deletions e2e/tests/ingressclasses/update.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ load "$BATS_TEST_DIRNAME/../../libs/serviceaccount_utils.bash"

setup() {
create_tenant ingressclassuser alice User
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom"], "allowedRegex": "\\w+-lb"}}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/1", "value": {"kind": "ServiceAccount", "name": "system:serviceaccount:ingressclassuser-namespace:sa"}}]'
kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/2", "value": {"kind": "Group", "name": "foo.clastix.io"}}]'
create_namespace alice ingressclassuser-namespace
create_serviceaccount sa ingressclassuser-namespace

create_tenant ingressclassgroup foo.clastix.io Group
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressClasses", "value": {"allowed": ["custom2"]}}]'
kubectl patch tenants.capsule.clastix.io ingressclassgroup --type=json -p '[{"op": "add", "path": "/spec/ingressOptions", "value": {"allowedClasses": {"allowed": ["custom2"]}}}]'

if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -gt 17 ]]; then
local version="v1"
Expand Down Expand Up @@ -44,7 +44,7 @@ teardown() {
@test "Update ingressClass without permissions" {
if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -lt 18 ]]; then
kubectl version
skip "IngressClass resources is not suported on Kubernetes < 1.18"
skip "IngressClass resources is not supported on Kubernetes < 1.18"
fi

echo "Update ingressClass without List and Update operations" >&3
Expand Down Expand Up @@ -72,7 +72,7 @@ teardown() {
@test "Update ingressClass with List and Update operations" {
if [[ $(kubectl version -o json | jq -r .serverVersion.minor) -lt 18 ]]; then
kubectl version
skip "IngressClass resources is not suported on Kubernetes < 1.18"
skip "IngressClass resources is not supported on Kubernetes < 1.18"
fi

kubectl patch tenants.capsule.clastix.io ingressclassuser --type=json -p '[{"op": "add", "path": "/spec/owners/0/proxySettings","value":[{"kind": "IngressClasses", "operations": ["List", "Update"]}]}]'
Expand Down
Loading