@@ -6,17 +6,16 @@ import (
66 "log/slog"
77 "os"
88 "path"
9- "strconv"
109 "strings"
1110 "time"
1211
1312 "github.com/argoproj/argo-cd/v2/pkg/apiclient"
14- "github.com/argoproj/argo-cd/v2/pkg/apiclient/account"
1513 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
1614 "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate"
1715 "github.com/argoproj/argo-cd/v2/pkg/apiclient/project"
1816 "github.com/argoproj/argo-cd/v2/pkg/apiclient/session"
1917 argoCDV1Aplha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
18+ "github.com/argoproj/argo-cd/v2/util/rbac"
2019 "github.com/aws/aws-sdk-go-v2/aws"
2120 "google.golang.org/grpc/codes"
2221 "google.golang.org/grpc/status"
@@ -71,14 +70,6 @@ func InstallAndSetupArgoCD(ctx context.Context, clusterDir string, clusterClient
7170
7271 Namespace : constants .NamespaceArgoCD ,
7372 ReleaseName : constants .ReleaseNameArgoCD ,
74-
75- Values : map [string ]any {
76- "argo-cd" : map [string ]any {
77- "configs" : map [string ]any {
78- "cm" : getArgoCDConfigMapOptions (),
79- },
80- },
81- },
8273 })
8374
8475 // Port-forward ArgoCD and create ArgoCD client.
@@ -123,44 +114,13 @@ func InstallAndSetupArgoCD(ctx context.Context, clusterDir string, clusterClient
123114 if (config .ParsedGeneralConfig .Obmondo != nil ) &&
124115 (config .ParsedGeneralConfig .Obmondo .Monitoring ) {
125116
126- argoCDAccountClientCloser , argoCDAccountClient := argoCDClient .NewAccountClientOrDie ()
127- defer argoCDAccountClientCloser .Close ()
117+ projectClientCloser , projectClient := argoCDClient .NewProjectClientOrDie ()
118+ defer projectClientCloser .Close ()
128119
129- setupKubeAgentArgoCDAccount (ctx , argoCDAccountClient , clusterClient )
120+ setupKubeAgentArgoCDProjectRole (ctx , projectClient , clusterClient )
130121 }
131122}
132123
133- func getArgoCDConfigMapOptions () map [string ]any {
134- argoCDConfigMapOptions := map [string ]any {
135- /*
136- For ArgoCD-CrossPlane integration, we need to use annotation based application resource
137- tracking.
138-
139- You ask why? Let me explain :
140-
141- Suppose, we define an XR claim (which is namespace scoped) in our git repository. The
142- 'infrastructure' ArgoCD App is tracking this XR Claim.
143- The XR Claim will dynamically generate an XR (which is cluster scoped). And this XR
144- will derive the 'argocd.argoproj.io/instance' label from its parent XR Claim.
145-
146- So, the situation is : we have a dynamically generated XR, not defined in git, but
147- being tracked by ArgoCD, because of that derived label.
148- This will cause the 'infrastructure' ArgoCD App to be always out of sync. Additionally,
149- if someone syncs the 'infrastructure' ArgoCD App, with pruning enabled, then ArgoCD
150- will delete those XRs.
151- */
152- "application.resourceTrackingMethod" : "annotation" ,
153- }
154-
155- // When the user is an Obmondo customer, KubeAid Agent will get deployed to the cluster.
156- // We need to create an ArgoCD account for KubeAid Agent.
157- if config .ParsedGeneralConfig .Obmondo != nil {
158- argoCDConfigMapOptions ["accounts.kubeaid-agent" ] = "apiKey"
159- }
160-
161- return argoCDConfigMapOptions
162- }
163-
164124// Port-forwards the ArgoCD server and creates an ArgoCD client.
165125// Returns the ArgoCD client.
166126func NewArgoCDClient (ctx context.Context , clusterClient client.Client ) apiclient.Client {
@@ -275,9 +235,17 @@ func SyncAllArgoCDApps(ctx context.Context) {
275235 assert .AssertErrNil (ctx , err , "Failed listing ArgoCD apps" )
276236
277237 for _ , item := range response .Items {
238+ // Skip syncing argocd ArgoCD app while syncing other ArgoCD apps.
239+ if item .Name == constants .ArgoCDAppArgoCD {
240+ continue
241+ }
242+
278243 SyncArgoCDApp (ctx , item .Name , []* argoCDV1Aplha1.SyncOperationResource {})
279244 }
280245 }
246+
247+ // Lastly, sync the argocd ArgoCD app.
248+ SyncArgoCDApp (ctx , constants .ArgoCDAppArgoCD , []* argoCDV1Aplha1.SyncOperationResource {})
281249}
282250
283251// Syncs the ArgoCD App (if not synced already).
@@ -441,55 +409,104 @@ func isArgoCDAppSynced(
441409 }
442410}
443411
444- func setupKubeAgentArgoCDAccount (ctx context.Context ,
445- argoCDAccountServiceClient account. AccountServiceClient ,
412+ func setupKubeAgentArgoCDProjectRole (ctx context.Context ,
413+ projectClient project. ProjectServiceClient ,
446414 clusterClient client.Client ,
447415) {
448- // During Helm installation, an ArgoCD account for KubeAid Agent got created.
449- // Unfortunately, ArgoCD will not auto-generate an initial password for that account.
450- // So, we need to do it ourselves. And save it in the 'argocd-initial-kubeaid-agent-secret'
451- // Kubernetes Secret, from where KubeAid Agent can pick it up.
452-
453- slog .InfoContext (ctx , "Setting up KubeAid Agent ArgoCD account" )
416+ // We'll create a project token for the 'kubeaid-agent' role.
417+ // And save it in the 'argocd-project-role-kubeaid-agent' Kubernetes Secret with token
418+ // from where KubeAid Agent can pick it up.
419+ slog .InfoContext (ctx , "Setting up KubeAid Agent ArgoCD project role" )
454420
455- // Generate a random password.
456- password := strconv .Itoa (int (time .Now ().Unix ()))
421+ projectQuery := & project.ProjectQuery {
422+ Name : constants .ArgoCDProjectKubeAid ,
423+ }
457424
458- // Use it for the KubeAid Agent user.
459- _ , err := argoCDAccountServiceClient .UpdatePassword (ctx , & account.UpdatePasswordRequest {
460- Name : "kubeaid-agent" ,
461- CurrentPassword : getArgoCDAdminPassword (ctx , clusterClient ),
462- NewPassword : password ,
463- })
425+ // Fetch 'kubeaid' project details
426+ kubeAidProject , err := projectClient .Get (ctx , projectQuery )
464427 assert .AssertErrNil (ctx , err ,
465- "Failed generating initial password for KubeAid Agent ArgoCD account " ,
428+ "Failed fetching KubeAid project details " ,
466429 )
467430
468- // Store it in the 'argocd-initial-kubeaid-agent-secret' Kubernetes Secret.
431+ description := "Role kubeaid-agent to perform necessary operations via KubeAid Agent"
432+ policies := []string {
433+ getKubeAidAgentRolePolicy (
434+ rbac .ResourceApplications ,
435+ rbac .ActionGet ,
436+ constants .ArgoCDRBACEffectAllow ,
437+ ),
438+ getKubeAidAgentRolePolicy (
439+ rbac .ResourceApplications ,
440+ rbac .ActionSync ,
441+ constants .ArgoCDRBACEffectAllow ,
442+ ),
443+ }
444+ projectRole := argoCDV1Aplha1.ProjectRole {
445+ Name : constants .ArgoCDRoleKubeAidAgent ,
446+ Description : description ,
447+ Policies : policies ,
448+ Groups : []string {constants .ArgoCDRoleKubeAidAgent },
449+ }
450+ kubeAidProject .Spec .Roles = append (kubeAidProject .Spec .Roles , projectRole )
469451
470- secretName := "argocd-initial-kubeaid-agent-secret"
452+ // Update the project 'kubeaid' by adding role 'kubeaid-agent' details
453+ projectRequest := & project.ProjectUpdateRequest {
454+ Project : kubeAidProject ,
455+ }
456+ _ , err = projectClient .Update (ctx , projectRequest )
457+ assert .AssertErrNil (ctx , err ,
458+ "Failed updating KubeAid project with KubeAid Agent role details" ,
459+ )
471460
472- argoCDInitialKubeAidAgentSecret := & coreV1.Secret {
461+ // Generate the 'kubeaid-agent' project token with no expiry.
462+ // KubeAid Agent is then uses this token to perform sync operations.
463+ tokenRequest := & project.ProjectTokenCreateRequest {
464+ Project : constants .ArgoCDProjectKubeAid ,
465+ Role : constants .ArgoCDRoleKubeAidAgent ,
466+ }
467+ tokenResponse , err := projectClient .CreateToken (ctx , tokenRequest )
468+ assert .AssertErrNil (ctx , err ,
469+ "Failed generating KubeAid project token for KubeAid Agent role" ,
470+ )
471+
472+ // Store it in the 'argocd-project-role-kubeaid-agent' Kubernetes Secret.
473+ // We adding a label to identify the secret was created by 'kubeaid-bootstrap-script'.
474+ secretObj := & coreV1.Secret {
473475 ObjectMeta : metaV1.ObjectMeta {
474- Name : secretName ,
476+ Name : constants . ArgoCDProjectRoleSecretName ,
475477 Namespace : constants .NamespaceArgoCD ,
478+ Labels : map [string ]string {
479+ constants .ArgoCDLabelKeyManagedBy : constants .ArgoCDProjectKubeAid ,
480+ },
476481 },
477482
478483 StringData : map [string ]string {
479- "password " : password ,
484+ "token " : tokenResponse . GetToken () ,
480485 },
481486 }
482- err = clusterClient .Create (ctx , argoCDInitialKubeAidAgentSecret , & client.CreateOptions {})
487+ err = clusterClient .Create (ctx , secretObj , & client.CreateOptions {})
483488 if k8sAPIErrors .IsAlreadyExists (err ) {
484489 return
485490 }
486491 assert .AssertErrNil (ctx , err ,
487492 "Failed creating Kubernetes Secret" ,
488- slog .String ("secret" , secretName ),
493+ slog .String ("secret" , constants . ArgoCDProjectRoleSecretName ),
489494 slog .String ("namespace" , constants .NamespaceArgoCD ),
490495 )
491496}
492497
498+ func getKubeAidAgentRolePolicy (resource , action , effect string ) string {
499+ return fmt .Sprintf (
500+ constants .ArgoCDProjectRolePolicyFmt ,
501+ constants .ArgoCDProjectKubeAid ,
502+ constants .ArgoCDRoleKubeAidAgent ,
503+ resource ,
504+ action ,
505+ constants .ArgoCDProjectKubeAid ,
506+ effect ,
507+ )
508+ }
509+
493510// Returns the initial ArgoCD admin password.
494511func getArgoCDAdminPassword (ctx context.Context , clusterClient client.Client ) string {
495512 argoCDInitialAdminSecret := & coreV1.Secret {}
0 commit comments