Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Josh/cf 3767 add cli flag to attach jira ticket in assume #808

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ require (
github.com/common-fate/common-fate v0.15.13
github.com/common-fate/glide-cli v0.6.0
github.com/common-fate/grab v1.3.0
github.com/common-fate/sdk v1.69.0
github.com/common-fate/sdk v1.71.0
github.com/common-fate/xid v1.0.0
github.com/fatih/color v1.16.0
github.com/hashicorp/yamux v0.1.2
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ github.com/common-fate/iso8601 v1.1.0 h1:nrej9shsK1aB4IyOAjZl68xGk8yDuUxVwQjoDzx
github.com/common-fate/iso8601 v1.1.0/go.mod h1:DU4mvUEkkWZUUSJq2aCuNqM1luSb0Pwyb2dLzXS+img=
github.com/common-fate/sdk v1.69.0 h1:EcgIBjAFFvQnCd1/Lj5Wik/bOUMD9xhxDLEmXS1H7Gk=
github.com/common-fate/sdk v1.69.0/go.mod h1:OrXhzB2Y1JSrKGHrb4qRmY+6MF2M3MFb+3edBnessXo=
github.com/common-fate/sdk v1.70.3-0.20241125053707-a6c1defd9189 h1:1MdYrkF18no04kC/VRrr4mqAaQMzHDINJ4jxtDvnoyk=
github.com/common-fate/sdk v1.70.3-0.20241125053707-a6c1defd9189/go.mod h1:OrXhzB2Y1JSrKGHrb4qRmY+6MF2M3MFb+3edBnessXo=
github.com/common-fate/sdk v1.71.0 h1:SA+KZdbkOWBR6SrTculoUlALAGj6ftULdUPgr3Yw7RY=
github.com/common-fate/sdk v1.71.0/go.mod h1:OrXhzB2Y1JSrKGHrb4qRmY+6MF2M3MFb+3edBnessXo=
github.com/common-fate/session-manager-plugin v0.0.0-20240723053832-3d311db99016 h1:WObxQKT/BuR8HWKSGsJ6aQb/cdhvkenkb1KWXNyPWeE=
github.com/common-fate/session-manager-plugin v0.0.0-20240723053832-3d311db99016/go.mod h1:glAZTUB+4Eg0JVLC3B/YEomJv6QHcNS3klJjw9HC5Y8=
github.com/common-fate/updatecheck v0.3.5 h1:UGIKMnYwuHjbhhCaisLz1pNPg8Z1nXEoWcfqT+4LkAg=
Expand Down
15 changes: 8 additions & 7 deletions pkg/assume/assume.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func AssumeCommand(c *cli.Context) error {
}

reason := assumeFlags.String("reason")

attachments := assumeFlags.StringSlice("attach")
cfg, err := config.Load()
if err != nil {
return err
Expand Down Expand Up @@ -350,12 +350,13 @@ func AssumeCommand(c *cli.Context) error {
}

noAccessInput := accessrequesthook.NoAccessInput{
Profile: profile,
Reason: reason,
Duration: apiDuration,
Confirm: assumeFlags.Bool("confirm"),
Wait: wait,
StartTime: time.Now(),
Profile: profile,
Reason: reason,
Attachments: attachments,
Duration: apiDuration,
Confirm: assumeFlags.Bool("confirm"),
Wait: wait,
StartTime: time.Now(),
}
retry, justActivated, hookErr := hook.NoAccess(c.Context, noAccessInput)
if hookErr != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/assume/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func GlobalFlags() []cli.Flag {
&cli.BoolFlag{Name: "no-cache", Usage: "Disables caching of session credentials and forces a refresh", EnvVars: []string{"GRANTED_NO_CACHE"}},
&cli.StringSliceFlag{Name: "browser-launch-template-arg", Usage: "Additional arguments to provide to the browser launch template command in key=value format, e.g. '--browser-launch-template-arg foo=bar"},
&cli.BoolFlag{Name: "skip-profile-registry-sync", Usage: "You can use this to skip the automated profile registry sync process."},
&cli.StringSliceFlag{Name: "attach", Usage: "Attach justifications to your request, such as a Jira ticket id or url `--attach=TP-123`"},
}
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/granted/eks/eks.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var proxyCommand = cli.Command{
&cli.StringFlag{Name: "target", Aliases: []string{"cluster"}},
&cli.StringFlag{Name: "role", Aliases: []string{"service-account"}},
&cli.StringFlag{Name: "reason", Usage: "Provide a reason for requesting access to the role"},
&cli.StringSliceFlag{Name: "attach", Usage: "Attach justifications to your request, such as a Jira ticket id or url `--attach=TP-123`"},
&cli.BoolFlag{Name: "confirm", Aliases: []string{"y"}, Usage: "Skip confirmation prompts for access requests"},
&cli.BoolFlag{Name: "wait", Value: true, Usage: "Wait for the access request to be approved."},
&cli.BoolFlag{Name: "no-cache", Usage: "Disables caching of session credentials and forces a refresh", EnvVars: []string{"GRANTED_NO_CACHE"}},
Expand All @@ -59,6 +60,7 @@ var proxyCommand = cli.Command{
Role: c.String("role"),
Duration: c.Duration("duration"),
Reason: c.String("reason"),
Attachments: c.StringSlice("attach"),
Confirm: c.Bool("confirm"),
Wait: c.Bool("wait"),
PromptForEntitlement: promptForClusterAndRole,
Expand Down
16 changes: 9 additions & 7 deletions pkg/granted/proxy/ensureaccess.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type EnsureAccessInput[T any] struct {
Role string
Duration time.Duration
Reason string
Attachments []string
Confirm bool
Wait bool
PromptForEntitlement func(ctx context.Context, cfg *config.Context) (*accessv1alpha1.Entitlement, error)
Expand All @@ -42,13 +43,14 @@ type EnsureAccessOutput[T any] struct {
func EnsureAccess[T any](ctx context.Context, cfg *config.Context, input EnsureAccessInput[T]) (*EnsureAccessOutput[T], error) {

accessRequestInput := accessrequesthook.NoEntitlementAccessInput{
Target: input.Target,
Role: input.Role,
Reason: input.Reason,
Duration: durationOrDefault(input.Duration),
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: time.Now(),
Target: input.Target,
Role: input.Role,
Reason: input.Reason,
Attachments: input.Attachments,
Duration: durationOrDefault(input.Duration),
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: time.Now(),
}

if accessRequestInput.Target == "" && accessRequestInput.Role == "" {
Expand Down
2 changes: 2 additions & 0 deletions pkg/granted/rds/rds.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var proxyCommand = cli.Command{
&cli.StringFlag{Name: "role", Aliases: []string{"user"}},
&cli.IntFlag{Name: "port", Usage: "The local port to forward the database connection to"},
&cli.StringFlag{Name: "reason", Usage: "Provide a reason for requesting access to the role"},
&cli.StringSliceFlag{Name: "attach", Usage: "Attach justifications to your request, such as a Jira ticket id or url `--attach=TP-123`"},
&cli.BoolFlag{Name: "confirm", Aliases: []string{"y"}, Usage: "Skip confirmation prompts for access requests"},
&cli.BoolFlag{Name: "wait", Value: true, Usage: "Wait for the access request to be approved."},
&cli.BoolFlag{Name: "no-cache", Usage: "Disables caching of session credentials and forces a refresh", EnvVars: []string{"GRANTED_NO_CACHE"}},
Expand All @@ -62,6 +63,7 @@ var proxyCommand = cli.Command{
Role: c.String("role"),
Duration: c.Duration("duration"),
Reason: c.String("reason"),
Attachments: c.StringSlice("attach"),
Confirm: c.Bool("confirm"),
Wait: c.Bool("wait"),
PromptForEntitlement: promptForDatabaseAndUser,
Expand Down
10 changes: 6 additions & 4 deletions pkg/granted/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var latestCommand = cli.Command{
Usage: "Request access to the latest AWS role you attempted to use",
Flags: []cli.Flag{
&cli.StringFlag{Name: "reason", Usage: "A reason for access"},
&cli.StringSliceFlag{Name: "attach", Usage: "Attach justifications to your request, such as a Jira ticket id or url `--attach=TP-123`"},
&cli.DurationFlag{Name: "duration", Usage: "Duration of request, defaults to max duration of the access rule."},
&cli.BoolFlag{Name: "confirm", Aliases: []string{"y"}, Usage: "Skip confirmation prompts for access requests"},
},
Expand Down Expand Up @@ -105,10 +106,11 @@ var latestCommand = cli.Command{
}

_, _, err = hook.NoAccess(c.Context, accessrequesthook.NoAccessInput{
Profile: profile,
Reason: reason,
Duration: apiDuration,
Confirm: c.Bool("confirm"),
Profile: profile,
Reason: reason,
Attachments: c.StringSlice("attach"),
Duration: apiDuration,
Confirm: c.Bool("confirm"),
})
if err != nil {
return err
Expand Down
94 changes: 67 additions & 27 deletions pkg/hook/accessrequesthook/accessrequesthook.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/briandowns/spinner"
"github.com/common-fate/cli/printdiags"
"github.com/common-fate/clio"
"github.com/common-fate/grab"
"github.com/common-fate/granted/pkg/cfaws"
"github.com/common-fate/granted/pkg/cfcfg"
"github.com/common-fate/sdk/config"
Expand All @@ -31,12 +32,13 @@ import (
type Hook struct{}

type NoAccessInput struct {
Profile *cfaws.Profile
Reason string
Duration *durationpb.Duration
Confirm bool
Wait bool
StartTime time.Time
Profile *cfaws.Profile
Reason string
Attachments []string
Duration *durationpb.Duration
Confirm bool
Wait bool
StartTime time.Time
}

func (h Hook) NoAccess(ctx context.Context, input NoAccessInput) (retry bool, justActivated bool, err error) {
Expand All @@ -53,26 +55,28 @@ func (h Hook) NoAccess(ctx context.Context, input NoAccessInput) (retry bool, ju
clio.Infof("You don't currently have access to %s, checking if we can request access...\t[target=%s, role=%s, url=%s]", input.Profile.Name, target, role, cfg.AccessURL)

retry, _, justActivated, err = h.NoEntitlementAccess(ctx, cfg, NoEntitlementAccessInput{
Target: target.String(),
Role: role,
Reason: input.Reason,
Duration: input.Duration,
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: input.StartTime,
Target: target.String(),
Role: role,
Reason: input.Reason,
Duration: input.Duration,
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: input.StartTime,
Attachments: input.Attachments,
})

return retry, justActivated, err
}

type NoEntitlementAccessInput struct {
Target string
Role string
Reason string
Duration *durationpb.Duration
Confirm bool
Wait bool
StartTime time.Time
Target string
Role string
Reason string
Attachments []string
Duration *durationpb.Duration
Confirm bool
Wait bool
StartTime time.Time
}

func (h Hook) NoEntitlementAccess(ctx context.Context, cfg *config.Context, input NoEntitlementAccessInput) (retry bool, result *accessv1alpha1.BatchEnsureResponse, justActivated bool, err error) {
Expand Down Expand Up @@ -167,6 +171,41 @@ func (h Hook) NoEntitlementAccess(ctx context.Context, cfg *config.Context, inpu
}
}

if len(input.Attachments) > 0 {
req.Justification.Attachments = grab.Map(input.Attachments, func(t string) *accessv1alpha1.AttachmentSpecifier {
return &accessv1alpha1.AttachmentSpecifier{
Specify: &accessv1alpha1.AttachmentSpecifier_Lookup{
Lookup: t,
},
}
})
} else {
if result.Validation != nil && result.Validation.HasJiraTicket {
if !IsTerminal(os.Stdin.Fd()) {
return false, nil, justActivated, errors.New("detected a noninteractive terminal: a jira ticket attachment is required to make this access request, to apply the planned changes please re-run with the --attach flag")
}

var attachment string
msg := "Jira ticket attachment for access (Required)"
reasonPrompt := &survey.Input{
Message: msg,
Help: "Will be stored in audit trails and associated with your request",
}
withStdio := survey.WithStdio(os.Stdin, os.Stderr, os.Stderr)
err = survey.AskOne(reasonPrompt, &attachment, withStdio, survey.WithValidator(survey.Required))

if err != nil {
return false, nil, justActivated, err
}

req.Justification.Attachments = append(req.Justification.Attachments, &accessv1alpha1.AttachmentSpecifier{
Specify: &accessv1alpha1.AttachmentSpecifier_Lookup{
Lookup: attachment,
},
})
}
}

// the spinner must be started after prompting for reason, otherwise the prompt gets hidden
si := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
si.Suffix = " ensuring access..."
Expand Down Expand Up @@ -276,13 +315,14 @@ func (h Hook) RetryAccess(ctx context.Context, input NoAccessInput) error {
target := eid.New("AWS::Account", input.Profile.AWSConfig.SSOAccountID)
role := input.Profile.AWSConfig.SSORoleName
_, err = h.RetryNoEntitlementAccess(ctx, cfg, NoEntitlementAccessInput{
Target: target.String(),
Role: role,
Reason: input.Reason,
Duration: input.Duration,
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: input.StartTime,
Target: target.String(),
Role: role,
Reason: input.Reason,
Duration: input.Duration,
Confirm: input.Confirm,
Wait: input.Wait,
StartTime: input.StartTime,
Attachments: input.Attachments,
})
return err
}
Expand Down
Loading