Helm Charts are now inside of the repository (#147)

* Adding Helm chart source

* Pointing to new Chart location

* Setting GitHub Action for remote Helm Chart release

* Updating Go dependencies

* Using Helm as default installation tool

* Separating diff and e2e jobs

* Aligning tests to Helm labels

* Checking fmt and vet, and fixing it

* We don't need limits on E2E
This commit is contained in:
Dario Tranchitella
2020-12-01 23:30:31 +01:00
committed by GitHub
parent 0641350575
commit f6fd0cfe3f
28 changed files with 1904 additions and 71 deletions

45
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: CI
on:
push:
branches: [ "*" ]
pull_request:
branches: [ "*" ]
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v2.3.0
with:
version: latest
only-new-issues: false
args: --timeout 2m
diff:
name: diff
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Cache Go modules
uses: actions/cache@v1
env:
cache-name: go-mod
with:
path: |
~/go/pkg/mod
/home/runner/work/capsule/capsule
key: ${{ runner.os }}-build-${{ env.cache-name }}
restore-keys: |
${{ runner.os }}-build-
${{ runner.os }}-
- run: make manifests
- name: Checking if manifests are disaligned
run: test -z "$(git diff 2> /dev/null)"
- name: Checking if manifests generated untracked files
run: test -z "$(git ls-files --others --exclude-standard 2> /dev/null)"
- run: make fmt vet
- name: Checking if source code is not formatted
run: test -z "$(git diff 2> /dev/null)"

50
.github/workflows/e2e.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: e2e
on:
push:
branches: [ "*" ]
pull_request:
branches: [ "*" ]
jobs:
kind:
name: Kubernetes
strategy:
matrix:
k8s-version: ['v1.16.15', 'v1.17.11', 'v1.18.8', 'v1.19.1']
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache Go modules and Docker images
uses: actions/cache@v1
env:
cache-name: gomod-docker
with:
path: |
~/go/pkg/mod
/var/lib/docker
/home/runner/work/capsule/capsule
key: ${{ matrix.k8s-version }}-build-${{ env.cache-name }}
restore-keys: |
${{ matrix.k8s-version }}-build-
${{ matrix.k8s-version }}-
- run: make manifests
- name: Checking if manifests are disaligned
run: test -z "$(git diff 2> /dev/null)"
- name: Checking if manifests generated untracked files
run: test -z "$(git ls-files --others --exclude-standard 2> /dev/null)"
- name: Installing Ginkgo
run: go get github.com/onsi/ginkgo/ginkgo
- uses: actions/setup-go@v2
with:
go-version: '^1.13.8'
- uses: engineerd/setup-kind@v0.5.0
with:
skipClusterCreation: true
- uses: azure/setup-helm@v1
with:
version: 3.3.4
- name: e2e testing
run: make e2e/${{ matrix.k8s-version }}

35
.github/workflows/helm.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Helm Chart
on:
push:
branches: [ "*" ]
pull_request:
branches: [ "*" ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: azure/setup-helm@v1
with:
version: 3.3.4
- name: Linting Chart
run: helm lint ./charts/capsule
release:
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Publish Helm chart
uses: stefanprodan/helm-gh-pages@master
with:
token: ${{ secrets.BOT_GITHUB_TOKEN }}
charts_dir: charts
charts_url: https://clastix.github.io/charts
owner: clastix
repository: charts
branch: gh-pages
target_dir: .
commit_username: prometherion
commit_email: dario@tranchitella.eu

View File

@@ -1,63 +0,0 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ "*" ]
pull_request:
branches: [ "*" ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v2.3.0
with:
# version of golangci-lint to use in form of v1.2.3
version: latest
# if set to true and the action runs on a pull request - the action outputs only newly found issues
only-new-issues: false
args: --timeout 2m
kind:
name: e2e
strategy:
matrix:
k8s-version: ['v1.16.15', 'v1.17.11', 'v1.18.8', 'v1.19.1']
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache Go modules and Docker images
uses: actions/cache@v1
env:
cache-name: gomod-docker
with:
path: |
~/go/pkg/mod
/var/lib/docker
/home/runner/work/capsule/capsule
key: ${{ matrix.k8s-version }}-build-${{ env.cache-name }}
restore-keys: |
${{ matrix.k8s-version }}-build-
${{ matrix.k8s-version }}-
- name: Removing kustomize
run: sudo snap remove kustomize && sudo rm -rf $(which kustomize)
- name: Installing Ginkgo
run: go get github.com/onsi/ginkgo/ginkgo
- uses: actions/setup-go@v2
with:
go-version: '^1.13.8'
- uses: engineerd/setup-kind@v0.5.0
with:
skipClusterCreation: true
- name: e2e testing
run: make e2e/${{ matrix.k8s-version }}

View File

@@ -139,7 +139,7 @@ e2e/%:
kind create cluster --name capsule --image=kindest/node:$*
make docker-build
kind load docker-image --nodes capsule-control-plane --name capsule $(IMG)
make deploy
while [ -z $$(kubectl -n capsule-system get secret capsule-tls -o jsonpath='{.data.tls\.crt}') ]; do echo "waiting Capsule to be up and running..." && sleep 5; done
kubectl create namespace capsule-system
helm upgrade --install --namespace capsule-system capsule ./charts/capsule --set 'manager.image.pullPolicy=Never' --set 'manager.resources=null'
ginkgo -v -tags e2e ./e2e
kind delete cluster --name capsule

View File

@@ -38,7 +38,7 @@ Make sure you have access to a Kubernetes cluster as an administrator.
There are two ways to install Capsule:
* Use the Helm Chart available [here](https://github.com/clastix/capsule-helm-chart)
* Use the Helm Chart available [here](./charts/capsule/README.md)
* Use [`kustomize`](https://github.com/kubernetes-sigs/kustomize)
## Install with kustomize

View File

@@ -60,9 +60,9 @@ type TenantSpec struct {
// +kubebuilder:validation:Optional
NamespacesMetadata AdditionalMetadata `json:"namespacesMetadata"`
// +kubebuilder:validation:Optional
ServicesMetadata AdditionalMetadata `json:"servicesMetadata"`
StorageClasses StorageClassesSpec `json:"storageClasses"`
IngressClasses IngressClassesSpec `json:"ingressClasses"`
ServicesMetadata AdditionalMetadata `json:"servicesMetadata"`
StorageClasses StorageClassesSpec `json:"storageClasses"`
IngressClasses IngressClassesSpec `json:"ingressClasses"`
ContainerRegistries *ContainerRegistriesSpec `json:"containerRegistries,omitempty"`
// +kubebuilder:validation:Optional
NodeSelector map[string]string `json:"nodeSelector"`

View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

28
charts/capsule/Chart.yaml Normal file
View File

@@ -0,0 +1,28 @@
apiVersion: v2
type: application
description: A Helm chart to deploy the Capsule Operator for easily implementing,
managing, and maintaining mutitenancy and access control in Kubernetes.
home: https://github.com/clastix/capsule
icon: https://github.com/clastix/capsule/blob/master/assets/logo/space-capsule3.png
keywords:
- kubernetes
- operator
- multi-tenancy
- multi-tenant
- multitenancy
- multitenant
- namespace
maintainers:
- email: hello@clastix.io
name: Clastix Labs Team
name: capsule
sources:
- https://github.com/clastix/capsule
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 0.0.6
# This is the version number of the application being deployed.
# This version number should be incremented each time you make changes to the application.
appVersion: 0.0.3

122
charts/capsule/README.md Normal file
View File

@@ -0,0 +1,122 @@
# Deploying the Capsule Operator
Use the Capsule Operator for easily implementing, managing, and maintaining mutitenancy and access control in Kubernetes.
## Requirements
* [Helm 3](https://github.com/helm/helm/releases) is required when installing the Capsule Operator chart. Follow Helms official [steps](https://helm.sh/docs/intro/install/) for installing helm on your particular operating system.
* A Kubernetes cluster 1.16+ with following [Admission Controllers](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/) enabled:
* PodNodeSelector
* LimitRanger
* ResourceQuota
* MutatingAdmissionWebhook
* ValidatingAdmissionWebhook
* A [`kubeconfig`](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) file accessing the Kubernetes cluster with cluster admin permissions.
## Quick Start
The Capsule Operator Chart can be used to instantly deploy the Capsule Operator on your Kubernetes cluster.
1. Add this repository:
$ helm repo add clastix https://clastix.github.io/charts
2. Install the Chart:
$ helm install capsule capsule -n capsule-system
3. Show the status:
$ helm status capsule -n capsule-system
4. Upgrade the Chart
$ helm upgrade capsule -n capsule-system
5. Uninstall the Chart
$ helm uninstall capsule -n capsule-system
## Customize the installation
There are two methods for specifying overrides of values during chart installation: `--values` and `--set`.
The `--values` option is the preferred method because it allows you to keep your overrides in a YAML file, rather than specifying them all on the command line. Create a copy of the YAML file `values.yaml` and add your overrides to it.
Specify your overrides file when you install the chart:
$ helm install capsule capsule-helm-chart --values myvalues.yaml -n capsule-system
The values in your overrides file `myvalues.yaml` will override their counterparts in the charts values.yaml file. Any values in `values.yaml` that werent overridden will keep their defaults.
If you only need to make minor customizations, you can specify them on the command line by using the `--set` option. For example:
$ helm install capsule capsule-helm-chart --set force_tenant_prefix=false -n capsule-system
Here the values you can override:
Parameter | Description | Default
--- | --- | ---
`manager.options.logLevel` | Set the log verbosity of the controller with a value from 1 to 10.| `4`
`manager.options.forceTenantPrefix` | Boolean, enforces the Tenant owner, during Namespace creation, to name it using the selected Tenant name as prefix, separated by a dash | `false`
`manager.options.capsuleUserGroup` | Override the Capsule user group | `capsule.clastix.io`
`manager.options.protectedNamespaceRegex` | If specified, disallows creation of namespaces matching the passed regexp | `null`
`manager.image.repository` | Set the image repository of the controller. | `quay.io/clastix/capsule`
`manager.image.tag` | Overrides the image tag whose default is the chart. `appVersion` | `null`
`manager.image.pullPolicy` | Set the image pull policy. | `IfNotPresent`
`manager.resources.requests/cpu` | Set the CPU requests assigned to the controller. | `200m`
`manager.resources.requests/memory` | Set the memory requests assigned to the controller. | `128Mi`
`manager.resources.limits/cpu` | Set the CPU limits assigned to the controller. | `200m`
`manager.resources.limits/cpu` | Set the memory limits assigned to the controller. | `128Mi`
`proxy.image.repository` | Set the image repository of the rbac proxy. | `gcr.io/kubebuilder/kube-rbac-proxy`
`proxy.image.tag` | Set the image tag of the rbac proxy. | `v0.5.0`
`proxy.image.pullPolicy` | Set the image pull policy. | `IfNotPresent`
`proxy.resources.requests/cpu` | Set the CPU requests assigned to the rbac proxy. | `10m`
`proxy.resources.requests/memory` | Set the memory requests assigned to the rbac proxy. | `64Mi`
`proxy.resources.limits/cpu` | Set the CPU limits assigned to the rbac proxy. | `100m`
`proxy.resources.limits/cpu` | Set the memory limits assigned to the rbac proxy. | `128Mi`
`mutatingWebhooksTimeoutSeconds` | Timeout in seconds for mutating webhooks. | `30`
`validatingWebhooksTimeoutSeconds` | Timeout in seconds for validating webhooks. | `30`
`imagePullSecrets` | Configuration for `imagePullSecrets` so that you can use a private images registry. | `[]`
`serviceAccount.create` | Specifies whether a service account should be created. | `true`
`serviceAccount.annotations` | Annotations to add to the service account. | `{}`
`serviceAccount.name` | The name of the service account to use. If not set and `serviceAccount.create=true`, a name is generated using the fullname template | `capsule`
`podAnnotations` | Annotations to add to the Capsule pod. | `{}`
`priorityClassName` | Set the priority class name of the Capsule pod. | `null`
`nodeSelector` | Set the node selector for the Capsule pod. | `{}`
`tolerations` | Set list of tolerations for the Capsule pod. | `[]`
`replicaCount` | Set the replica count for Capsule pod. | `1`
`affinity` | Set affinity rules for the Capsule pod. | `{}`
`podSecurityPolicy.enabled` | Specify if a Pod Security Policy must be created. | `false`
## Created resources
This Helm Chart cretes the following Kubernetes resources in the release namespace:
* Capsule Namespace
* Capsule Operator Deployment
* Capsule Service
* CA Secret
* Certfificate Secret
* Tenant Custom Resource Definition
* MutatingWebHookConfiguration
* ValidatingWebHookConfiguration
* RBAC Cluster Roles
* Metrics Service
And optionally, depending on the values set:
* Capsule ServiceAccount
* PodSecurityPolicy
* RBAC ClusterRole and RoleBinding for pod security policy
## Notes on installing Custom Resource Definitions with Helm3
Capsule, as many other add-ons, defines its own set of Custom Resource Definitions (CRDs). Helm3 removed the old CRDs installation method for a more simple methodology. In the Helm Chart, there is now a special directory called `crds` to hold the CRDs. These CRDs are not templated, but will be installed by default when running a `helm install` for the chart. If the CRDs already exist (for example, you already executed `helm install`), it will be skipped with a warning. When you wish to skip the CRDs installation, and do not see the warning, you can pass the `--skip-crds` flag to the `helm install` command.
## More
See Capsule [use cases](https://github.com/clastix/capsule/blob/master/use_cases.md) for more information about how to use Capsule.

View File

@@ -0,0 +1,839 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.0
creationTimestamp: null
name: tenants.capsule.clastix.io
spec:
additionalPrinterColumns:
- JSONPath: .spec.namespaceQuota
description: The max amount of Namespaces can be created
name: Namespace quota
type: integer
- JSONPath: .status.size
description: The total amount of Namespaces in use
name: Namespace count
type: integer
- JSONPath: .spec.owner.name
description: The assigned Tenant owner
name: Owner name
type: string
- JSONPath: .spec.owner.kind
description: The assigned Tenant owner kind
name: Owner kind
type: string
- JSONPath: .spec.nodeSelector
description: Node Selector applied to Pods
name: Node selector
type: string
- JSONPath: .metadata.creationTimestamp
description: Age
name: Age
type: date
group: capsule.clastix.io
names:
kind: Tenant
listKind: TenantList
plural: tenants
shortNames:
- tnt
singular: tenant
scope: Cluster
subresources:
status: {}
validation:
openAPIV3Schema:
description: Tenant is the Schema for the tenants API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: TenantSpec defines the desired state of Tenant
properties:
containerRegistries:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
additionalRoleBindings:
items:
properties:
clusterRoleName:
type: string
subjects:
description: kubebuilder:validation:Minimum=1
items:
description: Subject contains a reference to the object or user
identities a role binding applies to. This can either hold
a direct API object reference, or a value for non-objects
such as user and group names.
properties:
apiGroup:
description: APIGroup holds the API group of the referenced
subject. Defaults to "" for ServiceAccount subjects. Defaults
to "rbac.authorization.k8s.io" for User and Group subjects.
type: string
kind:
description: Kind of object being referenced. Values defined
by this API group are "User", "Group", and "ServiceAccount".
If the Authorizer does not recognized the kind value,
the Authorizer should report an error.
type: string
name:
description: Name of the object being referenced.
type: string
namespace:
description: Namespace of the referenced object. If the
object kind is non-namespace, such as "User" or "Group",
and this value is not empty the Authorizer should report
an error.
type: string
required:
- kind
- name
type: object
type: array
required:
- clusterRoleName
- subjects
type: object
type: array
ingressClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
limitRanges:
items:
description: LimitRangeSpec defines a min/max usage limit for resources
that match on kind.
properties:
limits:
description: Limits is the list of LimitRangeItem objects that
are enforced.
items:
description: LimitRangeItem defines a min/max usage limit for
any resource that matches on kind.
properties:
default:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Default resource requirement limit value by
resource name if resource limit is omitted.
type: object
defaultRequest:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: DefaultRequest is the default resource requirement
request value by resource name if resource request is
omitted.
type: object
max:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Max usage constraints on this kind by resource
name.
type: object
maxLimitRequestRatio:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: MaxLimitRequestRatio if specified, the named
resource must have a request and limit that are both non-zero
where limit divided by request is less than or equal to
the enumerated value; this represents the max burst for
the named resource.
type: object
min:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: Min usage constraints on this kind by resource
name.
type: object
type:
description: Type of resource that this limit applies to.
type: string
required:
- type
type: object
type: array
required:
- limits
type: object
type: array
namespaceQuota:
minimum: 1
type: integer
namespacesMetadata:
properties:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
type: object
networkPolicies:
items:
description: NetworkPolicySpec provides the specification of a NetworkPolicy
properties:
egress:
description: List of egress rules to be applied to the selected
pods. Outgoing traffic is allowed if there are no NetworkPolicies
selecting the pod (and cluster policy otherwise allows the traffic),
OR if the traffic matches at least one egress rule across all
of the NetworkPolicy objects whose podSelector matches the pod.
If this field is empty then this NetworkPolicy limits all outgoing
traffic (and serves solely to ensure that the pods it selects
are isolated by default). This field is beta-level in 1.8
items:
description: NetworkPolicyEgressRule describes a particular
set of traffic that is allowed out of pods matched by a NetworkPolicySpec's
podSelector. The traffic must match both ports and to. This
type is beta-level in 1.8
properties:
ports:
description: List of destination ports for outgoing traffic.
Each item in this list is combined using a logical OR.
If this field is empty or missing, this rule matches all
ports (traffic not restricted by port). If this field
is present and contains at least one item, then this rule
allows traffic only if the traffic matches at least one
port in the list.
items:
description: NetworkPolicyPort describes a port to allow
traffic on
properties:
port:
anyOf:
- type: integer
- type: string
description: The port on the given protocol. This
can either be a numerical or named port on a pod.
If this field is not provided, this matches all
port names and numbers.
x-kubernetes-int-or-string: true
protocol:
description: The protocol (TCP, UDP, or SCTP) which
traffic must match. If not specified, this field
defaults to TCP.
type: string
type: object
type: array
to:
description: List of destinations for outgoing traffic of
pods selected for this rule. Items in this list are combined
using a logical OR operation. If this field is empty or
missing, this rule matches all destinations (traffic not
restricted by destination). If this field is present and
contains at least one item, this rule allows traffic only
if the traffic matches at least one item in the to list.
items:
description: NetworkPolicyPeer describes a peer to allow
traffic to/from. Only certain combinations of fields
are allowed
properties:
ipBlock:
description: IPBlock defines policy on a particular
IPBlock. If this field is set then neither of the
other fields can be.
properties:
cidr:
description: CIDR is a string representing the
IP Block Valid examples are "192.168.1.1/24"
or "2001:db9::/64"
type: string
except:
description: Except is a slice of CIDRs that should
not be included within an IP Block Valid examples
are "192.168.1.1/24" or "2001:db9::/64" Except
values will be rejected if they are outside
the CIDR range
items:
type: string
type: array
required:
- cidr
type: object
namespaceSelector:
description: "Selects Namespaces using cluster-scoped
labels. This field follows standard label selector
semantics; if present but empty, it selects all
namespaces. \n If PodSelector is also set, then
the NetworkPolicyPeer as a whole selects the Pods
matching PodSelector in the Namespaces selected
by NamespaceSelector. Otherwise it selects all Pods
in the Namespaces selected by NamespaceSelector."
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are
ANDed.
items:
description: A label selector requirement is
a selector that contains values, a key, and
an operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If
the operator is Exists or DoesNotExist,
the values array must be empty. This array
is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value".
The requirements are ANDed.
type: object
type: object
podSelector:
description: "This is a label selector which selects
Pods. This field follows standard label selector
semantics; if present but empty, it selects all
pods. \n If NamespaceSelector is also set, then
the NetworkPolicyPeer as a whole selects the Pods
matching PodSelector in the Namespaces selected
by NamespaceSelector. Otherwise it selects the Pods
matching PodSelector in the policy's own Namespace."
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are
ANDed.
items:
description: A label selector requirement is
a selector that contains values, a key, and
an operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If
the operator is Exists or DoesNotExist,
the values array must be empty. This array
is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value".
The requirements are ANDed.
type: object
type: object
type: object
type: array
type: object
type: array
ingress:
description: List of ingress rules to be applied to the selected
pods. Traffic is allowed to a pod if there are no NetworkPolicies
selecting the pod (and cluster policy otherwise allows the traffic),
OR if the traffic source is the pod's local node, OR if the
traffic matches at least one ingress rule across all of the
NetworkPolicy objects whose podSelector matches the pod. If
this field is empty then this NetworkPolicy does not allow any
traffic (and serves solely to ensure that the pods it selects
are isolated by default)
items:
description: NetworkPolicyIngressRule describes a particular
set of traffic that is allowed to the pods matched by a NetworkPolicySpec's
podSelector. The traffic must match both ports and from.
properties:
from:
description: List of sources which should be able to access
the pods selected for this rule. Items in this list are
combined using a logical OR operation. If this field is
empty or missing, this rule matches all sources (traffic
not restricted by source). If this field is present and
contains at least one item, this rule allows traffic only
if the traffic matches at least one item in the from list.
items:
description: NetworkPolicyPeer describes a peer to allow
traffic to/from. Only certain combinations of fields
are allowed
properties:
ipBlock:
description: IPBlock defines policy on a particular
IPBlock. If this field is set then neither of the
other fields can be.
properties:
cidr:
description: CIDR is a string representing the
IP Block Valid examples are "192.168.1.1/24"
or "2001:db9::/64"
type: string
except:
description: Except is a slice of CIDRs that should
not be included within an IP Block Valid examples
are "192.168.1.1/24" or "2001:db9::/64" Except
values will be rejected if they are outside
the CIDR range
items:
type: string
type: array
required:
- cidr
type: object
namespaceSelector:
description: "Selects Namespaces using cluster-scoped
labels. This field follows standard label selector
semantics; if present but empty, it selects all
namespaces. \n If PodSelector is also set, then
the NetworkPolicyPeer as a whole selects the Pods
matching PodSelector in the Namespaces selected
by NamespaceSelector. Otherwise it selects all Pods
in the Namespaces selected by NamespaceSelector."
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are
ANDed.
items:
description: A label selector requirement is
a selector that contains values, a key, and
an operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If
the operator is Exists or DoesNotExist,
the values array must be empty. This array
is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value".
The requirements are ANDed.
type: object
type: object
podSelector:
description: "This is a label selector which selects
Pods. This field follows standard label selector
semantics; if present but empty, it selects all
pods. \n If NamespaceSelector is also set, then
the NetworkPolicyPeer as a whole selects the Pods
matching PodSelector in the Namespaces selected
by NamespaceSelector. Otherwise it selects the Pods
matching PodSelector in the policy's own Namespace."
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are
ANDed.
items:
description: A label selector requirement is
a selector that contains values, a key, and
an operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If
the operator is Exists or DoesNotExist,
the values array must be empty. This array
is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value".
The requirements are ANDed.
type: object
type: object
type: object
type: array
ports:
description: List of ports which should be made accessible
on the pods selected for this rule. Each item in this
list is combined using a logical OR. If this field is
empty or missing, this rule matches all ports (traffic
not restricted by port). If this field is present and
contains at least one item, then this rule allows traffic
only if the traffic matches at least one port in the list.
items:
description: NetworkPolicyPort describes a port to allow
traffic on
properties:
port:
anyOf:
- type: integer
- type: string
description: The port on the given protocol. This
can either be a numerical or named port on a pod.
If this field is not provided, this matches all
port names and numbers.
x-kubernetes-int-or-string: true
protocol:
description: The protocol (TCP, UDP, or SCTP) which
traffic must match. If not specified, this field
defaults to TCP.
type: string
type: object
type: array
type: object
type: array
podSelector:
description: Selects the pods to which this NetworkPolicy object
applies. The array of ingress rules is applied to any pods selected
by this field. Multiple network policies can select the same
set of pods. In this case, the ingress rules for each are combined
additively. This field is NOT optional and follows standard
label selector semantics. An empty podSelector matches all pods
in this namespace.
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: A label selector requirement is a selector
that contains values, a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn,
Exists and DoesNotExist.
type: string
values:
description: values is an array of string values. If
the operator is In or NotIn, the values array must
be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value} pairs. A
single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field is "key",
the operator is "In", and the values array contains only
"value". The requirements are ANDed.
type: object
type: object
policyTypes:
description: List of rule types that the NetworkPolicy relates
to. Valid options are "Ingress", "Egress", or "Ingress,Egress".
If this field is not specified, it will default based on the
existence of Ingress or Egress rules; policies that contain
an Egress section are assumed to affect Egress, and all policies
(whether or not they contain an Ingress section) are assumed
to affect Ingress. If you want to write an egress-only policy,
you must explicitly specify policyTypes [ "Egress" ]. Likewise,
if you want to write a policy that specifies that no egress
is allowed, you must specify a policyTypes value that include
"Egress" (since such a policy would not include an Egress section
and would otherwise default to just [ "Ingress" ]). This field
is beta-level in 1.8
items:
description: Policy Type string describes the NetworkPolicy
type This type is beta-level in 1.8
type: string
type: array
required:
- podSelector
type: object
type: array
nodeSelector:
additionalProperties:
type: string
type: object
owner:
description: OwnerSpec defines tenant owner name and kind
properties:
kind:
enum:
- User
- Group
type: string
name:
type: string
required:
- kind
- name
type: object
resourceQuotas:
items:
description: ResourceQuotaSpec defines the desired hard limits to
enforce for Quota.
properties:
hard:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'hard is the set of desired hard limits for each
named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/'
type: object
scopeSelector:
description: scopeSelector is also a collection of filters like
scopes that must match each object tracked by a quota but expressed
using ScopeSelectorOperator in combination with possible values.
For a resource to match, both scopes AND scopeSelector (if specified
in spec), must be matched.
properties:
matchExpressions:
description: A list of scope selector requirements by scope
of the resources.
items:
description: A scoped-resource selector requirement is a
selector that contains values, a scope name, and an operator
that relates the scope name and values.
properties:
operator:
description: Represents a scope's relationship to a
set of values. Valid operators are In, NotIn, Exists,
DoesNotExist.
type: string
scopeName:
description: The name of the scope that the selector
applies to.
type: string
values:
description: An array of string values. If the operator
is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during
a strategic merge patch.
items:
type: string
type: array
required:
- operator
- scopeName
type: object
type: array
type: object
scopes:
description: A collection of filters that must match each object
tracked by a quota. If not specified, the quota matches all
objects.
items:
description: A ResourceQuotaScope defines a filter that must
match each object tracked by a quota
type: string
type: array
type: object
type: array
servicesMetadata:
properties:
additionalAnnotations:
additionalProperties:
type: string
nullable: true
type: object
additionalLabels:
additionalProperties:
type: string
nullable: true
type: object
required:
- additionalAnnotations
- additionalLabels
type: object
storageClasses:
properties:
allowed:
items:
type: string
nullable: true
type: array
allowedRegex:
nullable: true
type: string
required:
- allowed
- allowedRegex
type: object
required:
- ingressClasses
- limitRanges
- namespaceQuota
- owner
- storageClasses
type: object
status:
description: TenantStatus defines the observed state of Tenant
properties:
groups:
items:
type: string
type: array
namespaces:
items:
type: string
type: array
size:
type: integer
users:
items:
type: string
type: array
required:
- size
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,19 @@
- Capsule Operator Helm Chart deployed:
# Check the capsule logs
$ kubectl logs -f deployment/{{ template "capsule.fullname" . }}-controller-manager -c manager -n {{ .Release.Namespace }}
# Check the capsule logs
$ kubectl logs -f deployment/{{ template "capsule.fullname" . }}-controller-manager -c manager -n{{ .Release.Namespace }}
- Manage this chart:
# Upgrade Capsule
$ helm upgrade {{ .Release.Name }} -f <values.yaml> capsule -n {{ .Release.Namespace }}
# Show this status again
$ helm status {{ .Release.Name }} -n {{ .Release.Namespace }}
# Uninstall Capsule
$ helm uninstall {{ .Release.Name }} -n {{ .Release.Namespace }}

View File

@@ -0,0 +1,69 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "capsule.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "capsule.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "capsule.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "capsule.labels" -}}
helm.sh/chart: {{ include "capsule.chart" . }}
{{ include "capsule.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "capsule.selectorLabels" -}}
app.kubernetes.io/name: {{ include "capsule.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "capsule.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "capsule.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create the fully-qualified Docker image to use
*/}}
{{- define "capsule.fullyQualifiedDockerImage" -}}
{{- printf "%s:%s" .Values.manager.image.repository ( .Values.manager.image.tag | default (printf "v%s" .Chart.AppVersion) ) -}}
{{- end }}

View File

@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
labels:
{{- include "capsule.labels" . | nindent 4 }}
name: {{ include "capsule.fullname" . }}-ca
data:

View File

@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
labels:
{{- include "capsule.labels" . | nindent 4 }}
name: {{ include "capsule.fullname" . }}-tls
data:

View File

@@ -0,0 +1,97 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "capsule.fullname" . }}-controller-manager
labels:
{{- include "capsule.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "capsule.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "capsule.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "capsule.serviceAccountName" . }}
priorityClassName: {{ .Values.priorityClassName }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: cert
secret:
defaultMode: 420
secretName: {{ include "capsule.fullname" . }}-tls
containers:
- name: manager
command:
- /manager
args:
- --metrics-addr=127.0.0.1:8080
- --enable-leader-election
- --zap-log-level={{ default 4 .Values.manager.options.logLevel }}
{{ if .Values.manager.options.forceTenantPrefix }}- --force-tenant-prefix={{ .Values.manager.options.forceTenantPrefix }}{{ end }}
{{ if .Values.manager.options.capsuleUserGroup }}- --capsule-user-group={{ .Values.manager.options.capsuleUserGroup }}{{ end }}
{{ if .Values.manager.options.protectedNamespaceRegex }}- --protected-namespace-regex={{ .Values.manager.options.protectedNamespaceRegex }}{{ end }}
image: {{ include "capsule.fullyQualifiedDockerImage" . }}
imagePullPolicy: {{ .Values.manager.image.pullPolicy }}
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: webhook-server
containerPort: 9443
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: 10080
readinessProbe:
httpGet:
path: /readyz
port: 10080
volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
resources:
{{- toYaml .Values.manager.resources | nindent 12 }}
securityContext:
allowPrivilegeEscalation: false
- name: kube-rbac-proxy
image: {{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }}
imagePullPolicy: IfNotPresent
args:
- --secure-listen-address=0.0.0.0:8443
- --upstream=http://127.0.0.1:8080/
- --logtostderr=true
- --v=10
ports:
- containerPort: 8443
name: https
protocol: TCP
resources:
{{- toYaml .Values.proxy.resources | nindent 12 }}
securityContext:
allowPrivilegeEscalation: false

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "capsule.fullname" . }}-controller-manager-metrics-service
labels:
{{- include "capsule.labels" . | nindent 4 }}
spec:
ports:
- port: 8443
name: https
protocol: TCP
targetPort: https
selector:
{{- include "capsule.selectorLabels" . | nindent 4 }}
sessionAffinity: None
type: ClusterIP

View File

@@ -0,0 +1,34 @@
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: {{ include "capsule.fullname" . }}-mutating-webhook-configuration
labels:
{{- include "capsule.labels" . | nindent 4 }}
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /mutate-v1-namespace-owner-reference
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: owner.namespace.capsule.clastix.io
namespaceSelector: {}
objectSelector: {}
reinvocationPolicy: Never
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- namespaces
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.mutatingWebhooksTimeoutSeconds }}

View File

@@ -0,0 +1,54 @@
{{- if .Values.podSecurityPolicy.enabled }}
kind: PodSecurityPolicy
apiVersion: policy/v1beta1
metadata:
name: {{ include "capsule.fullname" . }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
spec:
fsGroup:
rule: RunAsAny
hostPorts:
- max: 0
min: 0
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- secret
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-use-psp
labels:
{{- include "capsule.labels" . | nindent 4 }}
rules:
- apiGroups:
- extensions
resources:
- podsecuritypolicies
resourceNames:
- {{ include "capsule.fullname" . }}
verbs:
- use
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-use-psp
labels:
{{- include "capsule.labels" . | nindent 4 }}
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "capsule.fullname" . }}-use-psp
subjects:
- apiGroup: ""
kind: ServiceAccount
name: {{ include "capsule.serviceAccountName" . }}
{{- end }}

View File

@@ -0,0 +1,35 @@
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
annotations:
# This is what defines this resource as a hook. Without this line, the
# job is considered part of the release.
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
restartPolicy: Never
containers:
- name: post-install-job
image: "bitnami/kubectl:1.18"
command: ["sh", "-c", "while [ -z $$(kubectl -n $NAMESPACE get secret capsule-tls -o jsonpath='{.data.tls\\.crt}') ]; do echo 'waiting Capsule to be up and running...' && sleep 5; done"]
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
serviceAccountName: {{ include "capsule.serviceAccountName" . }}

View File

@@ -0,0 +1,37 @@
{{- $deploymentName := printf "%s-controller-manager" (include "capsule.fullname" .) -}}
{{- $cmd := printf "kubectl scale deployment -n $NAMESPACE %s --replicas 0 && kubectl delete clusterroles.rbac.authorization.k8s.io capsule-namespace-deleter capsule-namespace-provisioner --ignore-not-found && kubectl delete clusterrolebindings.rbac.authorization.k8s.io capsule-namespace-provisioner --ignore-not-found" $deploymentName -}}
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
annotations:
# This is what defines this resource as a hook. Without this line, the
# job is considered part of the release.
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
restartPolicy: Never
containers:
- name: pre-delete-job
image: "bitnami/kubectl:1.18"
command: ["sh", "-c", {{ $cmd | quote }}]
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
serviceAccountName: {{ include "capsule.serviceAccountName" . }}

View File

@@ -0,0 +1,61 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-proxy-role
labels:
{{- include "capsule.labels" . | nindent 4 }}
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-metrics-reader
labels:
{{- include "capsule.labels" . | nindent 4 }}
rules:
- nonResourceURLs:
- /metrics
verbs:
- get
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-proxy-rolebinding
labels:
{{- include "capsule.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "capsule.fullname" . }}-proxy-role
subjects:
- kind: ServiceAccount
name: {{ include "capsule.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "capsule.fullname" . }}-manager-rolebinding
labels:
{{- include "capsule.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: {{ include "capsule.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}

View File

@@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "capsule.serviceAccountName" . }}
labels:
{{- include "capsule.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,235 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: {{ include "capsule.fullname" . }}-validating-webhook-configuration
labels:
{{- include "capsule.labels" . | nindent 4 }}
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-ingress
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: ingress-v1beta1.capsule.clastix.io
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
objectSelector: {}
rules:
- apiGroups:
- networking.k8s.io
- extensions
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- ingresses
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-ingress
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: ingress-v1.capsule.clastix.io
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
objectSelector: {}
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validate-v1-namespace-quota
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: quota.namespace.capsule.clastix.io
namespaceSelector: {}
objectSelector: {}
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- namespaces
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-v1-network-policy
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: validating.network-policy.capsule.clastix.io
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
objectSelector: {}
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
- DELETE
resources:
- networkpolicies
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-v1-pvc
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: pvc.capsule.clastix.io
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
objectSelector: {}
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- persistentvolumeclaims
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-v1-tenant
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: tenant.capsule.clastix.io
namespaceSelector: {}
objectSelector: {}
rules:
- apiGroups:
- capsule.clastix.io
apiVersions:
- v1alpha1
operations:
- CREATE
resources:
- tenants
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-v1-namespace-tenant-prefix
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: prefix.namespace.capsule.clastix.io
namespaceSelector: {}
objectSelector: {}
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- namespaces
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: Cg==
service:
name: {{ include "capsule.fullname" . }}-webhook-service
namespace: {{ .Release.Namespace }}
path: /validating-v1-registry
port: 443
failurePolicy: Ignore
matchPolicy: Exact
name: pod.capsule.clastix.io
namespaceSelector:
matchExpressions:
- key: capsule.clastix.io/tenant
operator: Exists
objectSelector: {}
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: {{ .Values.validatingWebhooksTimeoutSeconds }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "capsule.fullname" . }}-webhook-service
labels:
{{- include "capsule.labels" . | nindent 4 }}
spec:
ports:
- port: 443
name: https
protocol: TCP
targetPort: 9443
selector:
{{- include "capsule.selectorLabels" . | nindent 4 }}
sessionAffinity: None
type: ClusterIP

View File

@@ -0,0 +1,54 @@
# Default values for capsule.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
manager:
image:
repository: quay.io/clastix/capsule
pullPolicy: IfNotPresent
tag: ''
# Additional Capsule options
options:
logLevel: '4'
forceTenantPrefix:
capsuleUserGroup:
protectedNamespaceRegex:
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 200m
memory: 128Mi
proxy:
image:
repository: gcr.io/kubebuilder/kube-rbac-proxy
pullPolicy: IfNotPresent
tag: "v0.5.0"
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi
mutatingWebhooksTimeoutSeconds: 30
validatingWebhooksTimeoutSeconds: 30
imagePullSecrets: []
serviceAccount:
create: true
annotations: {}
name: "capsule"
podAnnotations: {}
priorityClassName: '' #system-cluster-critical
nodeSelector: {}
# node-role.kubernetes.io/master: ""
tolerations: []
#- key: CriticalAddonsOnly
# operator: Exists
#- effect: NoSchedule
# key: node-role.kubernetes.io/master
replicaCount: 1
affinity: {}
podSecurityPolicy:
enabled: false

View File

@@ -104,11 +104,11 @@ func ModifyCapsuleManagerPodArgs(args []string) {
pl := &corev1.PodList{}
Eventually(func() []corev1.Pod {
Expect(k8sClient.List(context.TODO(), pl, client.MatchingLabels{"control-plane": "controller-manager"})).Should(Succeed())
Expect(k8sClient.List(context.TODO(), pl, client.MatchingLabels{"app.kubernetes.io/instance": "capsule"})).Should(Succeed())
return pl.Items
}, podRecreationTimeoutInterval, defaultPollInterval).Should(HaveLen(2))
Eventually(func() []corev1.Pod {
Expect(k8sClient.List(context.TODO(), pl, client.MatchingLabels{"control-plane": "controller-manager"})).Should(Succeed())
Expect(k8sClient.List(context.TODO(), pl, client.MatchingLabels{"app.kubernetes.io/instance": "capsule"})).Should(Succeed())
return pl.Items
}, podRecreationTimeoutInterval, defaultPollInterval).Should(HaveLen(1))
// had to add sleep in order to manager be started

1
go.mod
View File

@@ -8,6 +8,7 @@ require (
github.com/onsi/ginkgo v1.14.1
github.com/onsi/gomega v1.10.2
github.com/stretchr/testify v1.5.1
go.uber.org/zap v1.15.0
gomodules.xyz/jsonpatch/v2 v2.1.0
k8s.io/api v0.19.3
k8s.io/apimachinery v0.19.3