Skip to content

Commit

Permalink
Allow incident IDs to be attached to consoles
Browse files Browse the repository at this point in the history
When consoles are used for incident resolution, we should be tracking
the corresponding incident ID for auditing reasons.

This change allows the incident ID to be included in the console
specifications handled by the k8s operator such that its value can be
read back from downstream consumers of the `ConsoleRequestEvent`.
  • Loading branch information
ivgiuliani committed Feb 18, 2025
1 parent aec5d53 commit 1de12bf
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 8 deletions.
5 changes: 3 additions & 2 deletions apis/workloads/v1alpha1/console_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (

// ConsoleSpec defines the desired state of Console
type ConsoleSpec struct {
User string `json:"user"`
Reason string `json:"reason"`
User string `json:"user"`
Reason string `json:"reason"`
IncidentId string `json:"incident_id"`

// Number of seconds that the console should run for.
// If the process running within the console has not exited before this
Expand Down
1 change: 1 addition & 0 deletions apis/workloads/v1alpha1/lifecycle_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (l *lifecycleEventRecorderImpl) ConsoleRequest(ctx context.Context, csl *Co
Console: csl.Name,
RequiredAuthorisations: authCount,
AuthorisationRuleName: authRuleName,
IncidentId: csl.Spec.IncidentId,
Timestamp: csl.CreationTimestamp.Time,
Labels: csl.Labels,
},
Expand Down
3 changes: 3 additions & 0 deletions cmd/theatre-consoles/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ var (
Duration()
createReason = create.Flag("reason", "Reason for creating console").
String()
createIncidentId = create.Flag("incident-id", "Incident ID linked to the console").
String()
createNoninteractive = create.Flag("noninteractive", "Do not enable TTY and STDIN on console container").
Bool()
createAttach = create.Flag("attach", "Attach to the console if it starts successfully").
Expand Down Expand Up @@ -117,6 +119,7 @@ func Run(ctx context.Context, logger kitlog.Logger) error {
Selector: *createSelector,
Timeout: *createTimeout,
Reason: *createReason,
IncidentId: *createIncidentId,
Command: *createCommand,
Attach: *createAttach,
Noninteractive: *createNoninteractive,
Expand Down
3 changes: 3 additions & 0 deletions config/base/crds/workloads.crd.gocardless.com_consoles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ spec:
type: string
type: object
x-kubernetes-map-type: atomic
incident_id:
type: string
noninteractive:
description: |-
Disable TTY and STDIN on the underlying container. This should usually
Expand Down Expand Up @@ -118,6 +120,7 @@ spec:
type: string
required:
- consoleTemplateRef
- incident_id
- reason
- user
type: object
Expand Down
1 change: 1 addition & 0 deletions controllers/workloads/console/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,7 @@ func getAuditLogger(logger logr.Logger, consoleId string, c *workloadsv1alpha1.C
"console_is_authorised", statusCtx.IsAuthorised,
"command", string(cmdString),
"reason", c.Spec.Reason,
"incident_id", c.Spec.IncidentId,
)

if statusCtx.Pod != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/workloads/console/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type ConsoleRequestSpec struct {
RequiredAuthorisations int `json:"required_authorisations"`
AuthorisationRuleName string `json:"authorisation_rule_name"`
Timestamp time.Time `json:"timestamp"`
IncidentId string `json:"incident_id"`
Labels map[string]string `json:"labels"`
}

Expand Down
8 changes: 6 additions & 2 deletions pkg/workloads/console/runner/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ var _ = Describe("Runner", func() {

cmd := []string{"/bin/rails", "console"}
reason := "reason for console"
createOptions := runner.Options{Cmd: cmd, Reason: reason}
incidentId := "INC-123"
createOptions := runner.Options{Cmd: cmd, Reason: reason, IncidentId: incidentId}

BeforeEach(func() {
namespace = newNamespace("")
Expand All @@ -179,12 +180,15 @@ var _ = Describe("Runner", func() {
By("Referencing the template in the returned console spec")
Expect(console.Spec.ConsoleTemplateRef.Name).To(Equal(consoleTemplate.Name))

By("Seting the specified command in the spec")
By("Setting the specified command in the spec")
Expect(console.Spec.Command).To(Equal(cmd))

By("Setting the specified reason in the spec")
Expect(console.Spec.Reason).To(Equal(reason))

By("Setting the specified incident ID in the spec")
Expect(console.Spec.IncidentId).To(Equal(incidentId))

By("Inheriting labels from console template")
Expect(console.Labels).To(HaveKeyWithValue("release", "test"))

Expand Down
17 changes: 13 additions & 4 deletions pkg/workloads/console/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ type Runner struct {

// Options defines the parameters that can be set upon a new console
type Options struct {
Cmd []string
Timeout int
Reason string
Cmd []string
Timeout int
Reason string
IncidentId string
// Whether or not to enable a TTY for the console. Typically this
// should be set to false but some execution environments, eg
// Tekton, do not like attaching to TTY-enabled pods.
Expand Down Expand Up @@ -148,6 +149,7 @@ type CreateOptions struct {
Selector string
Timeout time.Duration
Reason string
IncidentId string
Command []string
Attach bool
Noninteractive bool
Expand Down Expand Up @@ -185,7 +187,13 @@ func (c *Runner) Create(ctx context.Context, opts CreateOptions) (*workloadsv1al
return nil, err
}

opt := Options{Cmd: opts.Command, Timeout: int(opts.Timeout.Seconds()), Reason: opts.Reason, Noninteractive: opts.Noninteractive}
opt := Options{
Cmd: opts.Command,
Timeout: int(opts.Timeout.Seconds()),
Reason: opts.Reason,
Noninteractive: opts.Noninteractive,
IncidentId: opts.IncidentId,
}
csl, err := c.CreateResource(tpl.Namespace, *tpl, opt)
if err != nil {
return nil, err
Expand Down Expand Up @@ -682,6 +690,7 @@ func (c *Runner) CreateResource(namespace string, template workloadsv1alpha1.Con
TimeoutSeconds: opts.Timeout,
Command: opts.Cmd,
Reason: opts.Reason,
IncidentId: opts.IncidentId,
Noninteractive: opts.Noninteractive,
},
}
Expand Down

0 comments on commit 1de12bf

Please sign in to comment.