Bookmark this page

The Project Template and the Self-Provisioner Role

Objectives

  • Configure default quotas, limit ranges, role bindings, and other restrictions for new projects, and the allowed users to self-provision new projects.

Project Creation

Kubernetes provides namespaces to isolate workloads.

Namespace metadata has security implications in clusters. For example, policy controllers might use namespace labels to limit capabilities in a namespace. If users can modify namespaces, then malicious users can modify namespace metadata to override security measures.

Additionally, namespaces are not namespaced. Therefore, granting granular access to namespaces poses some challenges. For example, with Kubernetes role-based access control, you cannot allow users to list a subset of namespaces. However, to allow users to list their namespaces, you must allow them to list all namespaces.

Note

Listing resources and viewing individual resources are different operations. You can grant users permissions to view specific namespaces, but listing namespaces requires a separate permission.

OpenShift introduces projects to improve security and users' experience of working with namespaces. The OpenShift API server adds the Project resource type. When you make a query to list projects, the API server lists namespaces, filters the visible namespaces to your user, and returns the visible namespaces in project format.

Additionally, OpenShift introduces the ProjectRequest resource type. When you create a project request, the OpenShift API server creates a namespace from a template. By using a template, cluster administrators can customize namespace creation. For example, cluster administrators can ensure that new namespaces have specific permissions, resource quotas, or limit ranges.

These features provide self-service management of namespaces. Cluster administrators can allow users to create namespaces without allowing users to modify namespace metadata. Administrators can also customize the creation of namespaces to ensure that namespaces follow organizational requirements.

Planning a Project Template

You can add any namespaced resource to the project template. For example, you can add resources of the following types:

Roles and role bindings

Add roles and role bindings to the template to grant specific permissions in new projects. The default template grants the admin role to the user who requests the project. You can keep this permission or use another similar permission, such as granting the admin role to a group of users. You can also add different permissions, such as more granular permissions over specific resource types.

Resource quotas and limit ranges

Add resource quotas to the project template to ensure that all new projects have resource limits. If you add resource quotas, then creating workloads requires explicit resource limit declarations. Consider adding limit ranges to reduce the effort for workload creation.

Even with quotas in all namespaces, users can create projects to continue adding workloads to a cluster. If this scenario is a concern, then consider adding cluster resource quotas to the cluster.

Network policies

Add network policies to the template to enforce organizational network isolation requirements.

Creating a Project Template

The oc adm create-bootstrap-project-template command prints a template that you can use to create your own project template.

This template has the same behavior as the default project creation in OpenShift. The template adds a role binding that grants the admin cluster role over the new namespace to the user who requests the project.

Project templates use the same template feature as the oc new-app command.

Execute the following command to create a file with an initial template:

[user@host ~]$ oc adm create-bootstrap-project-template -o yaml > file

This initial template has the following content:

apiVersion: template.openshift.io/v1
kind: Template
metadata:
  creationTimestamp: null
  name: project-request
objects: 1
- apiVersion: project.openshift.io/v1 2
  kind: Project
  metadata:
    annotations:
      openshift.io/description: ${PROJECT_DESCRIPTION}
      openshift.io/display-name: ${PROJECT_DISPLAYNAME}
      openshift.io/requester: ${PROJECT_REQUESTING_USER}
    creationTimestamp: null
    name: ${PROJECT_NAME}
  spec: {}
  status: {}
- apiVersion: rbac.authorization.k8s.io/v1 3
  kind: RoleBinding
  metadata:
    creationTimestamp: null
    name: admin
    namespace: ${PROJECT_NAME}
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: admin
  subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: ${PROJECT_ADMIN_USER}
parameters: 4
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_DESCRIPTION
- name: PROJECT_ADMIN_USER
- name: PROJECT_REQUESTING_USER

1

The resources that OpenShift creates in new namespaces

2

The project resource

3

A role binding to grant the admin role to the requesting user

4

The parameters that are available to the template

When a user requests a project, OpenShift replaces the ${VARIABLE} syntax with the parameters of the project request, and creates the objects in the objects key.

Modify the object list to add the required resources for new namespaces.

The YAML output of oc commands that return lists of objects is formatted similarly to the template objects key.

[user@host ~]$ oc get limitrange,resourcequota -o yaml
apiVersion: v1
items:
- apiVersion: v1
  kind: LimitRange
  metadata:
    creationTimestamp: "2024-01-31T17:48:23Z"
    name: example
    namespace: example
    resourceVersion: "881771"
    uid: d0c19c60-00a9-4028-acc5-22680f1ea658
  spec:
    limits:
    - default:
        cpu: 500m
        memory: 512Mi
      defaultRequest:
        cpu: 250m
        memory: 256Mi
      max:
        cpu: "1"
        memory: 1Gi
      min:
        cpu: 125m
        memory: 128Mi
      type: Container
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    creationTimestamp: "2024-01-31T17:48:04Z"
    name: example
    namespace: example
    resourceVersion: "881648"
    uid: 108f0771-dc11-4289-ae76-6514d58bbece
  spec:
    hard:
      count/pods: "1"
  status:
...output omitted...
kind: List
metadata:
  resourceVersion: ""

Some common resources in project templates, such as quotas, do not have strict validation. For example, if the previous template contains the count/pod text instead of the count/pods text, then the quota does not work. You can create the project template, and new namespaces contain the quota, but the quota does not have an effect. To define a project template and to reduce the risk of errors, you can perform the following steps:

  • Create a namespace.

  • Create your chosen resources and test until you get the intended behavior.

  • List the resources in YAML format.

  • Edit the resource listing to ensure that the definitions create the correct resources. For example, remove elements that do not apply to resource creation, such as the creationTimestamp or status keys.

  • Replace the namespace name with the ${PROJECT_NAME} value.

  • Add the list of resources to the project template that the oc adm create-bootstrap-project-template command generates.

Note

Extracting a resource definition from an existing resource might not always produce correct results. Besides including elements that do not apply to resource creation, existing definitions might contain attributes that generate unexpected behavior. For example, a controller might add to resources some annotations that are unsuitable for template definitions.

Even after testing the resources in a test namespace, always verify that the projects that are created from your template have only the required behavior.

Use the oc create command to create the template resource in the openshift-config namespace:

[user@host ~]$ oc create -f template -n openshift-config
template.template.openshift.io/project-request created

Configuring the Project Template

Update the projects.config.openshift.io/cluster resource to use the new project template. Modify the spec section. By default, the name of the project template is project-request.

apiVersion: config.openshift.io/v1
kind: Project
metadata:
...output omitted...
  name: cluster
...output omitted...
spec:
  projectRequestTemplate:
    name: project-request

A successful update to the projects.config.openshift.io/cluster resource rolls out a new version of the apiserver deployment in the openshift-apiserver namespace. After the new apiserver deployment completes, new projects create the resources in the customized project template.

Note

During the apiserver deployment rollout, API requests can produce unexpected results.

To revert to the original project template, modify the projects.config.openshift.io/cluster resource to clear the spec resource to match the spec: {} format.

Managing Self-provisioning Permissions

Users with the self-provisioner cluster role can create projects. By default, the self-provisioner role is bound to all authenticated users.

Control the binding of the role to limit which users can request new projects.

Important

Remember that users with namespace permissions can create namespaces that do not use the project template.

Use the oc describe command to view the role bindings.

[user@host ~]$ oc describe clusterrolebinding.rbac self-provisioners
Name:         self-provisioners
Labels:       <none>
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
Role:
  Kind:  ClusterRole
  Name:  self-provisioner
Subjects:
  Kind   Name                        Namespace
  ----   ----                        ---------
  Group  system:authenticated:oauth

This role binding has an rbac.authorization.kubernetes.io/autoupdate annotation. This annotation protects roles and bindings from modifications that can interfere with the working of clusters. When the API server starts, the cluster restores resources with this annotation automatically, unless you set the annotation to the false value.

To make changes, disable automatic updates with the annotation, and edit the subjects in the binding.

Important

The oc adm policy remove-cluster-role-from-group command removes the cluster role binding when you remove the last subject.

Use extra caution or avoid this command to manage protected role bindings. The command removes the permission, but only until the API server restarts. Removing the permission permanently after deleting the binding is a lengthier process than changing the subjects.

For example, to disable self-provisioning, execute the following commands:

[user@host ~]$ oc annotate clusterrolebinding/self-provisioners \
  --overwrite rbac.authorization.kubernetes.io/autoupdate=false
clusterrolebinding.rbac.authorization.k8s.io/self-provisioners annotated
[user@host ~]$ oc patch clusterrolebinding.rbac self-provisioners \
  -p '{"subjects": null}'
clusterrolebinding.rbac.authorization.k8s.io/self-provisioners patched

You can also use the oc edit command to modify any value of a resource. The command launches the vi editor to apply your modifications. For example, to change the subject of the role binding from the system:authenticated:oauth group to the provisioners group, execute the followign command:

[user@host ~]$ oc edit clusterrolebinding/self-provisioners
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
...output omitted...
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: self-provisioner
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: provisioners

References

For more information, refer to the Configuring Project Creation section in the Projects chapter in the Red Hat OpenShift Container Platform 4.14 Building Applications documentation at https://access.redhat.com/documentation/en-us/openshift_container_platform/4.14/html-single/building_applications/index#configuring-project-creation

Customizing OpenShift Project Creation

Revision: do280-4.14-08d11e1