Skip to content

Commit 7bb8a16

Browse files
feat: add release for 0.13 (#85)
add 0.13.0 notes Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
1 parent 7e1fe36 commit 7bb8a16

50 files changed

Lines changed: 7748 additions & 1063 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

config/_default/hugo.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ menu:
164164
pre: <i class='fas fa-briefcase'></i>
165165
weight: 16
166166

167+
- name: Resources
168+
url: /project/resources/
169+
pre: <i class="fa-solid fa-circle-info"></i>
170+
weight: 17
171+
167172
- name: Project
168173
url: /project/
169174
pre: <i class='fas fa-flask'></i>
170-
weight: 17
175+
weight: 18

config/_default/params.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ version: latest
99
url_latest_version: https://projectcapsule.dev
1010
archived_version: false
1111
versions:
12+
- version: v0.13
13+
url: https://release-0-13.projectcapsule.dev
1214
- version: v0.12
1315
url: https://release-0-12.projectcapsule.dev
1416
- version: v0.11

content/en/docs/operating/admission-policies.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,114 @@ You may consider the upstream policies, depending on your needs:
747747
* [QoS Guaranteed](https://kyverno.io/policies/other/require-qos-guaranteed/require-qos-guaranteed/)
748748

749749

750+
## Certificates
751+
752+
### Deny ClusterIssuer in Certificates
753+
754+
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`.
755+
756+
{{% tabpane lang="yaml" %}}
757+
{{% tab header="**Engines**:" disabled=true /%}}
758+
{{< tab header="Kyverno" >}}
759+
---
760+
apiVersion: kyverno.io/v1
761+
kind: ClusterPolicy
762+
metadata:
763+
name: certificates-only-local-issuer
764+
spec:
765+
validationFailureAction: Enforce
766+
background: true
767+
rules:
768+
- name: deny-clusterissuer-in-certificates
769+
match:
770+
any:
771+
- resources:
772+
kinds:
773+
- cert-manager.io/v1/Certificate
774+
namespaceSelector:
775+
matchExpressions:
776+
- key: capsule.clastix.io/tenant
777+
operator: Exists
778+
validate:
779+
message: "Certificates must not reference ClusterIssuers; use a namespaced Issuer in the same namespace."
780+
deny:
781+
conditions:
782+
any:
783+
- key: "{{ request.object.spec.issuerRef.kind || 'Issuer' }}"
784+
operator: Equals
785+
value: "ClusterIssuer"
786+
787+
- name: deny-cross-namespace-issuerref-in-certificates
788+
match:
789+
any:
790+
- resources:
791+
kinds:
792+
- cert-manager.io/v1/Certificate
793+
validate:
794+
message: "Certificates must reference an Issuer in the same namespace (spec.issuerRef.namespace must be empty or equal to the Certificate namespace)."
795+
deny:
796+
conditions:
797+
any:
798+
# If issuerRef.namespace is set and differs from the Certificate namespace -> deny
799+
- key: "{{request.object.spec.issuerRef.namespace || '' }}"
800+
operator: NotEquals
801+
value: ""
802+
# AND also not equal to request namespace
803+
- key: "{{ request.object.spec.issuerRef.namespace || request.namespace }}"
804+
operator: NotEquals
805+
value: "{{ request.namespace }}"{{< /tab >}}
806+
{{% /tabpane %}}
807+
808+
### Deny ClusterIssuer in Gateways
809+
810+
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.
811+
812+
This requires extra permissions to allow Kyverno to read Gateway resources:
813+
814+
```yaml
815+
admissionController:
816+
rbac:
817+
clusterRole:
818+
extraResources:
819+
- apiGroups: ["gateway.networking.k8s.io"]
820+
resources: ["*"]
821+
verbs: ["get", "list", "watch"]
822+
```
823+
824+
{{% tabpane lang="yaml" %}}
825+
{{% tab header="**Engines**:" disabled=true /%}}
826+
{{< tab header="Kyverno" >}}
827+
---
828+
apiVersion: kyverno.io/v1
829+
kind: ClusterPolicy
830+
metadata:
831+
name: gateways-deny-cluster-issuer-annotation
832+
spec:
833+
validationFailureAction: Enforce
834+
background: false
835+
rules:
836+
- name: deny-cert-manager-cluster-issuer-annotation
837+
match:
838+
any:
839+
- resources:
840+
kinds:
841+
- gateway.networking.k8s.io/v1/Gateway
842+
namespaceSelector:
843+
matchExpressions:
844+
- key: capsule.clastix.io/tenant
845+
operator: Exists
846+
validate:
847+
message: "Gateways must not use cert-manager.io/cluster-issuer; use namespaced issuer mechanisms instead."
848+
deny:
849+
conditions:
850+
any:
851+
- key: "{{ request.object.metadata.annotations.\"cert-manager.io/cluster-issuer\" || '' }}"
852+
operator: NotEquals
853+
value: ""{{< /tab >}}
854+
{{% /tabpane %}}
855+
856+
857+
750858
## Images
751859

752860
### Allowed Registries
@@ -886,3 +994,73 @@ spec:
886994
- (name): "?*"
887995
imagePullPolicy: Always{{< /tab >}}
888996
{{% /tabpane %}}
997+
998+
999+
## Certificate Management
1000+
1001+
1002+
### Selective ClusterIssuers
1003+
1004+
Allow certain ClusterIssuers within Tenants:
1005+
1006+
{{% tabpane lang="yaml" %}}
1007+
{{% tab header="**Engines**:" disabled=true /%}}
1008+
{{< tab header="Kyverno" >}}
1009+
---
1010+
apiVersion: kyverno.io/v1
1011+
kind: ClusterPolicy
1012+
metadata:
1013+
name: certificates-restrict-clusterissuer-by-tenant-label
1014+
spec:
1015+
validationFailureAction: Enforce
1016+
background: true
1017+
rules:
1018+
- name: allow-clusterissuer-only-when-managed-by-matches
1019+
match:
1020+
any:
1021+
- resources:
1022+
kinds:
1023+
- cert-manager.io/v1/Certificate
1024+
namespaceSelector:
1025+
matchExpressions:
1026+
- key: capsule.clastix.io/tenant
1027+
operator: Exists
1028+
context:
1029+
- name: certManagedBy
1030+
variable:
1031+
jmesPath: request.object.metadata.labels."capsule.clastix.io/managed-by" || ''
1032+
- name: clusterIssuerManagedBy
1033+
apiCall:
1034+
urlPath: /apis/cert-manager.io/v1/clusterissuers/{{ request.object.spec.issuerRef.name }}
1035+
jmesPath: metadata.labels."company.com/tenant" || ''
1036+
default: ""
1037+
preconditions:
1038+
all:
1039+
- key: "{{ request.object.spec.issuerRef.kind || 'Issuer' }}"
1040+
operator: Equals
1041+
value: ClusterIssuer
1042+
- key: "{{request.operation || 'BACKGROUND'}}"
1043+
operator: AnyIn
1044+
value:
1045+
- CREATE
1046+
- UPDATE
1047+
validate:
1048+
message: >-
1049+
ClusterIssuer is only allowed when the Certificate label
1050+
capsule.clastix.io/managed-by ({{certManagedBy}}) matches the referenced ClusterIssuer label
1051+
company.com/tenant ({{clusterIssuerManagedBy}}).
1052+
deny:
1053+
conditions:
1054+
any:
1055+
- key: "{{certManagedBy}}"
1056+
operator: Equals
1057+
value: ""
1058+
- key: "{{clusterIssuerManagedBy}}"
1059+
operator: Equals
1060+
value: ""
1061+
- key: "{{certManagedBy}}"
1062+
operator: NotEquals
1063+
value: "{{clusterIssuerManagedBy}}"{{< /tab >}}
1064+
{{% /tabpane %}}
1065+
1066+

content/en/docs/operating/architecture.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,56 @@ In Capsule, we introduce a new persona called the `Tenant Owner`. The goal is to
3030

3131
### Capsule Administrators
3232

33+
[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.
34+
3335
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.
3436

3537
**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.**
3638

3739
Capsule Administrators can:
40+
3841
- Create and manage [namespaces via labels in any tenant](/docs/tenants/namespaces/#label).
3942
- Create namespaces outside of tenants.
4043
- Delete namespaces in any tenant.
4144

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

44-
[Configure Capsule Administrators](/docs/operating/setup/configuration/#administrators)
45-
4647
### Capsule Users
4748

49+
[Configure Capsule Users](/docs/operating/setup/configuration/#users)
50+
4851
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).
4952

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

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

54-
[Configure Capsule Users](/docs/operating/setup/configuration/#users)
57+
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:
58+
59+
```bash
60+
kubectl get capsuleconfiguration default -o jsonpath='{.status.users}' | jq
61+
62+
[
63+
{
64+
"kind": "Group",
65+
"name": "oidc:kubernetes:admin"
66+
},
67+
{
68+
"kind": "Group",
69+
"name": "projectcapsule.dev"
70+
},
71+
{
72+
"kind": "User",
73+
"name": "test-user"
74+
}
75+
]
76+
```
5577

5678
### Tenant Owners
5779

58-
**Every Tenant Owner must be a [Capsule User](#capsule-users)**
80+
[Configure Tenant Owners](/docs/tenants/permissions/#ownership)
81+
82+
**Every Tenant Owner must be a [Capsule User](#capsule-users). By using the [TenantOwner CRD](/docs/tenants/permissions/#tenant-owners) this is automatically handeled.**
5983

6084

6185
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.
@@ -67,8 +91,6 @@ Tenant Owners can:
6791

6892
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.
6993

70-
[Configure Tenant Owners](/docs/tenants/permissions/#ownership)
71-
7294
## Layouts
7395

7496
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.

content/en/docs/operating/best-practices/_index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Best Practices
33
weight: 2
4-
description: Best Practices when running Capsule in production
4+
description: Best Practices when running Capsule in production
55
---
66

77

@@ -30,7 +30,7 @@ Instead, a centralized secrets management system should be established — such
3030
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.
3131

3232
If no external secret store is available, there should at least be a secure way to store sensitive data in Git.
33-
In our ecosystem, we provide a solution based on SOPS (Secrets OPerationS) for this use case.
33+
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).
3434

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

0 commit comments

Comments
 (0)