Skip to content

Commit

Permalink
Merge pull request #579 from carbonin/use_sa_for_pull_secrets
Browse files Browse the repository at this point in the history
Use a service account for pull secrets
  • Loading branch information
bdunne authored Jul 8, 2020
2 parents 743aeb9 + 966f161 commit 1ebbeaf
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 36 deletions.
1 change: 0 additions & 1 deletion manageiq-operator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/ManageIQ/manageiq-pods/manageiq-operator
go 1.14

require (
github.com/google/uuid v1.1.1
github.com/operator-framework/operator-sdk v0.15.1
github.com/spf13/pflag v1.0.5
k8s.io/api v0.0.0
Expand Down
37 changes: 28 additions & 9 deletions manageiq-operator/pkg/controller/manageiq/manageiq_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
miqtool "github.com/ManageIQ/manageiq-pods/manageiq-operator/pkg/helpers/miq-components"
appsv1 "k8s.io/api/apps/v1"
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"
Expand Down Expand Up @@ -118,6 +117,9 @@ func (r *ReconcileManageIQ) Reconcile(request reconcile.Request) (reconcile.Resu
if e := r.generateSecrets(miqInstance); e != nil {
return reconcile.Result{}, e
}
if e := r.generateDefaultServiceAccount(miqInstance); e != nil {
return reconcile.Result{}, e
}
if e := r.generatePostgresqlResources(miqInstance); e != nil {
return reconcile.Result{}, e
}
Expand All @@ -139,6 +141,17 @@ func (r *ReconcileManageIQ) Reconcile(request reconcile.Request) (reconcile.Resu
return reconcile.Result{}, nil
}

func (r *ReconcileManageIQ) generateDefaultServiceAccount(cr *miqv1alpha1.ManageIQ) error {
serviceAccount, mutateFunc := miqtool.DefaultServiceAccount(cr, r.scheme)
if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, serviceAccount, mutateFunc); err != nil {
return err
} else if result != controllerutil.OperationResultNone {
logger.Info("Service Account has been reconciled", "component", "app", "result", result)
}

return nil
}

func (r *ReconcileManageIQ) generateHttpdResources(cr *miqv1alpha1.ManageIQ) error {
privileged, err := miqtool.PrivilegedHttpd(cr.Spec.HttpdAuthenticationType)
if err != nil {
Expand Down Expand Up @@ -351,27 +364,33 @@ func (r *ReconcileManageIQ) generateKafkaResources(cr *miqv1alpha1.ManageIQ) err
}

func (r *ReconcileManageIQ) generateOrchestratorResources(cr *miqv1alpha1.ManageIQ) error {
orchestratorServiceAccount := miqtool.OrchestratorServiceAccount(cr)
if err := r.createk8sResIfNotExist(cr, orchestratorServiceAccount, &corev1.ServiceAccount{}); err != nil {
serviceAccount, mutateFunc := miqtool.OrchestratorServiceAccount(cr, r.scheme)
if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, serviceAccount, mutateFunc); err != nil {
return err
} else if result != controllerutil.OperationResultNone {
logger.Info("Service Account has been reconciled", "component", "orchestrator", "result", result)
}

orchestratorRole := miqtool.OrchestratorRole(cr)
if err := r.createk8sResIfNotExist(cr, orchestratorRole, &rbacv1.Role{}); err != nil {
role, mutateFunc := miqtool.OrchestratorRole(cr, r.scheme)
if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, role, mutateFunc); err != nil {
return err
} else if result != controllerutil.OperationResultNone {
logger.Info("Role has been reconciled", "component", "orchestrator", "result", result)
}

orchestratorRoleBinding := miqtool.OrchestratorRoleBinding(cr)
if err := r.createk8sResIfNotExist(cr, orchestratorRoleBinding, &rbacv1.RoleBinding{}); err != nil {
roleBinding, mutateFunc := miqtool.OrchestratorRoleBinding(cr, r.scheme)
if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, roleBinding, mutateFunc); err != nil {
return err
} else if result != controllerutil.OperationResultNone {
logger.Info("Role Binding has been reconciled", "component", "orchestrator", "result", result)
}

orchestratorDeployment, mutateFunc, err := miqtool.OrchestratorDeployment(cr, r.scheme)
deployment, mutateFunc, err := miqtool.OrchestratorDeployment(cr, r.scheme)
if err != nil {
return err
}

if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, orchestratorDeployment, mutateFunc); err != nil {
if result, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, deployment, mutateFunc); err != nil {
return err
} else if result != controllerutil.OperationResultNone {
logger.Info("Deployment has been reconciled", "component", "orchestrator", "result", result)
Expand Down
7 changes: 7 additions & 0 deletions manageiq-operator/pkg/helpers/miq-components/httpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ func HttpdServiceAccount(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*cor
if err := controllerutil.SetControllerReference(cr, serviceAccount, scheme); err != nil {
return err
}

if cr.Spec.ImagePullSecret != "" {
addSAPullSecret(serviceAccount, cr.Spec.ImagePullSecret)
}

return nil
}

Expand Down Expand Up @@ -359,6 +364,8 @@ func HttpdDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*appsv1.
// Only assign the service account if we need additional privileges
if privileged {
deployment.Spec.Template.Spec.ServiceAccountName = cr.Spec.AppName + "-httpd"
} else {
deployment.Spec.Template.Spec.ServiceAccountName = defaultServiceAccountName(cr.Spec.AppName)
}

configureHttpdAuth(&cr.Spec, &deployment.Spec.Template.Spec)
Expand Down
2 changes: 2 additions & 0 deletions manageiq-operator/pkg/helpers/miq-components/kafka.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ func KafkaDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*appsv1.
var repNum int32 = 1
deployment.Spec.Replicas = &repNum
deployment.Spec.Template.Spec.Containers = []corev1.Container{container}
deployment.Spec.Template.Spec.ServiceAccountName = defaultServiceAccountName(cr.Spec.AppName)
var termSecs int64 = 10
deployment.Spec.Template.Spec.TerminationGracePeriodSeconds = &termSecs
deployment.Spec.Template.Spec.Volumes = []corev1.Volume{
Expand Down Expand Up @@ -323,6 +324,7 @@ func ZookeeperDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*app
var repNum int32 = 1
deployment.Spec.Replicas = &repNum
deployment.Spec.Template.Spec.Containers = []corev1.Container{container}
deployment.Spec.Template.Spec.ServiceAccountName = defaultServiceAccountName(cr.Spec.AppName)
deployment.Spec.Template.Spec.Volumes = []corev1.Volume{
corev1.Volume{
Name: "zookeeper-data",
Expand Down
1 change: 1 addition & 0 deletions manageiq-operator/pkg/helpers/miq-components/memcached.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func NewMemcachedDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*
var repNum int32 = 1
deployment.Spec.Replicas = &repNum
deployment.Spec.Template.Spec.Containers = []corev1.Container{container}
deployment.Spec.Template.Spec.ServiceAccountName = defaultServiceAccountName(cr.Spec.AppName)
return nil
}

Expand Down
78 changes: 52 additions & 26 deletions manageiq-operator/pkg/helpers/miq-components/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,43 @@ import (
"strings"
)

func OrchestratorServiceAccount(cr *miqv1alpha1.ManageIQ) *corev1.ServiceAccount {
return &corev1.ServiceAccount{
func OrchestratorServiceAccount(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*corev1.ServiceAccount, controllerutil.MutateFn) {
sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: orchestratorObjectName(cr),
Namespace: cr.ObjectMeta.Namespace,
},
}

f := func() error {
if err := controllerutil.SetControllerReference(cr, sa, scheme); err != nil {
return err
}

if cr.Spec.ImagePullSecret != "" {
addSAPullSecret(sa, cr.Spec.ImagePullSecret)
}

return nil
}

return sa, f
}

func OrchestratorRole(cr *miqv1alpha1.ManageIQ) *rbacv1.Role {
return &rbacv1.Role{
func OrchestratorRole(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*rbacv1.Role, controllerutil.MutateFn) {
role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: orchestratorObjectName(cr),
Namespace: cr.ObjectMeta.Namespace,
},
Rules: []rbacv1.PolicyRule{
}

f := func() error {
if err := controllerutil.SetControllerReference(cr, role, scheme); err != nil {
return err
}

role.Rules = []rbacv1.PolicyRule{
rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"pods", "pods/finalizers"},
Expand All @@ -43,28 +64,43 @@ func OrchestratorRole(cr *miqv1alpha1.ManageIQ) *rbacv1.Role {
Resources: []string{"deployments", "deployments/scale"},
Verbs: []string{"*"},
},
},
}

return nil
}

return role, f
}

func OrchestratorRoleBinding(cr *miqv1alpha1.ManageIQ) *rbacv1.RoleBinding {
return &rbacv1.RoleBinding{
func OrchestratorRoleBinding(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*rbacv1.RoleBinding, controllerutil.MutateFn) {
rb := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: orchestratorObjectName(cr),
Namespace: cr.ObjectMeta.Namespace,
},
RoleRef: rbacv1.RoleRef{
}

f := func() error {
if err := controllerutil.SetControllerReference(cr, rb, scheme); err != nil {
return err
}

rb.RoleRef = rbacv1.RoleRef{
Kind: "Role",
Name: orchestratorObjectName(cr),
APIGroup: "rbac.authorization.k8s.io",
},
Subjects: []rbacv1.Subject{
}
rb.Subjects = []rbacv1.Subject{
rbacv1.Subject{
Kind: "ServiceAccount",
Name: orchestratorObjectName(cr),
},
},
}

return nil
}

return rb, f
}

func orchestratorObjectName(cr *miqv1alpha1.ManageIQ) string {
Expand Down Expand Up @@ -270,6 +306,10 @@ func OrchestratorDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*
Name: "WORKER_RESOURCES",
Value: strconv.FormatBool(*cr.Spec.EnforceWorkerResourceConstraints),
},
corev1.EnvVar{
Name: "WORKER_SERVICE_ACCOUNT",
Value: defaultServiceAccountName(cr.Spec.AppName),
},
},
}

Expand Down Expand Up @@ -311,20 +351,6 @@ func OrchestratorDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*
deployment.Spec.Template.Spec.ServiceAccountName = cr.Spec.AppName + "-orchestrator"
deployment.Spec.Template.Spec.TerminationGracePeriodSeconds = &termSecs

if cr.Spec.ImagePullSecret != "" {
pullSecret := []corev1.LocalObjectReference{
corev1.LocalObjectReference{Name: cr.Spec.ImagePullSecret},
}
deployment.Spec.Template.Spec.ImagePullSecrets = pullSecret

c := &deployment.Spec.Template.Spec.Containers[0]
pullSecretEnv := corev1.EnvVar{
Name: "IMAGE_PULL_SECRET",
Value: cr.Spec.ImagePullSecret,
}
c.Env = append(c.Env, pullSecretEnv)
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions manageiq-operator/pkg/helpers/miq-components/postgresql.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ func PostgresqlDeployment(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*ap
var repNum int32 = 1
deployment.Spec.Replicas = &repNum
deployment.Spec.Template.Spec.Containers = []corev1.Container{container}
deployment.Spec.Template.Spec.ServiceAccountName = defaultServiceAccountName(cr.Spec.AppName)
deployment.Spec.Template.Spec.Volumes = []corev1.Volume{
corev1.Volume{
Name: "miq-pgdb-volume",
Expand Down
51 changes: 51 additions & 0 deletions manageiq-operator/pkg/helpers/miq-components/rbac.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package miqtools

import (
"fmt"
miqv1alpha1 "github.com/ManageIQ/manageiq-pods/manageiq-operator/pkg/apis/manageiq/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func addSAPullSecret(sa *corev1.ServiceAccount, secret string) {
secretRef := corev1.LocalObjectReference{Name: secret}
if sa.ImagePullSecrets == nil {
sa.ImagePullSecrets = []corev1.LocalObjectReference{secretRef}
} else {
for _, ref := range sa.ImagePullSecrets {
if ref.Name == secret {
return
}
}
sa.ImagePullSecrets = append(sa.ImagePullSecrets, secretRef)
}
}

func defaultServiceAccountName(appName string) string {
return fmt.Sprintf("%s-default", appName)
}

func DefaultServiceAccount(cr *miqv1alpha1.ManageIQ, scheme *runtime.Scheme) (*corev1.ServiceAccount, controllerutil.MutateFn) {
sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: defaultServiceAccountName(cr.Spec.AppName),
Namespace: cr.ObjectMeta.Namespace,
},
}

f := func() error {
if err := controllerutil.SetControllerReference(cr, sa, scheme); err != nil {
return err
}

if cr.Spec.ImagePullSecret != "" {
addSAPullSecret(sa, cr.Spec.ImagePullSecret)
}

return nil
}

return sa, f
}

0 comments on commit 1ebbeaf

Please sign in to comment.