github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/project_role.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "text/tabwriter" 8 "time" 9 10 timeutil "github.com/argoproj/pkg/v2/time" 11 jwtgo "github.com/golang-jwt/jwt/v5" 12 "github.com/spf13/cobra" 13 14 "github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless" 15 "github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils" 16 argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient" 17 projectpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/project" 18 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 19 "github.com/argoproj/argo-cd/v3/util/errors" 20 utilio "github.com/argoproj/argo-cd/v3/util/io" 21 "github.com/argoproj/argo-cd/v3/util/jwt" 22 "github.com/argoproj/argo-cd/v3/util/rbac" 23 "github.com/argoproj/argo-cd/v3/util/templates" 24 ) 25 26 const ( 27 policyTemplate = "p, proj:%s:%s, %s, %s, %s/%s, %s" 28 ) 29 30 // NewProjectRoleCommand returns a new instance of the `argocd proj role` command 31 func NewProjectRoleCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 32 roleCommand := &cobra.Command{ 33 Use: "role", 34 Short: "Manage a project's roles", 35 Run: func(c *cobra.Command, args []string) { 36 c.HelpFunc()(c, args) 37 os.Exit(1) 38 }, 39 } 40 roleCommand.AddCommand(NewProjectRoleListCommand(clientOpts)) 41 roleCommand.AddCommand(NewProjectRoleGetCommand(clientOpts)) 42 roleCommand.AddCommand(NewProjectRoleCreateCommand(clientOpts)) 43 roleCommand.AddCommand(NewProjectRoleDeleteCommand(clientOpts)) 44 roleCommand.AddCommand(NewProjectRoleCreateTokenCommand(clientOpts)) 45 roleCommand.AddCommand(NewProjectRoleListTokensCommand(clientOpts)) 46 roleCommand.AddCommand(NewProjectRoleDeleteTokenCommand(clientOpts)) 47 roleCommand.AddCommand(NewProjectRoleAddPolicyCommand(clientOpts)) 48 roleCommand.AddCommand(NewProjectRoleRemovePolicyCommand(clientOpts)) 49 roleCommand.AddCommand(NewProjectRoleAddGroupCommand(clientOpts)) 50 roleCommand.AddCommand(NewProjectRoleRemoveGroupCommand(clientOpts)) 51 return roleCommand 52 } 53 54 // NewProjectRoleAddPolicyCommand returns a new instance of an `argocd proj role add-policy` command 55 func NewProjectRoleAddPolicyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 56 var opts policyOpts 57 command := &cobra.Command{ 58 Use: "add-policy PROJECT ROLE-NAME", 59 Short: "Add a policy to a project role", 60 Example: `# Before adding new policy 61 $ argocd proj role get test-project test-role 62 Role Name: test-role 63 Description: 64 Policies: 65 p, proj:test-project:test-role, projects, get, test-project, allow 66 JWT Tokens: 67 ID ISSUED-AT EXPIRES-AT 68 1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) <none> 69 70 # Add a new policy to allow update to the project 71 $ argocd proj role add-policy test-project test-role -a update -p allow -o project 72 73 # Policy should be updated 74 $ argocd proj role get test-project test-role 75 Role Name: test-role 76 Description: 77 Policies: 78 p, proj:test-project:test-role, projects, get, test-project, allow 79 p, proj:test-project:test-role, applications, update, test-project/project, allow 80 JWT Tokens: 81 ID ISSUED-AT EXPIRES-AT 82 1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) <none> 83 84 # Add a new policy to allow get logs to the project 85 $ argocd proj role add-policy test-project test-role -a get -p allow -o project -r logs 86 87 # Policy should be updated 88 $ argocd proj role get test-project test-role 89 Role Name: test-role 90 Description: 91 Policies: 92 p, proj:test-project:test-role, projects, get, test-project, allow 93 p, proj:test-project:test-role, applications, update, test-project/project, allow 94 p, proj:test-project:test-role, logs, get, test-project/project, allow 95 JWT Tokens: 96 ID ISSUED-AT EXPIRES-AT 97 1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) <none> 98 `, 99 Run: func(c *cobra.Command, args []string) { 100 ctx := c.Context() 101 102 if len(args) != 2 || !rbac.ProjectScoped[opts.resource] { 103 c.HelpFunc()(c, args) 104 os.Exit(1) 105 } 106 projName := args[0] 107 roleName := args[1] 108 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 109 defer utilio.Close(conn) 110 111 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 112 errors.CheckError(err) 113 114 role, roleIndex, err := proj.GetRoleByName(roleName) 115 errors.CheckError(err) 116 117 policy := fmt.Sprintf(policyTemplate, proj.Name, role.Name, opts.resource, opts.action, proj.Name, opts.object, opts.permission) 118 proj.Spec.Roles[roleIndex].Policies = append(role.Policies, policy) 119 120 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 121 errors.CheckError(err) 122 }, 123 } 124 addPolicyFlags(command, &opts) 125 return command 126 } 127 128 // NewProjectRoleRemovePolicyCommand returns a new instance of an `argocd proj role remove-policy` command 129 func NewProjectRoleRemovePolicyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 130 var opts policyOpts 131 command := &cobra.Command{ 132 Use: "remove-policy PROJECT ROLE-NAME", 133 Short: "Remove a policy from a role within a project", 134 Example: `List the policy of the test-role before removing a policy 135 $ argocd proj role get test-project test-role 136 Role Name: test-role 137 Description: 138 Policies: 139 p, proj:test-project:test-role, projects, get, test-project, allow 140 p, proj:test-project:test-role, applications, update, test-project/project, allow 141 p, proj:test-project:test-role, logs, get, test-project/project, allow 142 JWT Tokens: 143 ID ISSUED-AT EXPIRES-AT 144 1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) <none> 145 146 # Remove the policy to allow update to objects 147 $ argocd proj role remove-policy test-project test-role -a update -p allow -o project 148 149 # The role should be removed now. 150 $ argocd proj role get test-project test-role 151 Role Name: test-role 152 Description: 153 Policies: 154 p, proj:test-project:test-role, projects, get, test-project, allow 155 p, proj:test-project:test-role, logs, get, test-project/project, allow 156 JWT Tokens: 157 ID ISSUED-AT EXPIRES-AT 158 1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) <none> 159 160 161 # Remove the logs read policy 162 $ argocd proj role remove-policy test-project test-role -a get -p allow -o project -r logs 163 164 # The role should be removed now. 165 $ argocd proj role get test-project test-role 166 Role Name: test-role 167 Description: 168 Policies: 169 p, proj:test-project:test-role, projects, get, test-project, allow 170 JWT Tokens: 171 ID ISSUED-AT EXPIRES-AT 172 1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) <none> 173 `, 174 Run: func(c *cobra.Command, args []string) { 175 ctx := c.Context() 176 177 if len(args) != 2 || !rbac.ProjectScoped[opts.resource] { 178 c.HelpFunc()(c, args) 179 os.Exit(1) 180 } 181 projName := args[0] 182 roleName := args[1] 183 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 184 defer utilio.Close(conn) 185 186 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 187 errors.CheckError(err) 188 189 role, roleIndex, err := proj.GetRoleByName(roleName) 190 errors.CheckError(err) 191 192 policyToRemove := fmt.Sprintf(policyTemplate, proj.Name, role.Name, opts.resource, opts.action, proj.Name, opts.object, opts.permission) 193 duplicateIndex := -1 194 for i, policy := range role.Policies { 195 if policy == policyToRemove { 196 duplicateIndex = i 197 break 198 } 199 } 200 if duplicateIndex < 0 { 201 return 202 } 203 role.Policies[duplicateIndex] = role.Policies[len(role.Policies)-1] 204 proj.Spec.Roles[roleIndex].Policies = role.Policies[:len(role.Policies)-1] 205 206 promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled) 207 canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to delete '%s' policy? [y/n]", policyToRemove)) 208 if canDelete { 209 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 210 errors.CheckError(err) 211 } else { 212 fmt.Printf("The command to delete policy '%s' was cancelled.\n", policyToRemove) 213 } 214 }, 215 } 216 addPolicyFlags(command, &opts) 217 return command 218 } 219 220 // NewProjectRoleCreateCommand returns a new instance of an `argocd proj role create` command 221 func NewProjectRoleCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 222 var description string 223 command := &cobra.Command{ 224 Use: "create PROJECT ROLE-NAME", 225 Short: "Create a project role", 226 Example: templates.Examples(` 227 # Create a project role in the "my-project" project with the name "my-role". 228 argocd proj role create my-project my-role --description "My project role description" 229 `), 230 231 Run: func(c *cobra.Command, args []string) { 232 ctx := c.Context() 233 234 if len(args) != 2 { 235 c.HelpFunc()(c, args) 236 os.Exit(1) 237 } 238 projName := args[0] 239 roleName := args[1] 240 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 241 defer utilio.Close(conn) 242 243 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 244 errors.CheckError(err) 245 246 _, _, err = proj.GetRoleByName(roleName) 247 if err == nil { 248 fmt.Printf("Role '%s' already exists\n", roleName) 249 return 250 } 251 proj.Spec.Roles = append(proj.Spec.Roles, v1alpha1.ProjectRole{Name: roleName, Description: description}) 252 253 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 254 errors.CheckError(err) 255 fmt.Printf("Role '%s' created\n", roleName) 256 }, 257 } 258 command.Flags().StringVarP(&description, "description", "", "", "Project description") 259 return command 260 } 261 262 // NewProjectRoleDeleteCommand returns a new instance of an `argocd proj role delete` command 263 func NewProjectRoleDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 264 command := &cobra.Command{ 265 Use: "delete PROJECT ROLE-NAME", 266 Short: "Delete a project role", 267 Example: `$ argocd proj role delete test-project test-role`, 268 Run: func(c *cobra.Command, args []string) { 269 ctx := c.Context() 270 271 if len(args) != 2 { 272 c.HelpFunc()(c, args) 273 os.Exit(1) 274 } 275 projName := args[0] 276 roleName := args[1] 277 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 278 defer utilio.Close(conn) 279 280 promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled) 281 282 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 283 errors.CheckError(err) 284 285 _, index, err := proj.GetRoleByName(roleName) 286 if err != nil { 287 fmt.Printf("Role '%s' does not exist in project\n", roleName) 288 return 289 } 290 proj.Spec.Roles[index] = proj.Spec.Roles[len(proj.Spec.Roles)-1] 291 proj.Spec.Roles = proj.Spec.Roles[:len(proj.Spec.Roles)-1] 292 293 canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to delete '%s' role? [y/n]", roleName)) 294 if canDelete { 295 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 296 errors.CheckError(err) 297 fmt.Printf("Role '%s' deleted\n", roleName) 298 } else { 299 fmt.Printf("The command to delete role '%s' was cancelled.\n", roleName) 300 } 301 }, 302 } 303 return command 304 } 305 306 func tokenTimeToString(t int64) string { 307 tokenTimeToString := "Never" 308 if t > 0 { 309 tokenTimeToString = time.Unix(t, 0).Format(time.RFC3339) 310 } 311 return tokenTimeToString 312 } 313 314 // NewProjectRoleCreateTokenCommand returns a new instance of an `argocd proj role create-token` command 315 func NewProjectRoleCreateTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 316 var ( 317 expiresIn string 318 outputTokenOnly bool 319 tokenID string 320 ) 321 command := &cobra.Command{ 322 Use: "create-token PROJECT ROLE-NAME", 323 Short: "Create a project token", 324 Example: `$ argocd proj role create-token test-project test-role 325 Create token succeeded for proj:test-project:test-role. 326 ID: f316c466-40bd-4cfd-8a8c-1392e92255d4 327 Issued At: 2023-10-08T15:21:40+01:00 328 Expires At: Never 329 Token: xxx 330 `, 331 Aliases: []string{"token-create"}, 332 Run: func(c *cobra.Command, args []string) { 333 ctx := c.Context() 334 335 if len(args) != 2 { 336 c.HelpFunc()(c, args) 337 os.Exit(1) 338 } 339 projName := args[0] 340 roleName := args[1] 341 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 342 defer utilio.Close(conn) 343 if expiresIn == "" { 344 expiresIn = "0s" 345 } 346 duration, err := timeutil.ParseDuration(expiresIn) 347 errors.CheckError(err) 348 tokenResponse, err := projIf.CreateToken(ctx, &projectpkg.ProjectTokenCreateRequest{ 349 Project: projName, 350 Role: roleName, 351 ExpiresIn: int64(duration.Seconds()), 352 Id: tokenID, 353 }) 354 errors.CheckError(err) 355 356 token, err := jwtgo.Parse(tokenResponse.Token, nil) 357 if token == nil { 358 err = fmt.Errorf("received malformed token %w", err) 359 errors.CheckError(err) 360 return 361 } 362 363 claims := token.Claims.(jwtgo.MapClaims) 364 365 issuedAt, _ := jwt.IssuedAt(claims) 366 expiresAt := int64(jwt.Float64Field(claims, "exp")) 367 id := jwt.StringField(claims, "jti") 368 subject := jwt.GetUserIdentifier(claims) 369 if !outputTokenOnly { 370 fmt.Printf("Create token succeeded for %s.\n", subject) 371 fmt.Printf(" ID: %s\n Issued At: %s\n Expires At: %s\n", 372 id, tokenTimeToString(issuedAt), tokenTimeToString(expiresAt), 373 ) 374 fmt.Println(" Token: " + tokenResponse.Token) 375 } else { 376 fmt.Println(tokenResponse.Token) 377 } 378 }, 379 } 380 command.Flags().StringVarP(&expiresIn, "expires-in", "e", "", 381 "Duration before the token will expire, e.g. \"12h\", \"7d\". (Default: No expiration)", 382 ) 383 command.Flags().StringVarP(&tokenID, "id", "i", "", "Token unique identifier. (Default: Random UUID)") 384 command.Flags().BoolVarP(&outputTokenOnly, "token-only", "t", false, "Output token only - for use in scripts.") 385 386 return command 387 } 388 389 func NewProjectRoleListTokensCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 390 var useUnixTime bool 391 command := &cobra.Command{ 392 Use: "list-tokens PROJECT ROLE-NAME", 393 Short: "List tokens for a given role.", 394 Example: `$ argocd proj role list-tokens test-project test-role 395 ID ISSUED AT EXPIRES AT 396 f316c466-40bd-4cfd-8a8c-1392e92255d4 2023-10-08T15:21:40+01:00 Never 397 fa9d3517-c52d-434c-9bff-215b38508842 2023-10-08T11:08:18+01:00 Never 398 `, 399 Aliases: []string{"list-token", "token-list"}, 400 Run: func(c *cobra.Command, args []string) { 401 ctx := c.Context() 402 403 if len(args) != 2 { 404 c.HelpFunc()(c, args) 405 os.Exit(1) 406 } 407 projName := args[0] 408 roleName := args[1] 409 410 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 411 defer utilio.Close(conn) 412 413 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 414 errors.CheckError(err) 415 role, _, err := proj.GetRoleByName(roleName) 416 errors.CheckError(err) 417 418 if len(role.JWTTokens) == 0 { 419 fmt.Printf("No tokens for %s.%s\n", projName, roleName) 420 return 421 } 422 423 writer := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0) 424 _, err = fmt.Fprintf(writer, "ID\tISSUED AT\tEXPIRES AT\n") 425 errors.CheckError(err) 426 427 tokenRowFormat := "%s\t%v\t%v\n" 428 for _, token := range role.JWTTokens { 429 if useUnixTime { 430 _, _ = fmt.Fprintf(writer, tokenRowFormat, token.ID, token.IssuedAt, token.ExpiresAt) 431 } else { 432 _, _ = fmt.Fprintf(writer, tokenRowFormat, token.ID, tokenTimeToString(token.IssuedAt), tokenTimeToString(token.ExpiresAt)) 433 } 434 } 435 err = writer.Flush() 436 errors.CheckError(err) 437 }, 438 } 439 command.Flags().BoolVarP(&useUnixTime, "unixtime", "u", false, 440 "Print timestamps as Unix time instead of converting. Useful for piping into delete-token.", 441 ) 442 return command 443 } 444 445 // NewProjectRoleDeleteTokenCommand returns a new instance of an `argocd proj role delete-token` command 446 func NewProjectRoleDeleteTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 447 command := &cobra.Command{ 448 Use: "delete-token PROJECT ROLE-NAME ISSUED-AT", 449 Short: "Delete a project token", 450 Example: `#Create project test-project 451 $ argocd proj create test-project 452 453 # Create a role associated with test-project 454 $ argocd proj role create test-project test-role 455 Role 'test-role' created 456 457 # Create test-role associated with test-project 458 $ argocd proj role create-token test-project test-role 459 Create token succeeded for proj:test-project:test-role. 460 ID: c312450e-12e1-4e0d-9f65-fac9cb027b32 461 Issued At: 2023-10-08T13:58:57+01:00 462 Expires At: Never 463 Token: xxx 464 465 # Get test-role id to input into the delete-token command below 466 $ argocd proj role get test-project test-role 467 Role Name: test-role 468 Description: 469 Policies: 470 p, proj:test-project:test-role, projects, get, test-project, allow 471 JWT Tokens: 472 ID ISSUED-AT EXPIRES-AT 473 1696769937 2023-10-08T13:58:57+01:00 (6 minutes ago) <none> 474 475 $ argocd proj role delete-token test-project test-role 1696769937 476 `, 477 Aliases: []string{"token-delete", "remove-token"}, 478 Run: func(c *cobra.Command, args []string) { 479 ctx := c.Context() 480 481 if len(args) != 3 { 482 c.HelpFunc()(c, args) 483 os.Exit(1) 484 } 485 projName := args[0] 486 roleName := args[1] 487 tokenId := args[2] 488 issuedAt, err := strconv.ParseInt(tokenId, 10, 64) 489 errors.CheckError(err) 490 491 promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled) 492 493 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 494 defer utilio.Close(conn) 495 496 canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to delete '%s' project token? [y/n]", tokenId)) 497 if canDelete { 498 _, err = projIf.DeleteToken(ctx, &projectpkg.ProjectTokenDeleteRequest{Project: projName, Role: roleName, Iat: issuedAt}) 499 errors.CheckError(err) 500 } else { 501 fmt.Printf("The command to delete project token '%s' was cancelled.\n", tokenId) 502 } 503 }, 504 } 505 return command 506 } 507 508 // Print list of project role names 509 func printProjectRoleListName(roles []v1alpha1.ProjectRole) { 510 for _, role := range roles { 511 fmt.Println(role.Name) 512 } 513 } 514 515 // Print table of project roles 516 func printProjectRoleListTable(roles []v1alpha1.ProjectRole) { 517 w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) 518 fmt.Fprintf(w, "ROLE-NAME\tDESCRIPTION\n") 519 for _, role := range roles { 520 fmt.Fprintf(w, "%s\t%s\n", role.Name, role.Description) 521 } 522 _ = w.Flush() 523 } 524 525 // NewProjectRoleListCommand returns a new instance of an `argocd proj roles list` command 526 func NewProjectRoleListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 527 var output string 528 command := &cobra.Command{ 529 Use: "list PROJECT", 530 Short: "List all the roles in a project", 531 Example: templates.Examples(` 532 # This command will list all the roles in argocd-project in a default table format. 533 argocd proj role list PROJECT 534 535 # List the roles in the project in formats like json, yaml, wide, or name. 536 argocd proj role list PROJECT --output json 537 538 `), 539 540 Run: func(c *cobra.Command, args []string) { 541 ctx := c.Context() 542 543 if len(args) != 1 { 544 c.HelpFunc()(c, args) 545 os.Exit(1) 546 } 547 projName := args[0] 548 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 549 defer utilio.Close(conn) 550 551 project, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 552 errors.CheckError(err) 553 switch output { 554 case "json", "yaml": 555 err := PrintResourceList(project.Spec.Roles, output, false) 556 errors.CheckError(err) 557 case "name": 558 printProjectRoleListName(project.Spec.Roles) 559 case "wide", "": 560 printProjectRoleListTable(project.Spec.Roles) 561 default: 562 errors.CheckError(fmt.Errorf("unknown output format: %s", output)) 563 } 564 }, 565 } 566 command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|name") 567 return command 568 } 569 570 // NewProjectRoleGetCommand returns a new instance of an `argocd proj roles get` command 571 func NewProjectRoleGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 572 command := &cobra.Command{ 573 Use: "get PROJECT ROLE-NAME", 574 Short: "Get the details of a specific role", 575 Example: `$ argocd proj role get test-project test-role 576 Role Name: test-role 577 Description: 578 Policies: 579 p, proj:test-project:test-role, projects, get, test-project, allow 580 JWT Tokens: 581 ID ISSUED-AT EXPIRES-AT 582 1696774900 2023-10-08T15:21:40+01:00 (4 minutes ago) <none> 583 1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) <none> 584 `, 585 Run: func(c *cobra.Command, args []string) { 586 ctx := c.Context() 587 588 if len(args) != 2 { 589 c.HelpFunc()(c, args) 590 os.Exit(1) 591 } 592 projName := args[0] 593 roleName := args[1] 594 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 595 defer utilio.Close(conn) 596 597 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 598 errors.CheckError(err) 599 600 role, _, err := proj.GetRoleByName(roleName) 601 errors.CheckError(err) 602 603 printRoleFmtStr := "%-15s%s\n" 604 fmt.Printf(printRoleFmtStr, "Role Name:", roleName) 605 fmt.Printf(printRoleFmtStr, "Description:", role.Description) 606 fmt.Printf("Policies:\n") 607 fmt.Printf("%s\n", proj.ProjectPoliciesString()) 608 fmt.Printf("Groups:\n") 609 // if the group exists in the role 610 // range over each group and print it 611 if v1alpha1.RoleGroupExists(role) { 612 for _, group := range role.Groups { 613 fmt.Printf(" - %s\n", group) 614 } 615 } else { 616 fmt.Println("<none>") 617 } 618 fmt.Printf("JWT Tokens:\n") 619 w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) 620 fmt.Fprintf(w, "ID\tISSUED-AT\tEXPIRES-AT\n") 621 for _, token := range proj.Status.JWTTokensByRole[roleName].Items { 622 expiresAt := "<none>" 623 if token.ExpiresAt > 0 { 624 expiresAt = humanizeTimestamp(token.ExpiresAt) 625 } 626 fmt.Fprintf(w, "%d\t%s\t%s\n", token.IssuedAt, humanizeTimestamp(token.IssuedAt), expiresAt) 627 } 628 _ = w.Flush() 629 }, 630 } 631 return command 632 } 633 634 // NewProjectRoleAddGroupCommand returns a new instance of an `argocd proj role add-group` command 635 func NewProjectRoleAddGroupCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 636 command := &cobra.Command{ 637 Use: "add-group PROJECT ROLE-NAME GROUP-CLAIM", 638 Short: "Add a group claim to a project role", 639 Run: func(c *cobra.Command, args []string) { 640 ctx := c.Context() 641 642 if len(args) != 3 { 643 c.HelpFunc()(c, args) 644 os.Exit(1) 645 } 646 projName, roleName, groupName := args[0], args[1], args[2] 647 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 648 defer utilio.Close(conn) 649 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 650 errors.CheckError(err) 651 updated, err := proj.AddGroupToRole(roleName, groupName) 652 errors.CheckError(err) 653 if !updated { 654 fmt.Printf("Group '%s' already present in role '%s'\n", groupName, roleName) 655 return 656 } 657 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 658 errors.CheckError(err) 659 fmt.Printf("Group '%s' added to role '%s'\n", groupName, roleName) 660 }, 661 } 662 return command 663 } 664 665 // NewProjectRoleRemoveGroupCommand returns a new instance of an `argocd proj role remove-group` command 666 func NewProjectRoleRemoveGroupCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 667 command := &cobra.Command{ 668 Use: "remove-group PROJECT ROLE-NAME GROUP-CLAIM", 669 Short: "Remove a group claim from a role within a project", 670 Run: func(c *cobra.Command, args []string) { 671 ctx := c.Context() 672 673 if len(args) != 3 { 674 c.HelpFunc()(c, args) 675 os.Exit(1) 676 } 677 projName, roleName, groupName := args[0], args[1], args[2] 678 conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() 679 defer utilio.Close(conn) 680 proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) 681 errors.CheckError(err) 682 updated, err := proj.RemoveGroupFromRole(roleName, groupName) 683 errors.CheckError(err) 684 if !updated { 685 fmt.Printf("Group '%s' not present in role '%s'\n", groupName, roleName) 686 return 687 } 688 689 promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled) 690 691 canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to remove '%s' group from role '%s'? [y/n]", groupName, roleName)) 692 693 if canDelete { 694 _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) 695 errors.CheckError(err) 696 fmt.Printf("Group '%s' removed from role '%s'\n", groupName, roleName) 697 } else { 698 fmt.Printf("The command to remove group '%s' from role '%s' was cancelled.\n", groupName, roleName) 699 } 700 }, 701 } 702 return command 703 }