Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control API Architecture #59

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
= {controlapi}: Organization

TIP: This resource implements the xref:references/functional-requirements.adoc#_feature_manage_organizations["Manage Organizations"] features.

To circumvent the current limitation of the Kubernetes API to show filtered lists of cluster-scoped resources based on access rights, `Organization` is a virtual resource.

It represents a filtered and formatted list of standard Kubernetes `Namespace` resources which have specific labels and annotations.

It is assumed that the resource `appuio.io/v1/Organization` is used for all operations (create, list, read, update, delete).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are watches and patches not supported?

Suggested change
It is assumed that the resource `appuio.io/v1/Organization` is used for all operations (create, list, read, update, delete).
It is assumed that the resource `appuio.io/v1/Organization` is used for all operations (create, list, read, watch, update, patch, delete).


== Object

.Virtual resource
[source,yaml]
----
apiVersion: appuio.io/v1
kind: Organization
metadata:
name: acme-corp <1>
spec:
displayName: Acme Corp. <2>
----
<1> `metadata.name` from the `Namespace` without the `org`-prefix
<2> Replicates `metadata.annotations.[organization.appuio.io/displayName]` from the `Namespace`

.Original resource
[source,yaml]
----
apiVersion: v1
kind: Namespace
metadata:
name: org-acme-corp <1>
labels:
appuio.io/resource-type: organization <2>
annotations:
organization.appuio.io/displayName: Acme Corp. <3>
----
<1> Prefixed (`org`) name to circumvent possible name collision (e.g. if a company is called "kube-system")
<2> Identify resource type, used by the API server to filter for namespace representing organizations
<3> Reflected in the organization object as `spec.displayName`

== Labels and Annotations

[cols="2,1,1,3",options="header"]
|===
|Name
|Type
|Resource
|Description

|`appuio.io/resource-type`
|label
|`v1/Namespace`
|Identifies the resource type in the scope of the {controlapi}

|`organization.appuio.io/displayName`
|annotation
|`appuio.io/v1/Organization`
|Display name of the organization

|===

== Resource filter

The virtual resource is a filtered view on `Namespaces`.
The filter uses the following heuristic:

* Resource kind = v1/Namespace
* label[appuio.io/resource-type] = organization
* subject is bound to one of the defined `ClusterRole` resources.

== RBAC rules

These are `ClusterRole` resources which are bound to a subject by a namespaced `RoleBinding`:

`org-view`:: View (read only) access to an organization
`org-admin`:: Admin (read / write) access to an organization

Creating organizations can be done by all authenticated users.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
= {controlapi}: Team

TIP: This resource implements the xref:references/functional-requirements.adoc#_feature_manage_teams["Manage Teams"] features.

== Object

[source,yaml]
----
apiVersion: appuio.io/v1
kind: Team
metadata:
name: myteam1
namespace: org-acme-corp
spec:
userRefs: <1>
- max-muster
- demo-user
----
<1> References to one or more `User` objects
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
= {controlapi}: User

TIP: This resource implements the xref:references/functional-requirements.adoc#_feature_personal_settings_per_user["Personal Settings per User"] feature.

== Object

[source,yaml]
----
apiVersion: appuio.io/v1
kind: User
metadata:
name: demo-max
spec:
defaultOrganizationRef: acme-corp <1>
----
<1> Reference to an `Organization` object
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
= {controlapi}: Zone

TIP: This resource implements the xref:references/functional-requirements.adoc#_feature_zones["Manage Zones"] features.

== Object

[source,yaml]
----
apiVersion: appuio.io/v1
kind: Zone
metadata:
name: cloudscale-lpg-0
spec:
displayName: cloudscale.ch LPG 0 <1>
status: <2>
features:
openshift-version: "4.8"
kubernetes-version: "1.21"
sdn: OVN-Kubernetes
console-url: https://console.cloudscale-lpg-0.appuio.cloud/
kubernetes-api-url: https://api.cloudscale-lpg-0.appuio.cloud:6443/
----
<1> {product} instance specific name
<2> Provided by adapter, e.g. by https://syn.tools/[Project Syn Lieutenant]
78 changes: 78 additions & 0 deletions docs/modules/ROOT/pages/references/architecture/control-api.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
= {controlapi} Architecture

This page describes the xref:references/glossary.adoc#_control_api[{controlapi}].
It adheres to the decision taken in xref:explanation/decisions/control-api.adoc[{controlapi}] and it follows the features asked in xref:references/functional-requirements.adoc[Functional Requirements].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It adheres to the decision taken in xref:explanation/decisions/control-api.adoc[{controlapi}] and it follows the features asked in xref:references/functional-requirements.adoc[Functional Requirements].
It adheres to the decision taken in xref:explanation/decisions/control-api.adoc[{controlapi}] and it follows the features asked in xref:references/functional-requirements/portal.adoc[Portal Requirements].


== General Principles

Kubernetes API::
The Control API is built upon the Kubernetes API and adheres to it's https://kubernetes.io/docs/reference/kubernetes-api/[design principles].

API object field: `.status`::
The `status` field (also called https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#status-subresource["Status subresource"]) represents the current observed state and external information.
It is read-only to the end-user.

API object field: `.spec`::
The `spec` field contains the desired state for reconciliation.

== Virtual vs. CRD based resources

Some resources are not persisted to etcd and are only available _virtually_, others are persisted to etcd and are defined and represented via `CustomResourceDefinition` (CRDs).

Virtual resources are accessible via an https://kubernetes.io/docs/tasks/extend-kubernetes/setup-extension-api-server/[API Server Extension].
These resources are similar to views in a relational database.
The benefit of providing these resources instead of only using CRDs is that we can calculate access permissions dynamically for every request.
The same concept is also used by OpenShift with its `Project` resource which represents RBAC filtered `Namespaces` (see https://github.com/openshift/kube-projects[kube-projects]).
And we can also find it in https://github.com/loft-sh/kiosk[Kiosk] for example.

== Authentication and Authorization

Authentication against the API server is done by the {idp}.
It's always the same subject (user) which is being used throughout the whole {product} ecosystem.

For authorization, standard https://kubernetes.io/docs/reference/access-authn-authz/rbac/[Kubernetes RBAC] is being used.
Kyverno policies can be used to implement enhanced policies, for example the number of resources of a specified kind a user is allowed to create.

There are several layers of authorization:

* Kubernetes RBAC
* Kyverno policies
* Virtual resources with filtering

== Resource Scopes

Resources on the Kubernetes API server can either be https://kubernetes.io/docs/reference/using-api/api-concepts/#standard-api-terminology[cluster scoped or namespace scoped].

Each {controlapi} instance is represented by one Kubernetes API server instance.
This allows us to leverage the scoping concept of the Kubernetes API server to reflect the scopes in the {product} domain.
Also, by doing it that way, standard Kubernetes RBAC rules can be used for permission handling on an organization level.

{global} resources are available on the Kubernetes global scope (no namespace) whereas organization level resources are namespace scoped.

Global:: Kubernetes cluster global resource.
Organization:: Kubernetes namespaced resource.

== Resources

[cols="1,1,2",options="header"]
|===
|Name
|Scope
|Type

|xref:references/architecture/control-api-org.adoc[Organization]
|Global
|Virtual (represents filtered `Namespace` resources)

|xref:references/architecture/control-api-user.adoc[User]
|Global
|CRD

|xref:references/architecture/control-api-team.adoc[Team]
|Organization
|CRD

|xref:references/architecture/control-api-zone.adoc[Zone]
|Global
|CRD
|===
99 changes: 99 additions & 0 deletions docs/modules/ROOT/pages/references/functional-requirements.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
= Functional Requirements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page already exists in portal.adoc.
Maybe PR needs a rebase?


This page discusses functional requirements.
It currently mainly targets the Control API and the {product} Portal.

== Feature: Authentication

> As a xref:references/glossary.adoc#_user[User] +
> I want to only login once to the {product} ecosystem +
> So that I can use strong authentication methods and still get a good user experience

*Scenarios*

* Login
* Logout

== Feature: Manage Organizations

> As a xref:references/glossary.adoc#_user[User] +
> I want to manage organizations +
> So that I can group resources under it

*Scenarios*

* Create Organization
* List Organizations
* Edit Organization
* Delete Organization
* Invite User to Organization
* Join Organization

_Implementation: xref:references/architecture/control-api-org.adoc[APPUiO Control API: Organization]._

== Feature: Manage Teams

> As an xref:references/glossary.adoc#_organization-owner[Organization Owner] +
> I want to manage teams in an organization +
> So that I can group users under it for easier permission management

*Scenarios*

* Create Team
* List Teams
* Edit Team
* Delete Team
* Add User to Team
* Remove User from Team

_Implementation: xref:references/architecture/control-api-team.adoc[APPUiO Control API: Team]._

== Feature: Zones

> As a xref:references/glossary.adoc#_user[User] +
> I want to see all available {zone}s +
> So that I know of them

*Scenarios*

* List {zone}s

_Implementation: xref:references/architecture/control-api-zone.adoc[APPUiO Control API: Zone]._

== Feature: Personal Settings per User

> As a xref:references/glossary.adoc#_user[User] +
> I want to configure my personal settings +
> So that I can have my defaults configured to my liking

*Scenarios*

* Default Organization

_Implementation: xref:references/architecture/control-api-user.adoc[APPUiO Control API: User]._

== Feature: Branding

> As an xref:references/glossary.adoc#_instance_owner[Instance Owner] +
> I want to provide a familiar feeling to the user when using the web application
> So that I can have a consistent feeling throughout my offering

*Scenarios*

* Logo
* Colors
* Navigation
* Naming

== Feature: Permissions

> As a xref:references/glossary.adoc#_user[User] +
> I want to only see what I can really do according to my permissions +
> So that I don't get confused by actions which I'm not allowed to

*Scenarios*

* List resources
* Create resources
* Update resources
* Delete resources
10 changes: 10 additions & 0 deletions docs/modules/ROOT/pages/references/glossary.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ A Kubernetes namespace (in OpenShift also an object type "Project").

== {product} specific

=== {product} Instance
An instance of an {product} installation, consisting of a {global} instance and a number of Zones.

=== Zone
A single OpenShift cluster that is part of an {product} offering.

Expand Down Expand Up @@ -60,6 +63,13 @@ A user which interacts with {product} (the Kubernetes API) in a specified namesp
=== Organization Owner
A user which interacts with {product} (the Kubernetes API).

=== Instance Owner
Owner of the particular {product} instance.

=== Instance Admin
Administrator of the particular {product} instance.
On a {zone} it's the cluster admin, on the global level it's the admin.

== Roles

OpenShift default roles are documented in the https://docs.openshift.com/container-platform/4.9/authentication/using-rbac.html#default-roles_using-rbac[upstream documentation].
Expand Down
7 changes: 7 additions & 0 deletions docs/modules/ROOT/partials/nav-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
** xref:appuio-cloud:ROOT:references/architecture/namespace-ownership.adoc[Namespace ownership]
** xref:appuio-cloud:ROOT:references/architecture/metering.adoc[Metering of resource usage]
** xref:appuio-cloud:ROOT:references/architecture/metrics-of-interest.adoc[Metrics of interest]
** xref:appuio-cloud:ROOT:references/architecture/control-api.adoc[Control API]
*** xref:appuio-cloud:ROOT:references/architecture/control-api-org.adoc[Organization]
*** xref:appuio-cloud:ROOT:references/architecture/control-api-user.adoc[User]
*** xref:appuio-cloud:ROOT:references/architecture/control-api-team.adoc[Team]
*** xref:appuio-cloud:ROOT:references/architecture/control-api-zone.adoc[Zone]

* xref:appuio-cloud:ROOT:references/functional-requirements.adoc[Functional Requirements]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link is probably also outdated


* Functional Requirements

Expand Down