Skip to content
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
29 changes: 29 additions & 0 deletions .github/workflows/check-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json

name: Check Links

permissions: {}

on:
pull_request:
branches:
- "*"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
linkChecker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Check unrendered links
id: lychee_unrendered
uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332 # v2.4.1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
fail: true
debug: false
args: --github-token ${{secrets.GITHUB_TOKEN}} --config config/lychee.toml --max-concurrency 2 --max-retries 3 --retry-wait-time 5 --accept 200,429 --timeout 60 -E ./content
Empty file added .lycheeignore
Empty file.
1 change: 1 addition & 0 deletions config/lychee.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exclude_path = ["public/docs/reference/"]
27 changes: 15 additions & 12 deletions content/en/docs/guides/use-fluxcd.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,18 @@ spec:
In example, the cluster admin is supposed to apply this Kustomization, during the cluster bootstrap that i.e. will reconcile also Flux itself.
All the remaining Reconciliation resources can be children of this Kustomization.

![bootstrap](./assets/kustomization-hierarchy-root-tenants.png)
![bootstrap](/images/assets/kustomization-hierarchy-root-tenants.png)

### Namespace-as-a-Service

Tenants could have his own set of Namespaces to operate on but it should be prepared by higher-level roles, like platform admins: the declarations would be part of the platform space.
They would be responsible of tenants administration, and each change (e.g. new tenant Namespace) should be a request that would pass through approval.

![no-naas](./assets/flux-tenants-reconciliation.png)
![no-naas](/images/assets/flux-tenants-reconciliation.png)

What if we would like to provide tenants the ability to manage also their own space the GitOps-way? Enter Capsule.

![naas](./assets/flux-tenants-capsule-reconciliation.png)
![naas](/images/assets/flux-tenants-capsule-reconciliation.png)

## Manual setup

Expand Down Expand Up @@ -311,7 +311,7 @@ To deepen on this please go to [#Insights](#insights).

### How to setup Tenants GitOps-ready

Given that [Capsule](github.com/projectcapsule/capsule) and [Capsule Proxy](github.com/clastix/capsule-proxy) are installed, and [Flux v2](https://github.com/fluxcd/flux2) configured with [multi-tenancy lockdown](https://fluxcd.io/docs/installation/#multi-tenancy-lockdown) features, of which the patch below:
Given that [Capsule](https://github.com/projectcapsule/capsule) and [Capsule Proxy](/docs/proxy) are installed, and [Flux v2](https://github.com/fluxcd/flux2) configured with [multi-tenancy lockdown](https://fluxcd.io/docs/installation/#multi-tenancy-lockdown) features, of which the patch below:

```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
Expand Down Expand Up @@ -351,21 +351,26 @@ patches:

this is the required set of resources to setup a Tenant:
- `Namespace`: the Tenant GitOps Reconciler "home". This is not part of the Tenant to avoid a chicken & egg problem:

```yaml
apiVersion: v1
kind: Namespace
metadata:
name: my-tenant
```

- `ServiceAccount` of the Tenant GitOps Reconciler, in the above `Namespace`:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitops-reconciler
namespace: my-tenant
```

- `Tenant` resource with the above Tenant GitOps Reconciler's SA as Tenant Owner, with:

- Additional binding to *cluster-admin* `ClusterRole` for the Tenant's `Namespace`s and `Namespace` of the Tenant GitOps Reconciler' `ServiceAccount`.
By default Capsule binds only `admin` ClusterRole, which has no privileges over Custom Resources, but *cluster-admin* has. This is needed to operate on Flux CRs:
```yaml
Expand Down Expand Up @@ -531,42 +536,40 @@ This is because we need to make tenant reconciliation requests through Capsule P

### Threats

##### Bypass unprivileged impersonation
#### Bypass unprivileged impersonation

The reason why we can't set impersonation to be optional is because, as each tenant is allowed to not specify neither the kubeconfig nor the impersonation SA for the Reconciliation resource, and because in any case that kubeconfig could contain whatever privileged credentials, Flux would otherwise use the privileged ServiceAccount, to reconcile tenant resources.

That way, a tenant would be capable of managing the GitOps way the cluster as he was a cluster admin.

Furthermore, let's see if there are other vulnerabilities we are able to protect from.

##### Impersonate privileged SA
#### Impersonate privileged SA

Then, what if a tenant tries to escalate by using one of the Flux controllers privileged `ServiceAccount`s?

As `spec.ServiceAccountName` for Reconciliation resource cannot cross-namespace reference Service Accounts, tenants are able to let Flux apply his own resources only with ServiceAccounts that reside in his own Namespaces. Which is, Namespace of the ServiceAccount and Namespace of the Reconciliation resource must match.

He could neither create the Reconciliation resource where a privileged ServiceAccount is present (like flux-system), as the Namespace has to be owned by the Tenant. Capsule would block those Reconciliation resource creation requests.

##### Create and impersonate privileged SA
#### Create and impersonate privileged SA

Then, what if a tenant tries to escalate by creating a privileged `ServiceAccount` inside on of his own `Namespace`s?

A tenant could create a `ServiceAccount` in an owned `Namespace`, but he can't neither bind at cluster-level nor at a non-owned Namespace-level a ClusterRole, as that wouldn't be permitted by Capsule admission controllers.

Now let's go on with the practical part.

##### Change ownership of privileged Namespaces (e.g. flux-system)
#### Change ownership of privileged Namespaces (e.g. flux-system)

He could try to use privileged `ServiceAccount` by changing ownership of a privileged Namespace so that he could create Reconciliation resource there and using the privileged SA.
This is not permitted as he can't patch Namespaces which have not been created by him. Capsule request validation would not pass.

For other protections against threats in this multi-tenancy scenario please see the Capsule [Multi-Tenancy Benchmark](/docs/general/mtb).
For other protections against threats in this multi-tenancy scenario please see the Capsule [Multi-Tenancy Benchmark](/docs/overview/benchmark/).

## References
- https://fluxcd.io/docs/installation/#multi-tenancy-lockdown
- https://fluxcd.io/blog/2022/05/may-2022-security-announcement/
- https://github.com/clastix/capsule-proxy/issues/218
- https://github.com/projectcapsule/capsule-proxy/issues/218
- https://github.com/projectcapsule/capsule/issues/528
- https://github.com/clastix/flux2-capsule-multi-tenancy
- https://github.com/fluxcd/flux2-multi-tenancy
- https://fluxcd.io/docs/guides/repository-structure/
Loading
Loading