Reissue PAT if roles changed

[ZITADOPER-1]
This commit is contained in:
Haim Kortovich
2024-05-20 18:12:26 -05:00
parent 8afd44dc45
commit 9e7af107d1
5 changed files with 83 additions and 120 deletions

View File

@@ -2,9 +2,10 @@ package v1alpha1
const ( const (
ConditionTypeReady string = "Ready" ConditionTypeReady string = "Ready"
ConditionTypeBackupRestored string = "BackupRestored" ConditionTypePATUpToDate string = "PATUpToDate"
ConditionTypeReplicationConfigured string = "ReplicationConfigured"
ConditionTypeComplete string = "Complete" ConditionReasonRolesChanged string = "RolesChanged"
ConditionReasonPATUpToDate string = "UpToDate"
ConditionReasonDeploymentNotReady string = "DeploymentNotReady" ConditionReasonDeploymentNotReady string = "DeploymentNotReady"
ConditionReasonDeploymentReady string = "DeploymentReady" ConditionReasonDeploymentReady string = "DeploymentReady"

View File

@@ -66,6 +66,13 @@ func (d *MachineUserStatus) SetCondition(condition metav1.Condition) {
meta.SetStatusCondition(&d.Conditions, condition) meta.SetStatusCondition(&d.Conditions, condition)
} }
func (d *MachineUserStatus) GetConditionStatus(conditionType string) bool {
if d.Conditions == nil {
d.Conditions = make([]metav1.Condition, 0)
}
return meta.IsStatusConditionTrue(d.Conditions, conditionType)
}
//+kubebuilder:object:root=true //+kubebuilder:object:root=true
//+kubebuilder:subresource:status //+kubebuilder:subresource:status

View File

@@ -21,10 +21,12 @@ import (
project "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/project" project "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/project"
user "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/user" user "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/user"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
clientpkg "sigs.k8s.io/controller-runtime/pkg/client"
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller"
) )
@@ -192,7 +194,15 @@ func (wr *wrappedMachineUserReconciler) reconcilePAT(ctx context.Context, ztdCli
} }
} }
if token == nil { if token == nil || !wr.MachineUser.Status.GetConditionStatus(zitadelv1alpha1.ConditionTypePATUpToDate) {
if token != nil {
if _, err = ztdClient.RemovePersonalAccessToken(ctx, &pb.RemovePersonalAccessTokenRequest{
UserId: wr.MachineUser.Status.UserId,
TokenId: wr.MachineUser.Status.PATId,
}); err != nil {
return fmt.Errorf("Error removing PAT: %v", err)
}
}
resp, err := ztdClient.AddPersonalAccessToken(ctx, &pb.AddPersonalAccessTokenRequest{ resp, err := ztdClient.AddPersonalAccessToken(ctx, &pb.AddPersonalAccessTokenRequest{
UserId: wr.MachineUser.Status.UserId, UserId: wr.MachineUser.Status.UserId,
}) })
@@ -203,7 +213,7 @@ func (wr *wrappedMachineUserReconciler) reconcilePAT(ctx context.Context, ztdCli
Name: wr.MachineUser.PatSecretName(), Name: wr.MachineUser.PatSecretName(),
Namespace: wr.MachineUser.Namespace, Namespace: wr.MachineUser.Namespace,
} }
patSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{ desiredPatSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{
Key: key, Key: key,
Immutable: true, Immutable: true,
Data: map[string][]byte{ Data: map[string][]byte{
@@ -214,9 +224,30 @@ func (wr *wrappedMachineUserReconciler) reconcilePAT(ctx context.Context, ztdCli
if err != nil { if err != nil {
return fmt.Errorf("error building PAT Secret: %v", err) return fmt.Errorf("error building PAT Secret: %v", err)
} }
if err := wr.Create(ctx, patSecret); err != nil {
return fmt.Errorf("error creating pat-secret Secret: %v", err) {
var existingPatSecret corev1.Secret
if err := wr.Get(ctx, key, &existingPatSecret); err != nil {
if !errors.IsNotFound(err) {
return fmt.Errorf("error getting PAT Secret: %v", err)
} }
if err := wr.Create(ctx, desiredPatSecret); err != nil {
return fmt.Errorf("error creating PAT Secret: %v", err)
}
}
patch := clientpkg.MergeFrom(existingPatSecret.DeepCopy())
existingPatSecret.Data = desiredPatSecret.Data
if err = wr.Patch(ctx, &existingPatSecret, patch); err != nil {
return err
}
}
if err = wr.PatchStatus(ctx, condition.SetPatUpToDate); err != nil {
return err
}
patch := ctrlClient.MergeFrom(wr.MachineUser.DeepCopy()) patch := ctrlClient.MergeFrom(wr.MachineUser.DeepCopy())
wr.MachineUser.Status.PATId = resp.TokenId wr.MachineUser.Status.PATId = resp.TokenId
return wr.Client.Status().Patch(ctx, wr.MachineUser, patch) return wr.Client.Status().Patch(ctx, wr.MachineUser, patch)
@@ -268,7 +299,7 @@ func (wr *wrappedMachineUserReconciler) reconcileJWT(ctx context.Context, ztdCli
} }
patSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{ patSecret, err := wr.Builder.BuildSecret(builder.SecretOpts{
Key: key, Key: key,
Immutable: true, Immutable: false,
Data: secretData, Data: secretData,
}, wr.MachineUser) }, wr.MachineUser)
@@ -343,6 +374,11 @@ func (wr *wrappedMachineUserReconciler) reconcileUserGrants(ctx context.Context,
if existingProjectGrant == nil { if existingProjectGrant == nil {
return fmt.Errorf("Error no project granted to user organization: %v", err) return fmt.Errorf("Error no project granted to user organization: %v", err)
} }
if err = wr.PatchStatus(ctx, condition.SetPatOutOfDate); err != nil {
return err
}
_, err = ztdClient.AddUserGrant(ctx, &pb.AddUserGrantRequest{ _, err = ztdClient.AddUserGrant(ctx, &pb.AddUserGrantRequest{
UserId: wr.MachineUser.Status.UserId, UserId: wr.MachineUser.Status.UserId,
RoleKeys: userGrant.RoleKeys, RoleKeys: userGrant.RoleKeys,
@@ -357,6 +393,11 @@ func (wr *wrappedMachineUserReconciler) reconcileUserGrants(ctx context.Context,
sort.Strings(existingUserGrant.RoleKeys) sort.Strings(existingUserGrant.RoleKeys)
sort.Strings(userGrant.RoleKeys) sort.Strings(userGrant.RoleKeys)
if !reflect.DeepEqual(existingUserGrant.RoleKeys, userGrant.RoleKeys) { if !reflect.DeepEqual(existingUserGrant.RoleKeys, userGrant.RoleKeys) {
if err = wr.PatchStatus(ctx, condition.SetPatOutOfDate); err != nil {
return err
}
_, err := ztdClient.UpdateUserGrant(ctx, &pb.UpdateUserGrantRequest{ _, err := ztdClient.UpdateUserGrant(ctx, &pb.UpdateUserGrantRequest{
UserId: wr.MachineUser.Status.UserId, UserId: wr.MachineUser.Status.UserId,
GrantId: existingUserGrant.Id, GrantId: existingUserGrant.Id,

View File

@@ -1,111 +0,0 @@
package conditions
import (
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func SetCompleteWithCronJob(c Conditioner, cronJob *batchv1.CronJob) {
setScheduled := func() {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonCronJobScheduled,
Message: "Scheduled",
})
}
if cronJob.Status.LastScheduleTime == nil || cronJob.Status.LastSuccessfulTime == nil {
setScheduled()
return
}
if cronJob.Status.LastSuccessfulTime.Before(cronJob.Status.LastScheduleTime) {
if len(cronJob.Status.Active) > 0 {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonCronJobRunning,
Message: "Running",
})
} else {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonCronJobFailed,
Message: "Failed",
})
}
return
}
if cronJob.Status.LastScheduleTime.Equal(cronJob.Status.LastSuccessfulTime) ||
cronJob.Status.LastScheduleTime.Before(cronJob.Status.LastSuccessfulTime) {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionTrue,
Reason: zitadelv1alpha1.ConditionReasonCronJobSuccess,
Message: "Success",
})
return
}
setScheduled()
}
func SetCompleteWithJob(c Conditioner, job *batchv1.Job) {
switch getJobConditionType(job) {
case batchv1.JobFailed:
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionTrue,
Reason: zitadelv1alpha1.ConditionReasonJobFailed,
Message: "Failed",
})
case batchv1.JobComplete:
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionTrue,
Reason: zitadelv1alpha1.ConditionReasonJobComplete,
Message: "Success",
})
case batchv1.JobSuspended:
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonJobSuspended,
Message: "Suspended",
})
default:
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonJobRunning,
Message: "Running",
})
}
}
func SetCompleteFailedWithMessage(c Conditioner, message string) {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypeComplete,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonFailed,
Message: message,
})
}
func SetCompleteFailed(c Conditioner) {
SetCompleteFailedWithMessage(c, "Failed")
}
func getJobConditionType(job *batchv1.Job) batchv1.JobConditionType {
for _, c := range job.Status.Conditions {
if c.Status == corev1.ConditionFalse {
continue
}
return c.Type
}
return ""
}

25
src/pkg/condition/pat.go Normal file
View File

@@ -0,0 +1,25 @@
package conditions
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1"
)
func SetPatOutOfDate(c Conditioner) {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypePATUpToDate,
Status: metav1.ConditionFalse,
Reason: zitadelv1alpha1.ConditionReasonRolesChanged,
Message: "PAT out of date",
})
}
func SetPatUpToDate(c Conditioner) {
c.SetCondition(metav1.Condition{
Type: zitadelv1alpha1.ConditionTypePATUpToDate,
Status: metav1.ConditionTrue,
Reason: zitadelv1alpha1.ConditionReasonPATUpToDate,
Message: "PAT up to date",
})
}