Skip to content

Commit

Permalink
feat: project iam commands (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
JGiola authored Jan 26, 2024
1 parent c2fcbbb commit 05251da
Show file tree
Hide file tree
Showing 43 changed files with 2,008 additions and 495 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `project iam list` command
- `project iam edit` command
- `project iam remove-role` command

### Changed

- update go version to 1.21.6
Expand Down
84 changes: 84 additions & 0 deletions docs/30_commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,90 @@ Available flags for the command:
- `--context`, to specify a different context from the currently selected one
- `--company-id`, to set the ID of the desired Company

### iam

The `project iam` subcommands are used for managing the RBAC permissions associated with a project. Only
**Company Owners** and **Project Administrators** can modify, add or remove RBAC authorization for a project.

#### list

The `project iam list` subcommand allows you to view the list of all the different identity that has access to a
project.

Usage:

```sh
miactl project iam list [flags]
```

Available flags for the command:

- `--groups`, filter IAM entities to show only groups. Mutally exclusive with `users` and `serviceAccounts`
- `--serviceAccounts`, filter IAM entities to show only service accounts. Mutally exclusive with `users` and `groups`
- `--users`, filter IAM entities to show only users. Mutally exclusive with `groups` and `serviceAccounts`
- `--endpoint`, to set the Console endpoint (default is `https://console.cloud.mia-platform.eu`)
- `--certificate-authority`, to provide the path to a custom CA certificate
- `--insecure-skip-tls-verify`, to disallow the check the validity of the certificate of the remote endpoint
- `--context`, to specify a different context from the currently selected one
- `--company-id`, to set the ID of the desired Company
- `--project-id`, to set the ID of the desired Project

#### edit RESOURCE-NAME

The `project iam edit` subcommand allows you to alternatevely update the role assigned to the current project or
one of its environment for one of the different `IAM` entity types:

- `group`
- `service account`
- `user`

Usage:

```sh
miactl project edit [user|group|serviceaccount] [flags]
```

Available flags for the command:

- `--groups`, filter IAM entities to show only groups. Mutally exclusive with `users` and `serviceAccounts`
- `--serviceAccounts`, filter IAM entities to show only service accounts. Mutally exclusive with `users` and `groups`
- `--users`, filter IAM entities to show only users. Mutally exclusive with `groups` and `serviceAccounts`
- `--endpoint`, to set the Console endpoint (default is `https://console.cloud.mia-platform.eu`)
- `--certificate-authority`, to provide the path to a custom CA certificate
- `--insecure-skip-tls-verify`, to disallow the check the validity of the certificate of the remote endpoint
- `--context`, to specify a different context from the currently selected one
- `--company-id`, to set the ID of the desired Company
- `--project-id`, to set the ID of the desired Project
- `--project-role`, the new role for the current project
- `--entity-id`, the entity id to change
- `--environment`, the environment where to change the role
- `--environment-role`, the new role for the selected environment

#### remove-role RESOURCE-NAME

The `project iam remove-role` subcommand allows you to alternatevely delete the custom role assigned to one of the
different `IAM` entity types for the project or one of its environments.

Usage:

```sh
miactl project remove-role [user|group|serviceaccount] [flags]
```

Available flags for the command:

- `--groups`, filter IAM entities to show only groups. Mutally exclusive with `users` and `serviceAccounts`
- `--serviceAccounts`, filter IAM entities to show only service accounts. Mutally exclusive with `users` and `groups`
- `--users`, filter IAM entities to show only users. Mutally exclusive with `groups` and `serviceAccounts`
- `--endpoint`, to set the Console endpoint (default is `https://console.cloud.mia-platform.eu`)
- `--certificate-authority`, to provide the path to a custom CA certificate
- `--insecure-skip-tls-verify`, to disallow the check the validity of the certificate of the remote endpoint
- `--context`, to specify a different context from the currently selected one
- `--company-id`, to set the ID of the desired Company
- `--project-id`, to set the ID of the desired Project
- `--entity-id`, the entity id to change
- `--environment`, set the flag to the environment name for deleting the role for that environment

## deploy

This command allows you to trigger the deploy pipeline for the selected Project.
Expand Down
45 changes: 29 additions & 16 deletions internal/clioptions/clioptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@ type CLIOptions struct {
DeployType string
NoSemVer bool

IAMRole string
IAMRole string
ProjectIAMRole string
EnvironmentIAMRole string
EntityID string

UserEmail string
UserID string
KeepUserGroupMemeberships bool

UserEmails []string
UserIDs []string
GroupID string

ServiceAccountID string

Expand Down Expand Up @@ -152,49 +153,49 @@ func (o *CLIOptions) AddJWTServiceAccountFlags(flags *pflag.FlagSet) {

func (o *CLIOptions) AddEditServiceAccountFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.IAMRole, "role", "r", "", "the new company role for the service account")
flags.StringVarP(&o.ServiceAccountID, "service-account-id", "", "", "the service account id to edit")
flags.StringVar(&o.ServiceAccountID, "service-account-id", "", "the service account id to edit")
}

func (o *CLIOptions) AddRemoveServiceAccountFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.ServiceAccountID, "service-account-id", "", "", "the service account id to remove")
flags.StringVar(&o.ServiceAccountID, "service-account-id", "", "the service account id to remove")
}

func (o *CLIOptions) AddNewUserFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.IAMRole, "role", "r", "", "the company role of the user")
flags.StringVarP(&o.UserEmail, "email", "", "", "the email of the user to add")
flags.StringVar(&o.UserEmail, "email", "", "the email of the user to add")
}

func (o *CLIOptions) AddEditUserFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.IAMRole, "role", "r", "", "the new company role for the user")
flags.StringVarP(&o.UserID, "user-id", "", "", "the user id to edit")
flags.StringVar(&o.EntityID, "user-id", "", "the user id to edit")
}

func (o *CLIOptions) AddRemoveUserFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.UserID, "user-id", "", "", "the user id to remove")
flags.BoolVarP(&o.KeepUserGroupMemeberships, "no-include-groups", "", false, "keep the user membership in the company groups")
flags.StringVar(&o.EntityID, "user-id", "", "the user id to remove")
flags.BoolVar(&o.KeepUserGroupMemeberships, "no-include-groups", false, "keep the user membership in the company groups")
}

func (o *CLIOptions) CreateNewGroupFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.IAMRole, "role", "r", "", "the company role of the group")
}

func (o *CLIOptions) AddNewMembersToGroupFlags(flags *pflag.FlagSet) {
flags.StringSliceVarP(&o.UserEmails, "user-email", "", []string{}, "the list of user email to add to the group")
flags.StringVarP(&o.GroupID, "group-id", "", "", "the group id where to add the users")
flags.StringSliceVar(&o.UserEmails, "user-email", []string{}, "the list of user email to add to the group")
flags.StringVar(&o.EntityID, "group-id", "", "the group id where to add the users")
}

func (o *CLIOptions) AddEditGroupFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.IAMRole, "role", "r", "", "the new company role for the group")
flags.StringVarP(&o.GroupID, "group-id", "", "", "the group id to edit")
flags.StringVar(&o.EntityID, "group-id", "", "the group id to edit")
}

func (o *CLIOptions) AddRemoveGroupFlags(flags *pflag.FlagSet) {
flags.StringVarP(&o.GroupID, "group-id", "", "", "the group id to remove")
flags.StringVar(&o.EntityID, "group-id", "", "the group id to remove")
}

func (o *CLIOptions) AddRemoveMembersFromGroupFlags(flags *pflag.FlagSet) {
flags.StringSliceVarP(&o.UserIDs, "user-id", "", []string{}, "the list of user id to remove to the group")
flags.StringVarP(&o.GroupID, "group-id", "", "", "the group id where to remove the users")
flags.StringSliceVar(&o.UserIDs, "user-id", []string{}, "the list of user id to remove to the group")
flags.StringVar(&o.EntityID, "group-id", "", "the group id where to remove the users")
}

func (o *CLIOptions) AddMarketplaceApplyFlags(cmd *cobra.Command) {
Expand All @@ -220,7 +221,7 @@ func (o *CLIOptions) AddMarketplaceItemObjectIDFlag(flags *pflag.FlagSet) (flagN

func (o *CLIOptions) AddMarketplaceVersionFlag(flags *pflag.FlagSet) (flagName string) {
flagName = "version"
flags.StringVarP(&o.MarketplaceItemVersion, flagName, "", "", "The version of the Marketplace item")
flags.StringVar(&o.MarketplaceItemVersion, flagName, "", "The version of the Marketplace item")
return
}

Expand All @@ -242,6 +243,18 @@ func (o *CLIOptions) AddIAMListFlags(flags *pflag.FlagSet) {
flags.BoolVar(&o.ShowServiceAccounts, "serviceAccounts", false, "Filter IAM entities to show only service accounts. Mutally exclusive with users and groups")
}

func (o *CLIOptions) AddEditCompanyIAMFlags(flags *pflag.FlagSet) {
flags.StringVar(&o.EntityID, "entity-id", "", "the entity id to change")
flags.StringVar(&o.ProjectIAMRole, "project-role", "", "the new role for the current project")
flags.StringVar(&o.EnvironmentIAMRole, "environment-role", "", "the new role for the selected environment")
flags.StringVar(&o.Environment, "environment", "", "the environment where to change the role")
}

func (o *CLIOptions) AddRemoveProjectIAMRoleFlags(flags *pflag.FlagSet) {
flags.StringVar(&o.EntityID, "entity-id", "", "the entity id to change")
flags.StringVar(&o.Environment, "environment", "", "set the flag to the environment name for deleting the role for that environment")
}

func (o *CLIOptions) ToRESTConfig() (*client.Config, error) {
locator := cliconfig.NewConfigPathLocator()
locator.ExplicitPath = o.MiactlConfig
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/company/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func IAMCmd(o *clioptions.CLIOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "iam",
Short: "Manage Mia-Platform IAM for a company",
Long: `A Company Owner user can manager the access to the company directly to a user,
Long: `A Company Owner user can manage the access to the company directly to a user,
via a group or through service accounts.`,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/company/iam/group/add_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func AddMemberCmd(options *clioptions.CLIOptions) *cobra.Command {
client, err := client.APIClientForConfig(restConfig)
cobra.CheckErr(err)

err = addMemberToGroup(cmd.Context(), client, restConfig.CompanyID, options.GroupID, options.UserEmails)
err = addMemberToGroup(cmd.Context(), client, restConfig.CompanyID, options.EntityID, options.UserEmails)
cobra.CheckErr(err)
},
}
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/company/iam/group/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func AddCmd(options *clioptions.CLIOptions) *cobra.Command {
}

options.CreateNewGroupFlags(cmd.Flags())
err := cmd.RegisterFlagCompletionFunc("role", resources.IAMRoleCompletion)
err := cmd.RegisterFlagCompletionFunc("role", resources.IAMRoleCompletion(false))

if err != nil {
// we panic here because if we reach here, something nasty is happening in flag autocomplete registration
Expand All @@ -59,7 +59,7 @@ func AddCmd(options *clioptions.CLIOptions) *cobra.Command {
}

func createNewGroup(ctx context.Context, client *client.APIClient, companyID, groupName string, role resources.IAMRole) error {
if !resources.IsValidIAMRole(role) {
if !resources.IsValidIAMRole(role, false) {
return fmt.Errorf("invalid service account role %s", role)
}

Expand Down
23 changes: 5 additions & 18 deletions internal/cmd/company/iam/group/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ import (

"github.com/mia-platform/miactl/internal/client"
"github.com/mia-platform/miactl/internal/clioptions"
"github.com/mia-platform/miactl/internal/iam"
"github.com/mia-platform/miactl/internal/resources"
"github.com/spf13/cobra"
)

const (
editGroupRoleTemplate = "/api/companies/%s/groups/%s"
)

func EditCmd(options *clioptions.CLIOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "group",
Expand All @@ -42,13 +39,13 @@ func EditCmd(options *clioptions.CLIOptions) *cobra.Command {
client, err := client.APIClientForConfig(restConfig)
cobra.CheckErr(err)

err = editCompanyGroup(cmd.Context(), client, restConfig.CompanyID, options.GroupID, resources.IAMRole(options.IAMRole))
err = editCompanyGroup(cmd.Context(), client, restConfig.CompanyID, options.EntityID, resources.IAMRole(options.IAMRole))
cobra.CheckErr(err)
},
}

options.AddEditGroupFlags(cmd.Flags())
err := cmd.RegisterFlagCompletionFunc("role", resources.IAMRoleCompletion)
err := cmd.RegisterFlagCompletionFunc("role", resources.IAMRoleCompletion(false))

if err != nil {
// we panic here because if we reach here, something nasty is happening in flag autocomplete registration
Expand All @@ -59,7 +56,7 @@ func EditCmd(options *clioptions.CLIOptions) *cobra.Command {
}

func editCompanyGroup(ctx context.Context, client *client.APIClient, companyID, groupID string, role resources.IAMRole) error {
if !resources.IsValidIAMRole(role) {
if !resources.IsValidIAMRole(role, false) {
return fmt.Errorf("invalid service account role %s", role)
}

Expand All @@ -75,17 +72,7 @@ func editCompanyGroup(ctx context.Context, client *client.APIClient, companyID,
Role: role,
}

body, err := resources.EncodeResourceToJSON(payload)
if err != nil {
return fmt.Errorf("failed to encode request body: %w", err)
}

resp, err := client.
Patch().
APIPath(fmt.Sprintf(editGroupRoleTemplate, companyID, groupID)).
Body(body).
Do(ctx)

resp, err := iam.EditIAMResourceRole(ctx, client, companyID, groupID, iam.GroupsEntityName, payload)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 05251da

Please sign in to comment.