Create/Delete RBAC. Restore deployment to original state when BackupConfiguration is deleted

This commit is contained in:
Jean-Marc ANDRE 2020-12-09 23:15:15 +01:00
parent 43fb07ddea
commit cfbfd38ae4
8 changed files with 398 additions and 177 deletions

View File

@ -48,8 +48,6 @@ type BackupConfigurationSpec struct {
// +optional
VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"`
Paths []string `json:"paths"`
// +optional
Suspend *bool `json:"suspend,omitempty"`
}
// BackupConfigurationStatus defines the observed state of BackupConfiguration
@ -62,10 +60,9 @@ type BackupConfigurationStatus struct {
ActiveSidecar bool `json:"activeSidecar"`
}
// BackupConfiguration is the Schema for the backupconfigurations API
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// BackupConfiguration is the Schema for the backupconfigurations API
type BackupConfiguration struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -118,11 +118,6 @@ func (in *BackupConfigurationSpec) DeepCopyInto(out *BackupConfigurationSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Suspend != nil {
in, out := &in.Suspend, &out.Suspend
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfigurationSpec.

View File

@ -19,17 +19,20 @@ package controllers
import (
"context"
formolrbac "github.com/desmo999r/formol/pkg/rbac"
formolutils "github.com/desmo999r/formol/pkg/utils"
"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
kbatch_beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
// rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/predicate"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
)
@ -41,6 +44,16 @@ type BackupConfigurationReconciler struct {
Scheme *runtime.Scheme
}
func (r *BackupConfigurationReconciler) getDeployment(namespace string, name string) (*appsv1.Deployment, error) {
deployment := &appsv1.Deployment{}
err := r.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: name,
}, deployment)
return deployment, err
}
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=backupconfigurations,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=backupconfigurations/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=repoes,verbs=get;list;watch
@ -49,23 +62,65 @@ type BackupConfigurationReconciler struct {
// +kubebuilder:rbac:groups=batch,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=batch,resources=cronjobs/status,verbs=get
func (r *BackupConfigurationReconciler) addSidecarContainer(backupConf *formolv1alpha1.BackupConfiguration) error {
log := r.Log.WithValues("backupconf", backupConf.Name)
getDeployment := func() (*appsv1.Deployment, error) {
deployment := &appsv1.Deployment{}
err := r.Get(context.Background(), client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Target.Name,
}, deployment)
return deployment, err
func (r *BackupConfigurationReconciler) deleteSidecarContainer(backupConf *formolv1alpha1.BackupConfiguration) error {
deployment, err := r.getDeployment(backupConf.Namespace, backupConf.Spec.Target.Name)
if err != nil {
return err
}
restorecontainers := []corev1.Container{}
for _, container := range deployment.Spec.Template.Spec.Containers {
if container.Name == "backup" {
continue
}
restorecontainers = append(restorecontainers, container)
}
deployment.Spec.Template.Spec.Containers = restorecontainers
if err := r.Update(context.Background(), deployment); err != nil {
return err
}
selector, err := metav1.LabelSelectorAsMap(deployment.Spec.Selector)
if err != nil {
return nil
}
pods := &corev1.PodList{}
err = r.List(context.Background(), pods, client.MatchingLabels(selector))
if err != nil {
return nil
}
replicasToDelete := []appsv1.ReplicaSet{}
for _, pod := range pods.Items {
for _, podRef := range pod.OwnerReferences {
rs := &appsv1.ReplicaSet{}
if err := r.Get(context.Background(), client.ObjectKey{
Name: podRef.Name,
Namespace: pod.Namespace,
}, rs); err != nil {
return nil
}
for _, rsRef := range rs.OwnerReferences {
if rsRef.Kind == deployment.Kind && rsRef.Name == deployment.Name {
replicasToDelete = append(replicasToDelete, *rs)
}
}
}
}
deployment, err := getDeployment()
for _, replica := range replicasToDelete {
if err := r.Delete(context.TODO(), &replica); err != nil {
return nil
}
}
return nil
}
func (r *BackupConfigurationReconciler) addSidecarContainer(backupConf *formolv1alpha1.BackupConfiguration) error {
log := r.Log.WithValues("backupconf", backupConf.Name)
deployment, err := r.getDeployment(backupConf.Namespace, backupConf.Spec.Target.Name)
if err != nil {
log.Error(err, "unable to get Deployment")
return err
}
log.WithValues("Deployment", backupConf.Spec.Target.Name)
log.V(1).Info("got deployment", "Deployment", deployment)
for _, container := range deployment.Spec.Template.Spec.Containers {
if container.Name == "backup" {
log.V(0).Info("There is already a backup sidecar container. Skipping", "container", container)
@ -155,7 +210,7 @@ func (r *BackupConfigurationReconciler) addSidecarContainer(backupConf *formolv1
log.Error(err, "unable to get deployment pods")
return nil
}
podsToDelete := []appsv1.ReplicaSet{}
replicasToDelete := []appsv1.ReplicaSet{}
log.V(1).Info("got that list of pods", "pods", len(pods.Items))
for _, pod := range pods.Items {
log.V(1).Info("checking pod", "pod", pod)
@ -172,78 +227,35 @@ func (r *BackupConfigurationReconciler) addSidecarContainer(backupConf *formolv1
for _, rsRef := range rs.OwnerReferences {
if rsRef.Kind == deployment.Kind && rsRef.Name == deployment.Name {
log.V(0).Info("Adding pod to the list of pods to be restarted", "pod", pod.Name)
podsToDelete = append(podsToDelete, *rs)
replicasToDelete = append(replicasToDelete, *rs)
}
}
}
}
deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, sidecar)
if err := formolrbac.CreateBackupSessionListenerRBAC(r.Client, deployment.Spec.Template.Spec.ServiceAccountName, deployment.Namespace); err != nil {
log.Error(err, "unable to create backupsessionlistener RBAC")
return nil
}
log.V(0).Info("Adding a sicar container")
if err := r.Update(context.Background(), deployment); err != nil {
log.Error(err, "unable to update the Deployment")
return err
}
for _, pod := range podsToDelete {
if err := r.Delete(context.TODO(), &pod); err != nil {
log.Error(err, "unable to delete pod", "pod", pod.Name)
for _, replica := range replicasToDelete {
if err := r.Delete(context.TODO(), &replica); err != nil {
log.Error(err, "unable to delete replica", "replica", replica.Name)
return nil
}
}
deployment, err = getDeployment()
if err != nil {
log.Error(err, "unable to get Deployment")
return err
}
return nil
}
func (r *BackupConfigurationReconciler) addCronJob(backupConf *formolv1alpha1.BackupConfiguration) error {
log := r.Log.WithName("addCronJob")
// serviceaccount := &corev1.ServiceAccount{
// ObjectMeta: metav1.ObjectMeta{
// Namespace: backupConf.Namespace,
// Name: "backupsession-creator",
// },
// }
// if err := r.Get(context.Background(), client.ObjectKey{
// Namespace: backupConf.Namespace,
// Name: "backupsession-creator",
// }, serviceaccount); err != nil && errors.IsNotFound(err) {
// log.V(0).Info("creating service account", "service account", serviceaccount)
// if err = r.Create(context.Background(), serviceaccount); err != nil {
// log.Error(err, "unable to create serviceaccount", "serviceaccount", serviceaccount)
// return nil
// }
// }
// rolebinding := &rbacv1.RoleBinding{
// ObjectMeta: metav1.ObjectMeta{
// Namespace: backupConf.Namespace,
// Name: "backupsession-creator-rolebinding",
// },
// Subjects: []rbacv1.Subject{
// rbacv1.Subject{
// Kind: "ServiceAccount",
// Name: "backupsession-creator",
// },
// },
// RoleRef: rbacv1.RoleRef{
// APIGroup: "rbac.authorization.k8s.io",
// Kind: "ClusterRole",
// Name: "backupsession-creator",
// },
// }
// if err := r.Get(context.Background(), client.ObjectKey{
// Namespace: backupConf.Namespace,
// Name: "backupsession-creator-rolebinding",
// }, rolebinding); err != nil && errors.IsNotFound(err) {
// log.V(0).Info("creating role binding for service account", "rolebinding", rolebinding, "service account", serviceaccount)
// if err = r.Create(context.Background(), rolebinding); err != nil {
// log.Error(err, "unable to create rolebinding", "rolebinding", rolebinding)
// return nil
// }
// }
cronjob := &kbatch_beta1.CronJob{}
if err := r.Get(context.Background(), client.ObjectKey{
Namespace: backupConf.Namespace,
@ -256,6 +268,11 @@ func (r *BackupConfigurationReconciler) addCronJob(backupConf *formolv1alpha1.Ba
return err
}
if err := formolrbac.CreateBackupSessionCreatorRBAC(r.Client, backupConf.Namespace); err != nil {
log.Error(err, "unable to create backupsession-creator RBAC")
return nil
}
cronjob = &kbatch_beta1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "backup-" + backupConf.Name,
@ -310,10 +327,35 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
// your logic here
backupConf := &formolv1alpha1.BackupConfiguration{}
if err := r.Get(ctx, req.NamespacedName, backupConf); err != nil {
log.Error(err, "unable to fetch BackupConfiguration")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
finalizerName := "finalizer.backupconfiguration.formol.desmojim.fr"
if backupConf.ObjectMeta.DeletionTimestamp.IsZero() {
if !formolutils.ContainsString(backupConf.ObjectMeta.Finalizers, finalizerName) {
backupConf.ObjectMeta.Finalizers = append(backupConf.ObjectMeta.Finalizers, finalizerName)
if err := r.Update(context.Background(), backupConf); err != nil {
log.Error(err, "unable to append finalizer")
return ctrl.Result{}, err
}
}
} else {
log.V(0).Info("backupconf being deleted", "backupconf", backupConf.Name)
if formolutils.ContainsString(backupConf.ObjectMeta.Finalizers, finalizerName) {
if err := r.deleteExternelResources(backupConf); err != nil {
return ctrl.Result{}, err
}
}
backupConf.ObjectMeta.Finalizers = formolutils.RemoveString(backupConf.ObjectMeta.Finalizers, finalizerName)
if err := r.Update(context.Background(), backupConf); err != nil {
log.Error(err, "unable to remove finalizer")
return ctrl.Result{}, err
}
// We have been deleted. Return here
return ctrl.Result{}, nil
}
if err := r.addCronJob(backupConf); err != nil {
return ctrl.Result{}, nil
}
@ -330,12 +372,7 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
return ctrl.Result{}, nil
}
if backupConf.Spec.Suspend != nil && *backupConf.Spec.Suspend == true {
log.V(0).Info("We are suspended return and wait for the next event")
// TODO Suspend the CronJob
return ctrl.Result{}, nil
}
backupConf.Status.Suspended = false
log.V(1).Info("updating backupconf")
if err := r.Status().Update(ctx, backupConf); err != nil {
log.Error(err, "unable to update backupconf", "backupconf", backupConf)
@ -345,9 +382,28 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
return ctrl.Result{}, nil
}
func (r *BackupConfigurationReconciler) deleteExternelResources(backupConf *formolv1alpha1.BackupConfiguration) error {
deployment, err := r.getDeployment(backupConf.Namespace, backupConf.Spec.Target.Name)
if err != nil {
return err
}
if err := formolrbac.DeleteBackupSessionListenerRBAC(r.Client, deployment.Spec.Template.Spec.ServiceAccountName, deployment.Namespace); err != nil {
return err
}
if err := formolrbac.DeleteBackupSessionCreatorRBAC(r.Client, backupConf.Namespace); err != nil {
return err
}
if err := r.deleteSidecarContainer(backupConf); err != nil {
return err
}
return nil
}
func (r *BackupConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&formolv1alpha1.BackupConfiguration{}).
Owns(&kbatch_beta1.CronJob{}).
WithOptions(controller.Options{MaxConcurrentReconciles: 3}).
WithEventFilter(predicate.GenerationChangedPredicate{}).
// Owns(&kbatch_beta1.CronJob{}).
Complete(r)
}

14
go.mod
View File

@ -4,10 +4,12 @@ go 1.13
require (
github.com/go-logr/logr v0.1.0
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/client-go v0.17.2
sigs.k8s.io/controller-runtime v0.5.0
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.1
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect
k8s.io/api v0.18.6
k8s.io/apimachinery v0.18.6
k8s.io/client-go v0.18.6
sigs.k8s.io/controller-runtime v0.6.4
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 // indirect
)

16
main.go
View File

@ -74,14 +74,14 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "BackupConfiguration")
os.Exit(1)
}
if err = (&controllers.BackupSessionReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("BackupSession"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "BackupSession")
os.Exit(1)
}
// if err = (&controllers.BackupSessionReconciler{
// Client: mgr.GetClient(),
// Log: ctrl.Log.WithName("controllers").WithName("BackupSession"),
// Scheme: mgr.GetScheme(),
// }).SetupWithManager(mgr); err != nil {
// setupLog.Error(err, "unable to create controller", "controller", "BackupSession")
// os.Exit(1)
// }
if os.Getenv("ENABLE_WEBHOOKS") != "false" {
if err = (&formolv1alpha1.BackupSession{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "BackupSession")

View File

@ -0,0 +1,231 @@
package rbac
import (
"context"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
backupListenerRole = "backup-listener-role"
backupListenerRoleBinding = "backup-listener-rolebinding"
backupSessionCreatorSA = "backupsession-creator"
backupSessionCreatorRole = "backupsession-creator-role"
backupSessionCreatorRoleBinding = "backupsession-creator-rolebinding"
)
func DeleteBackupSessionCreatorRBAC(cl client.Client, namespace string) error {
serviceaccount := &corev1.ServiceAccount{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorSA,
}, serviceaccount); err == nil {
if err = cl.Delete(context.Background(), serviceaccount); err != nil {
return err
}
}
role := &rbacv1.Role{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorRole,
}, role); err == nil {
if err = cl.Delete(context.Background(), role); err != nil {
return err
}
}
rolebinding := &rbacv1.RoleBinding{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorRoleBinding,
}, rolebinding); err == nil {
if err = cl.Delete(context.Background(), rolebinding); err != nil {
return err
}
}
return nil
}
func CreateBackupSessionCreatorRBAC(cl client.Client, namespace string) error {
serviceaccount := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: backupSessionCreatorSA,
},
}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorSA,
}, serviceaccount); err != nil && errors.IsNotFound(err) {
if err = cl.Create(context.Background(), serviceaccount); err != nil {
return err
}
}
role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: backupSessionCreatorRole,
},
Rules: []rbacv1.PolicyRule{
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"},
APIGroups: []string{"formol.desmojim.fr"},
Resources: []string{"backupsessions"},
},
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{"formol.desmojim.fr"},
Resources: []string{"backupconfigurations"},
},
},
}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorRole,
}, role); err != nil && errors.IsNotFound(err) {
if err = cl.Create(context.Background(), role); err != nil {
return err
}
}
rolebinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: backupSessionCreatorRoleBinding,
},
Subjects: []rbacv1.Subject{
rbacv1.Subject{
Kind: "ServiceAccount",
Name: backupSessionCreatorSA,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: backupSessionCreatorRole,
},
}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupSessionCreatorRoleBinding,
}, rolebinding); err != nil && errors.IsNotFound(err) {
if err = cl.Create(context.Background(), rolebinding); err != nil {
return err
}
}
return nil
}
func DeleteBackupSessionListenerRBAC(cl client.Client, saName string, namespace string) error {
if saName == "" {
saName = "default"
}
sa := &corev1.ServiceAccount{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: saName,
}, sa); err != nil {
return err
}
role := &rbacv1.Role{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupListenerRole,
}, role); err == nil {
if err = cl.Delete(context.Background(), role); err != nil {
return err
}
}
rolebinding := &rbacv1.RoleBinding{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupListenerRoleBinding,
}, rolebinding); err == nil {
if err = cl.Delete(context.Background(), rolebinding); err != nil {
return err
}
}
return nil
}
func CreateBackupSessionListenerRBAC(cl client.Client, saName string, namespace string) error {
if saName == "" {
saName = "default"
}
sa := &corev1.ServiceAccount{}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: saName,
}, sa); err != nil {
return err
}
role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: backupListenerRole,
},
Rules: []rbacv1.PolicyRule{
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{""},
Resources: []string{"pods"},
},
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{"apps"},
Resources: []string{"deployments", "replicasets"},
},
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{"formol.desmojim.fr"},
Resources: []string{"backupsessions", "backupconfigurations"},
},
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch", "patch", "update"},
APIGroups: []string{"formol.desmojim.fr"},
Resources: []string{"backupsessions/status"},
},
},
}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupListenerRole,
}, role); err != nil && errors.IsNotFound(err) {
if err = cl.Create(context.Background(), role); err != nil {
return err
}
}
rolebinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: backupListenerRoleBinding,
},
Subjects: []rbacv1.Subject{
rbacv1.Subject{
Kind: "ServiceAccount",
Name: saName,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: backupListenerRole,
},
}
if err := cl.Get(context.Background(), client.ObjectKey{
Namespace: namespace,
Name: backupListenerRoleBinding,
}, rolebinding); err != nil && errors.IsNotFound(err) {
if err = cl.Create(context.Background(), rolebinding); err != nil {
return err
}
}
return nil
}

20
pkg/utils/root.go Normal file
View File

@ -0,0 +1,20 @@
package utils
func ContainsString(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}
func RemoveString(slice []string, s string) (result []string) {
for _, item := range slice {
if item == s {
continue
}
result = append(result, item)
}
return
}

View File

@ -52,86 +52,6 @@ spec:
storage: 50Mi
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: backupsession-creator
namespace: demo
labels:
app: backupsession-creator
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: backup-listener
labels:
app: backup-listener
rules:
- apiGroups: ["formol.desmojim.fr"]
resources: ["backupsessions", "backupconfigurations"]
verbs: ["get", "list", "watch"]
- apiGroups: ["formol.desmojim.fr"]
resources: ["backupsessions/status"]
verbs: ["update"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: backupsession-creator
namespace: demo
labels:
app: backupsession-creator
rules:
- apiGroups: ["formol.desmojim.fr"]
resources: ["backupsessions"]
verbs: ["get", "list", "create", "delete"]
- apiGroups: ["formol.desmojim.fr"]
resources: ["backupconfigurations"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: backupsession-creator
namespace: demo
labels:
app: backupsession-creator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: backupsession-creator
subjects:
- name: backupsession-creator
kind: ServiceAccount
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: backup-listener
labels:
app: backup-listener
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: backup-listener
subjects:
- name: default
namespace: demo
kind: ServiceAccount
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: demo-viewer
namespace: demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view
subjects:
- name: default
kind: ServiceAccount
---
apiVersion: v1
kind: Secret
metadata:
name: secret-minio