Skip to content

Commit

Permalink
RBAC manifest creation for Hosted Cluster admin personas (#1014)
Browse files Browse the repository at this point in the history
* RBAC manifest creation for Hosted Cluster admin personas

introduce RBAC artifact generation for hypershift admin personas / services
those artifacts are generated when the `--enable-admin-rbac-generation` flag
is provided during `hypershift install`

persona: hypershift-client

used by a client leveraging hypershift as a service to create hosted clusters
* hypershift-client ClusterRole
  full permissions on the hostedcluster and nodepool CRs
* hypershift-client ServiceAccount
* hypershift-client ClusterRoleBinding
  binds the hypershift-client ClusterRole to hypershift-client SA and Group Ref
  the groups itself must be provided by other means

persona: hypershift-reader

used by admins to investigate hosted clusters and the hypershift operator.
* hypershift-reader ClusterRole
  same permission subjects as the hypershift-operator ClusterRole but restricted
  to get, list, watch. access to secrets is not granted
* hypershift-reader ClusterRoleBinding
  binds the hypershift-reader ClusterRole to a Group called hypershift-readers
  the group itself must be provided by other means

Refs:
* https://issues.redhat.com/browse/HOSTEDCP-306
* https://issues.redhat.com/browse/APPSRE-4335

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>

* renamed hypershift-reader -> hypershift-readers

* list hypershift-readers clusterrole permissions explicitely

instead of copy+modify the hypershift-operator cluster role, list the permissions
required for the hypershift-readers cluster role explicitely

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>
  • Loading branch information
geoberle authored Feb 16, 2022
1 parent a7f0d32 commit f3b29fc
Show file tree
Hide file tree
Showing 4 changed files with 435 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ app-sre-saas-template: hypershift
--oidc-storage-provider-s3-secret-key=credentials \
--enable-ocp-cluster-monitoring=false \
--enable-ci-debug-output=false \
--enable-admin-rbac-generation=true \
render --template --format yaml > $(DIR)/hack/app-sre/saas_template.yaml

# Run tests
Expand Down
216 changes: 216 additions & 0 deletions cmd/install/assets/hypershift_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,3 +725,219 @@ func (r HypershiftRecordingRule) Build() *prometheusoperatorv1.PrometheusRule {
rule.Spec = recordingRuleSpec()
return rule
}

type HyperShiftClientClusterRole struct{}

func (o HyperShiftClientClusterRole) Build() *rbacv1.ClusterRole {
role := &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterRole",
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "hypershift-client",
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{"hypershift.openshift.io"},
Resources: []string{"hostedclusters", "nodepools"},
Verbs: []string{"*"},
},
},
}
return role
}

type HyperShiftClientServiceAccount struct {
Namespace *corev1.Namespace
}

func (o HyperShiftClientServiceAccount) Build() *corev1.ServiceAccount {
sa := &corev1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
Kind: "ServiceAccount",
APIVersion: corev1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: o.Namespace.Name,
Name: "hypershift-client",
},
}
return sa
}

type HyperShiftClientClusterRoleBinding struct {
ClusterRole *rbacv1.ClusterRole
ServiceAccount *corev1.ServiceAccount
GroupName string
}

func (o HyperShiftClientClusterRoleBinding) Build() *rbacv1.ClusterRoleBinding {
binding := &rbacv1.ClusterRoleBinding{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterRoleBinding",
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "hypershift-client",
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: o.ClusterRole.Name,
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: o.ServiceAccount.Name,
Namespace: o.ServiceAccount.Namespace,
},
{
Kind: "Group",
APIGroup: "rbac.authorization.k8s.io",
Name: o.GroupName,
},
},
}
return binding
}

type HyperShiftReaderClusterRole struct{}

func (o HyperShiftReaderClusterRole) Build() *rbacv1.ClusterRole {
role := &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterRole",
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "hypershift-readers",
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{"hypershift.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"config.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"apiextensions.k8s.io"},
Resources: []string{"customresourcedefinitions"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"networking.k8s.io"},
Resources: []string{"networkpolicies"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{
"bootstrap.cluster.x-k8s.io",
"controlplane.cluster.x-k8s.io",
"infrastructure.cluster.x-k8s.io",
"machines.cluster.x-k8s.io",
"exp.infrastructure.cluster.x-k8s.io",
"addons.cluster.x-k8s.io",
"exp.cluster.x-k8s.io",
"cluster.x-k8s.io",
},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"operator.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"route.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"security.openshift.io"},
Resources: []string{"securitycontextconstraints"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{""},
Resources: []string{
"events",
"configmaps",
"pods",
"pods/log",
"nodes",
"namespaces",
"serviceaccounts",
"services",
},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"apps"},
Resources: []string{"deployments"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"etcd.database.coreos.com"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"machine.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"monitoring.coreos.com"},
Resources: []string{"podmonitors"},
Verbs: []string{"get", "list", "watch"},
},
{
APIGroups: []string{"capi-provider.agent-install.openshift.io"},
Resources: []string{"*"},
Verbs: []string{"get", "list", "watch"},
},
},
}
return role
}

type HyperShiftReaderClusterRoleBinding struct {
ClusterRole *rbacv1.ClusterRole
GroupName string
}

func (o HyperShiftReaderClusterRoleBinding) Build() *rbacv1.ClusterRoleBinding {
binding := &rbacv1.ClusterRoleBinding{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterRoleBinding",
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "hypershift-readers",
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: o.ClusterRole.Name,
},
Subjects: []rbacv1.Subject{
{
Kind: "Group",
APIGroup: "rbac.authorization.k8s.io",
Name: o.GroupName,
},
},
}
return binding
}
30 changes: 30 additions & 0 deletions cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Options struct {
OIDCStorageProviderS3Credentials string
OIDCStorageProviderS3CredentialsSecret string
OIDCStorageProviderS3CredentialsSecretKey string
EnableAdminRBACGeneration bool
}

func (o *Options) Validate() error {
Expand Down Expand Up @@ -120,6 +121,7 @@ func NewCommand() *cobra.Command {
cmd.PersistentFlags().StringVar(&opts.OIDCStorageProviderS3Credentials, "oidc-storage-provider-s3-credentials", opts.OIDCStorageProviderS3Credentials, "Credentials to use for writing the OIDC documents into the S3 bucket. Required for AWS guest clusters")
cmd.PersistentFlags().StringVar(&opts.OIDCStorageProviderS3CredentialsSecret, "oidc-storage-provider-s3-secret", "", "Name of an existing secret containing the OIDC S3 credentials.")
cmd.PersistentFlags().StringVar(&opts.OIDCStorageProviderS3CredentialsSecretKey, "oidc-storage-provider-s3-secret-key", "credentials", "Name of the secret key containing the OIDC S3 credentials.")
cmd.PersistentFlags().BoolVar(&opts.EnableAdminRBACGeneration, "enable-admin-rbac-generation", false, "Generate RBAC manifests for hosted cluster admins")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
opts.ApplyDefaults()
Expand Down Expand Up @@ -306,5 +308,33 @@ func hyperShiftOperatorManifests(opts Options) ([]crclient.Object, error) {
return true
})...)

if opts.EnableAdminRBACGeneration {
// hypershift-client admin persona for hostedclusters and nodepools creation
clientClusterRole := assets.HyperShiftClientClusterRole{}.Build()
objects = append(objects, clientClusterRole)

clientServiceAccount := assets.HyperShiftClientServiceAccount{
Namespace: operatorNamespace,
}.Build()
objects = append(objects, clientServiceAccount)

clientRoleBinding := assets.HyperShiftClientClusterRoleBinding{
ClusterRole: clientClusterRole,
ServiceAccount: clientServiceAccount,
GroupName: "hypershift-client",
}.Build()
objects = append(objects, clientRoleBinding)

// hypershift-reader admin persona for inspecting hosted controlplanes and the operator
readerClusterRole := assets.HyperShiftReaderClusterRole{}.Build()
objects = append(objects, readerClusterRole)

readerRoleBinding := assets.HyperShiftReaderClusterRoleBinding{
ClusterRole: readerClusterRole,
GroupName: "hypershift-readers",
}.Build()
objects = append(objects, readerRoleBinding)
}

return objects, nil
}
Loading

0 comments on commit f3b29fc

Please sign in to comment.