Skip to content

Reduce System Account Coupling #260

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
20 changes: 6 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,6 @@ providers:
platformAdministrators:
subjects:
- [email protected]
systemAccounts:
unikorn-kubernetes: infra-manager-service
unikorn-compute: infra-manager-service
```
Install the Helm repository:
Expand Down Expand Up @@ -322,18 +319,13 @@ If your user's email address can be authenticated by any of the supported OIDC i
When using an integration such as the [Unikorn Kubernetes Service](https://github.com/unikorn-cloud/kubernetes) you will need to configure system account to RBAC mappings.
3rd party services usually act on behalf of a user, and as such need elevated global privileges, so as to avoid giving the end user permission to sensitive endpoints.

In the earlier `values.yaml` manifest, the following section was defined:

```yaml
systemAccounts:
unikorn-kubernetes: infra-manager-service
unikorn-compute: infra-manager-service
```

In very simple terms, when you create a 3rd party service, that will need to generate an X.509 certificate in order to authenticate with the tokens endpoint and issue an access token to talk to other Unikorn service APIs.
When you create a 3rd party service, that will need to generate an X.509 certificate in order to authenticate with the tokens endpoint and issue an access token to talk to other Unikorn service APIs.
That certificate will need to be signed by the trusted client CA (typically signed by the `unikorn-client-issuer` managed by cert-manager).
The X.509 Common Name (CN) encoded in the certificate is the key to this mapping e.g. `unikorn-kubernetes`.
The value references a role name that is either installed by default, or created specifically for your service.
The X.509 Common Name (CN) encoded in the certificate is used to lookup a `SystemAccount` resource in any namespace.
The `SystemAccount` resource is then used to lookup a role defined in the same namespace that defines permissions.

The key benefit with this way of defining RBAC rules is that it can be done completely independently of the Identity service.
Care should, however, be taken to ensure only trusted actors are allowed to create roles and system accounts.

#### 3rd Party User RBAC

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
name: systemaccounts.identity.unikorn-cloud.org
spec:
group: identity.unikorn-cloud.org
names:
categories:
- unikorn
kind: SystemAccount
listKind: SystemAccountList
plural: systemaccounts
singular: systemaccount
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.role.name
name: role
type: string
name: v1alpha1
schema:
openAPIV3Schema:
description: |-
SystemAccount is a namespaced resource that defines a system account name
(provided by clients as an X.509 client certificate CN) and a role associated
with that client. This aims to decouple services, and role definitions,
from the identity service itself.
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:
properties:
role:
description: Role is a reference to the role name defined in the local
namespace.
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
type: object
x-kubernetes-map-type: atomic
required:
- role
type: object
status:
type: object
required:
- spec
type: object
served: true
storage: true
subresources: {}
9 changes: 8 additions & 1 deletion charts/identity/templates/identity/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ rules:
- projects
- quotas
- quotametadata
- roles
- serviceaccounts
- users
- organizationusers
Expand All @@ -27,6 +26,14 @@ rules:
- patch
- create
- delete
- apiGroups:
- identity.unikorn-cloud.org
resources:
- roles
- systemaccounts
verbs:
- list
- watch
- apiGroups:
- identity.unikorn-cloud.org
resources:
Expand Down
1 change: 0 additions & 1 deletion charts/identity/templates/identity/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ spec:
{{- range $k, $v := .Values.systemAccounts }}
{{- $systemAccounts = append $systemAccounts (printf "%s=%s" $k (include "resource.id" $v)) }}
{{- end }}
- --system-account-roles-ids={{ join "," $systemAccounts }}
{{- with $signup := .Values.signup }}
{{- if $signup.enabled }}
- --user-email-verification
Expand Down
32 changes: 0 additions & 32 deletions charts/identity/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,6 @@ platformAdministrators:
# and not an alias.
subjects: []

# System accounts map X.509 Common Names to roles.
systemAccounts:
unikorn-kubernetes: infra-manager-service
unikorn-compute: infra-manager-service

# A static list of roles.
# Any unscoped API resources are to be managed by the platform operator
# and are assumed to be read only for all. Global permissions are applied
Expand Down Expand Up @@ -143,33 +138,6 @@ roles:
compute:clusters: [create,read,update,delete]
application:applications: [create,read,update,delete]
application:applicationsets: [create,read,update,delete]
# An infrastructure manager service is a role primarily for Kubernetes like
# services that can manage identities and physical networks on behalf of a cluster.
infra-manager-service:
decription: Infrastructure manager service
protected: true
scopes:
global:
identity:allocations: [create,read,update,delete]
region:identities: [create,read,delete]
region:regions: [read]
region:regions/detail: [read]
region:flavors: [read]
region:images: [read]
region:externalnetworks: [read]
region:networks: [create,read,delete]
region:servers: [create,read,update,delete]
region:securitygroups: [create,read,update,delete]
# An application manager is a role primarily for the application service that
# needs to be able to see the Kubernetes clusters it's deploying applications
# on to.
application-manager-service:
description: Application manager service
protected: true
scopes:
global:
kubernetes:clusters: [read]
# An administrator can do anything within an organization.
administrator:
description: Organization administrator
scopes:
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/unikorn/v1alpha1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func init() {
SchemeBuilder.Register(&QuotaMetadata{}, &QuotaMetadataList{})
SchemeBuilder.Register(&Quota{}, &QuotaList{})
SchemeBuilder.Register(&Allocation{}, &AllocationList{})
SchemeBuilder.Register(&SystemAccount{}, &SystemAccountList{})
}

// Resource maps a resource type to a group resource.
Expand Down
34 changes: 34 additions & 0 deletions pkg/apis/unikorn/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package v1alpha1
import (
unikornv1core "github.com/unikorn-cloud/core/pkg/apis/unikorn/v1alpha1"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -516,3 +517,36 @@ type ResourceAllocation struct {

type AllocationStatus struct {
}

// SystemAccountList is a list of system accounts.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:scope=Namespaced,categories=unikorn
type SystemAccountList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []SystemAccount `json:"items"`
}

// SystemAccount is a namespaced resource that defines a system account name
// (provided by clients as an X.509 client certificate CN) and a role associated
// with that client. This aims to decouple services, and role definitions,
// from the identity service itself.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:printcolumn:name="role",type="string",JSONPath=".spec.role.name"
// +kubebuilder:resource:scope=Namespaced,categories=unikorn
type SystemAccount struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec SystemAccountSpec `json:"spec"`
Status SystemAccountStatus `json:"status,omitempty"`
}

type SystemAccountSpec struct {
// Role is a reference to the role name defined in the local namespace.
Role corev1.LocalObjectReference `json:"role"`
}

type SystemAccountStatus struct {
}
94 changes: 94 additions & 0 deletions pkg/apis/unikorn/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading