Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ac6051e
add 0.13.0 notes
oliverbaehler Dec 5, 2025
032e016
add 0.13.0 notes
oliverbaehler Dec 5, 2025
c87dea9
chore: prepare docs
oliverbaehler Jan 23, 2026
fa1fd9d
feat: rollout preview docs
oliverbaehler Jan 29, 2026
5294f0f
feat: rollout preview docs
oliverbaehler Jan 29, 2026
48b8e41
feat: rollout preview docs
oliverbaehler Jan 30, 2026
1c8cba6
feat: add required metadata fields
oliverbaehler Feb 3, 2026
f4aae39
Some readability fixes (#71)
sandert-k8s Feb 11, 2026
48d9110
feat: add events
oliverbaehler Feb 20, 2026
9ea1d22
feat: add events
oliverbaehler Feb 20, 2026
3cd8529
feat: add events
oliverbaehler Feb 20, 2026
18f7e9a
feat: add events
oliverbaehler Feb 20, 2026
4f1cc74
feat: add proxy docs
oliverbaehler Feb 23, 2026
75944db
feat: add talks from kcd paris
oliverbaehler Mar 3, 2026
4d919c9
feat: add resources tab
oliverbaehler Mar 3, 2026
6e3a2e9
feat: share project updates
oliverbaehler Mar 10, 2026
0362312
feat: share project updates
oliverbaehler Mar 10, 2026
7214fb6
replication: rewrite replications and add diagrams (#74)
sandert-k8s Mar 15, 2026
12445df
feat(customquotas): add (#65)
CorentinPtrl Mar 23, 2026
2ceafc1
feat: rewrite overview section (#79)
sandert-k8s Mar 30, 2026
10116ae
feat: add customquota docs
oliverbaehler Apr 1, 2026
7ee88e6
feat: add customquota docs
oliverbaehler Apr 1, 2026
832be13
fix(proxysetting): change pods to GlobalCustomQuota
sandert-k8s Apr 3, 2026
f740e49
fix: remove superfluous apiversions from proxysettings
sandert-k8s Apr 7, 2026
9a90505
feat(replications): Add additional example for context
sandert-k8s Apr 3, 2026
17f7e93
fix name Sander
sandert-k8s Apr 3, 2026
60a5740
feat: add global custom quota docs
oliverbaehler Apr 17, 2026
5c9564b
Merge branch 'release/preview-v0.13' of github.com:projectcapsule/web…
oliverbaehler Apr 17, 2026
d3fd728
feat: finalize custom quota docs
oliverbaehler Apr 23, 2026
1fae7eb
feat: add none scope
oliverbaehler May 5, 2026
a831f26
fix: add gateway example
oliverbaehler May 6, 2026
31fea96
chore: release cleanup
oliverbaehler May 18, 2026
4bf48ad
chore: release cleanup
oliverbaehler May 20, 2026
843ae5c
feat: add version reference
oliverbaehler May 21, 2026
c8a9fa1
feat: add version reference
oliverbaehler May 21, 2026
dd7c67e
fix: references
oliverbaehler May 21, 2026
614240a
fix: references
oliverbaehler May 21, 2026
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
7 changes: 6 additions & 1 deletion config/_default/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,12 @@ menu:
pre: <i class='fas fa-briefcase'></i>
weight: 16

- name: Resources
url: /project/resources/
pre: <i class="fa-solid fa-circle-info"></i>
weight: 17

- name: Project
url: /project/
pre: <i class='fas fa-flask'></i>
weight: 17
weight: 18
2 changes: 2 additions & 0 deletions config/_default/params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ version: latest
url_latest_version: https://projectcapsule.dev
archived_version: false
versions:
- version: v0.13
url: https://release-0-13.projectcapsule.dev
- version: v0.12
url: https://release-0-12.projectcapsule.dev
- version: v0.11
Expand Down
178 changes: 178 additions & 0 deletions content/en/docs/operating/admission-policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,114 @@ You may consider the upstream policies, depending on your needs:
* [QoS Guaranteed](https://kyverno.io/policies/other/require-qos-guaranteed/require-qos-guaranteed/)


## Certificates

### Deny ClusterIssuer in Certificates

Often when working in multi-tenant environments, you want to ensure that tenants are not using `ClusterIssuers` to issue certificates, but rather use namespaced `Issuers` within their own namespace. This policy enforces that `cert-manager.io/v1/Certificate` resources do not reference `ClusterIssuers` and that the `Issuer` referenced is in the same namespace as the `Certificate`.

{{% tabpane lang="yaml" %}}
{{% tab header="**Engines**:" disabled=true /%}}
{{< tab header="Kyverno" >}}
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: certificates-only-local-issuer
spec:
validationFailureAction: Enforce
background: true
rules:
- name: deny-clusterissuer-in-certificates
match:
any:
- resources:
kinds:
- cert-manager.io/v1/Certificate
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
validate:
message: "Certificates must not reference ClusterIssuers; use a namespaced Issuer in the same namespace."
deny:
conditions:
any:
- key: "{{ request.object.spec.issuerRef.kind || 'Issuer' }}"
operator: Equals
value: "ClusterIssuer"

- name: deny-cross-namespace-issuerref-in-certificates
match:
any:
- resources:
kinds:
- cert-manager.io/v1/Certificate
validate:
message: "Certificates must reference an Issuer in the same namespace (spec.issuerRef.namespace must be empty or equal to the Certificate namespace)."
deny:
conditions:
any:
# If issuerRef.namespace is set and differs from the Certificate namespace -> deny
- key: "{{request.object.spec.issuerRef.namespace || '' }}"
operator: NotEquals
value: ""
# AND also not equal to request namespace
- key: "{{ request.object.spec.issuerRef.namespace || request.namespace }}"
operator: NotEquals
value: "{{ request.namespace }}"{{< /tab >}}
{{% /tabpane %}}

### Deny ClusterIssuer in Gateways

Deny to usage of ClusterIssuers in Gateways by checking for the `cert-manager.io/cluster-issuer` annotation. This ensures that tenants use namespaced issuer mechanisms instead.

This requires extra permissions to allow Kyverno to read Gateway resources:

```yaml
admissionController:
rbac:
clusterRole:
extraResources:
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
```

{{% tabpane lang="yaml" %}}
{{% tab header="**Engines**:" disabled=true /%}}
{{< tab header="Kyverno" >}}
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: gateways-deny-cluster-issuer-annotation
spec:
validationFailureAction: Enforce
background: false
rules:
- name: deny-cert-manager-cluster-issuer-annotation
match:
any:
- resources:
kinds:
- gateway.networking.k8s.io/v1/Gateway
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
validate:
message: "Gateways must not use cert-manager.io/cluster-issuer; use namespaced issuer mechanisms instead."
deny:
conditions:
any:
- key: "{{ request.object.metadata.annotations.\"cert-manager.io/cluster-issuer\" || '' }}"
operator: NotEquals
value: ""{{< /tab >}}
{{% /tabpane %}}



## Images

### Allowed Registries
Expand Down Expand Up @@ -886,3 +994,73 @@ spec:
- (name): "?*"
imagePullPolicy: Always{{< /tab >}}
{{% /tabpane %}}


## Certificate Management


### Selective ClusterIssuers

Allow certain ClusterIssuers within Tenants:

{{% tabpane lang="yaml" %}}
{{% tab header="**Engines**:" disabled=true /%}}
{{< tab header="Kyverno" >}}
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: certificates-restrict-clusterissuer-by-tenant-label
spec:
validationFailureAction: Enforce
background: true
rules:
- name: allow-clusterissuer-only-when-managed-by-matches
match:
any:
- resources:
kinds:
- cert-manager.io/v1/Certificate
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
context:
- name: certManagedBy
variable:
jmesPath: request.object.metadata.labels."capsule.clastix.io/managed-by" || ''
- name: clusterIssuerManagedBy
apiCall:
urlPath: /apis/cert-manager.io/v1/clusterissuers/{{ request.object.spec.issuerRef.name }}
jmesPath: metadata.labels."company.com/tenant" || ''
default: ""
preconditions:
all:
- key: "{{ request.object.spec.issuerRef.kind || 'Issuer' }}"
operator: Equals
value: ClusterIssuer
- key: "{{request.operation || 'BACKGROUND'}}"
operator: AnyIn
value:
- CREATE
- UPDATE
validate:
message: >-
ClusterIssuer is only allowed when the Certificate label
capsule.clastix.io/managed-by ({{certManagedBy}}) matches the referenced ClusterIssuer label
company.com/tenant ({{clusterIssuerManagedBy}}).
deny:
conditions:
any:
- key: "{{certManagedBy}}"
operator: Equals
value: ""
- key: "{{clusterIssuerManagedBy}}"
operator: Equals
value: ""
- key: "{{certManagedBy}}"
operator: NotEquals
value: "{{clusterIssuerManagedBy}}"{{< /tab >}}
{{% /tabpane %}}


34 changes: 28 additions & 6 deletions content/en/docs/operating/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,56 @@ In Capsule, we introduce a new persona called the `Tenant Owner`. The goal is to

### Capsule Administrators

[Configure Capsule Administrators](/docs/operating/setup/configuration/#administrators). The ClusterRoles assigned to Administrators can be configured in the [CapsuleConfiguration](/docs/operating/setup/configuration/#rbac) as well.

They are promoted to [Tenant-Owners](#tenant-owners) for all available tenants. Effectively granting them the ability to manage all namespaces within the cluster, across all tenants.

**Note**: Granting Capsule Administrator rights should be done with caution, as it provides extensive control over the cluster's multi-tenant environment. **When granting Capsule Administrator rights, the entity gets the privileges to create any namespace (also not part of capsule tenants) and the privileges to delete any tenant namespaces.**

Capsule Administrators can:

- Create and manage [namespaces via labels in any tenant](/docs/tenants/namespaces/#label).
- Create namespaces outside of tenants.
- Delete namespaces in any tenant.

Administrators come in handy in bootstrap scenarios or GitOps scenarios where certain users/serviceaccounts need to be able to manage namespaces for all tenants.

[Configure Capsule Administrators](/docs/operating/setup/configuration/#administrators)

### Capsule Users

[Configure Capsule Users](/docs/operating/setup/configuration/#users)

Any entity which needs to interact with tenants and their namespaces must be defined as a **Capsule User**. This is where the flexibility of Capsule comes into play. You can define users or groups as Capsule Users, allowing them to create and manage namespaces within any tenant they have access to. If they are not defined as Capsule Users, any interactions will be ignored by Capsule. Often a best practice is to define a single group which identifies all your tenant users. This way you can have one generic group for all your users and then use additional groups to separate responsibilities (e.g. administrators vs normal users).

**Only one entry is needed to identify a Capsule User. This is only important for Namespace Admission.**.

![Capsule Users Admission](/images/content/capsule-users-admission.drawio.png)

[Configure Capsule Users](/docs/operating/setup/configuration/#users)
You can always verify the effective Capsule Users by checking the Configuration Status. As this is variable with [Tenant Owners](#tenant-owners), the status will always show the effective users:

```bash
kubectl get capsuleconfiguration default -o jsonpath='{.status.users}' | jq

[
{
"kind": "Group",
"name": "oidc:kubernetes:admin"
},
{
"kind": "Group",
"name": "projectcapsule.dev"
},
{
"kind": "User",
"name": "test-user"
}
]
```

### Tenant Owners

**Every Tenant Owner must be a [Capsule User](#capsule-users)**
[Configure Tenant Owners](/docs/tenants/permissions/#ownership)

**Every Tenant Owner must be a [Capsule User](#capsule-users). By using the [TenantOwner CRD](/docs/tenants/permissions/#tenant-owners) this is automatically handeled.**


They manage the namespaces within their tenants and perform administrative tasks confined to their tenant boundaries. This delegation allows teams to operate more autonomously while still adhering to organizational policies. Tenant Owners can be used to shift reposnsability of one tenant towards this user group. promoting them to the SPOC of all namespaces within the tenant.
Expand All @@ -67,8 +91,6 @@ Tenant Owners can:

Capsule provides robust tools to strictly enforce tenant boundaries, ensuring that each tenant operates within its defined limits. This separation of duties promotes both security and efficient resource management.

[Configure Tenant Owners](/docs/tenants/permissions/#ownership)

## Layouts

Let's dicuss different Tenant Layouts which could be used . These are just approaches we have seen, however you might also find a combination of these which fits your use-case.
Expand Down
4 changes: 2 additions & 2 deletions content/en/docs/operating/best-practices/_index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Best Practices
weight: 2
description: Best Practices when running Capsule in production
description: Best Practices when running Capsule in production
---


Expand Down Expand Up @@ -30,7 +30,7 @@ Instead, a centralized secrets management system should be established — such
To integrate these external secret stores with Kubernetes, the [External Secrets Operator (ESO)](https://external-secrets.io/latest/) is a recommended solution. It automatically syncs defined secrets from external sources as Kubernetes secrets, and supports dynamic rotation, access control, and auditing.

If no external secret store is available, there should at least be a secure way to store sensitive data in Git.
In our ecosystem, we provide a solution based on SOPS (Secrets OPerationS) for this use case.
In our ecosystem, we provide a solution based on SOPS (Secrets OPerationS) for this use case; called the [sops-operator](https://github.com/peak-scale/sops-operator).

[👉 Demonstration](https://killercoda.com/peakscale/course/playgrounds/sops-secrets)

Loading
Loading