Add Limits & Isolation
There are 3 concepts in Loft that allow you to restrict or limit a user's account within a cluster:
- Account Quotas define resource limits for an account across all namespaces of an account within a cluster1
- Space Creation Settings define max number of namespaces a user can create, sleep mode and other options
- Templates which can be enforced when creating a namespace (e.g. NetworkPolicies, LimitRanges etc.)
Create Account Quotas
Account quotas are like Kubernetes resource quotas but they are aggregated across namespaces, i.e. if you specify a limit such as limits.memory: 8Gi
, the user can use up to 8Gi of memory across all the spaces owned by the account that the quota is defined for.
Account quotas can be created for any existing cluster account and as part of the process of updating and creating cluster accounts when using the UI.
- UI
- kubectl
Create file quota.yaml
:
apiVersion: config.kiosk.sh/v1alpha1
kind: AccountQuota
metadata:
name: johns-quota
spec:
account: johns-account
quota:
hard:
limits.cpu: "2"
limits.memory: 8Gi
Create the account quota using kubectl
:
# IMPORTANT: Make sure to switch to the context of the connected cluster!
kubectl apply -f quota.yaml
Space Limit & Metadata
While account quotas are mainly concerning resources that users are creating inside their spaces, you can also restrict the creation of spaces itself.
- UI
- kubectl
If you open the form to create or edit a cluster account, you will see the section "Space Creation Settings" which provides the following options:
- Space Limit to set a maximum number of namespaces for this account
- Timeout for Automatic Sleep Mode to enable automatic sleep mode after a certain period of inactivity
- Enforce Templates to specify templates which will be instantiated when creating a space with this account
- Labels & Annotations to specify metadata which should be set when creating a space3
Create file account.yaml
:
apiVersion: tenancy.kiosk.sh/v1alpha1
kind: Account
metadata:
name: johns-account
spec:
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: john # References the `spec.subject` defined in the User object
space:
clusterRole: loft-cluster-space-default
limit: 5
spaceTemplate:
metadata:
creationTimestamp: null
labels:
some-label: some-value
annotations:
# automatically start sleep mode after 1h
sleepmode.loft.sh/sleep-after: '3600'
Create the account using kubectl
:
# IMPORTANT: Make sure to switch to the context of the connected cluster!
kubectl apply -f account.yaml
Templates
Templates define Kubernetes manifests or Helm charts that you want to deploy to every namespace that a user creates when using their cluster account. This allows you to isolate namespaces and enforce security policies for each namespace.
Create Templates
Loft provides 2 default templates which will be added to each connected cluster:
loft-limit-range
for an example of a LimitRangeloft-network-policy
for an example of a NetworkPolicy
You can edit these templates if you want to or you can create your own templates as shown below.
- UI
- kubectl
Create file template.yaml
:
apiVersion: config.kiosk.sh/v1alpha1
kind: Template
metadata:
creationTimestamp: "2020-06-02T19:30:48Z"
generation: 1
name: network-isolation
resourceVersion: "705504"
selfLink: /apis/config.kiosk.sh/v1alpha1/templates/network-isolation
uid: efc3e5c0-7f35-4f83-8987-6258bfd33dec
resources:
manifests:
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-allow-same-namespace
spec:
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-allow-internet-access
labels:
# You can also use template parameters such as ${namespace} or ${account}
created-in-namespace: ${namespace}
spec:
ingress:
- {}
podSelector:
matchLabels:
isolation.loft.sh/allow-internet-access: "true"
policyTypes:
- Ingress
Create the template using kubectl
:
# IMPORTANT: Make sure to switch to the context of the connected cluster!
kubectl create -f template.yaml
Enforce Templates
One of the most popular use cases for templates is to ensure cluster security and enforce isolation among users and spaces. However, creating a Template per se does nothing at all if you do not enforce the template.
You can enforce that certain templates are always applied to namespaces when they are being created by adding these templates as part of the "Space Creation Settings" of an account. See the examples below for instructions.
- UI
- kubectl
Create file template.yaml
:
apiVersion: config.kiosk.sh/v1alpha1
kind: Template
metadata:
creationTimestamp: "2020-06-02T19:30:48Z"
generation: 1
name: network-isolation
resourceVersion: "705504"
selfLink: /apis/config.kiosk.sh/v1alpha1/templates/network-isolation
uid: efc3e5c0-7f35-4f83-8987-6258bfd33dec
resources:
manifests:
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-allow-same-namespace
spec:
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-allow-internet-access
spec:
ingress:
- {}
podSelector:
matchLabels:
isolation.loft.sh/allow-internet-access: "true"
policyTypes:
- Ingress
Create the template using kubectl
:
# IMPORTANT: Make sure to switch to the context of the connected cluster!
kubectl create -f template.yaml
Additional Security
While Templates are great for namespace-level enforcement of security policies, it is stongly recommended to add cluster-wide security resources as well.
One example of such a security resource would be a PodSecurityPolicy
that should be added to each connected cluster. You can use the following example to get started:
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
name: strict-policy
spec:
allowPrivilegeEscalation: false
fsGroup:
rule: RunAsAny
hostPorts:
- max: 0
min: 0
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- secret
- configMap
- emptyDir
- downwardAPI
- persistentVolumeClaim