Files
teleport/tool/common/common.go
T
Brian Joerger 731acf9cb7 Hardware Key UX fixes (#20849)
* Save private key policy in profile.

* Fix tsh status/logout with yubikey unplugged; fix cluster alert on tsh status with hardware_key_touch.

* Set private key policy from ping response.

* Skip cluster alerts on tsh status.
2023-01-30 19:17:53 +00:00

136 lines
4.2 KiB
Go

/*
Copyright 2016-2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package common
import (
"context"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/lib/asciitable"
"github.com/gravitational/teleport/lib/utils"
)
// ExitCodeError wraps an exit code as an error.
type ExitCodeError struct {
// Code is the exit code
Code int
}
// Error implements the error interface.
func (e *ExitCodeError) Error() string {
return fmt.Sprintf("exit code %d", e.Code)
}
// SessionsCollection is a collection of session end events.
type SessionsCollection struct {
SessionEvents []events.AuditEvent
}
// WriteText writes the session collection as text to the provided io.Writer.
func (e *SessionsCollection) WriteText(w io.Writer) error {
t := asciitable.MakeTable([]string{"ID", "Type", "Participants", "Hostname", "Timestamp"})
for _, event := range e.SessionEvents {
session, ok := event.(*events.SessionEnd)
if !ok {
log.Warn(trace.BadParameter("unsupported event type: expected SessionEnd: got: %T", event))
continue
}
t.AddRow([]string{
session.GetSessionID(),
session.Protocol,
strings.Join(session.Participants, ", "),
session.ServerHostname,
session.GetTime().Format(constants.HumanDateFormatSeconds),
})
}
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}
// WriteJSON writes the session collection as JSON to the provided io.Writer.
func (e *SessionsCollection) WriteJSON(w io.Writer) error {
data, err := json.MarshalIndent(e.SessionEvents, "", " ")
if err != nil {
return trace.Wrap(err)
}
_, err = w.Write(data)
return trace.Wrap(err)
}
// WriteYAML writes the session collection as YAML to the provided io.Writer.
func (e *SessionsCollection) WriteYAML(w io.Writer) error {
return utils.WriteYAML(w, e.SessionEvents)
}
// ShowSessions is a helper function for displaying listed sessions via tsh or tctl.
func ShowSessions(events []events.AuditEvent, format string, w io.Writer) error {
sessions := &SessionsCollection{SessionEvents: events}
switch format {
case teleport.Text, "":
return trace.Wrap(sessions.WriteText(w))
case teleport.YAML:
return trace.Wrap(sessions.WriteYAML(w))
case teleport.JSON:
return trace.Wrap(sessions.WriteJSON(w))
default:
return trace.BadParameter("unknown format %q", format)
}
}
// ClusterAlertGetter manages getting cluster alerts.
type ClusterAlertGetter interface {
GetClusterAlerts(ctx context.Context, query types.GetClusterAlertsRequest) ([]types.ClusterAlert, error)
}
// ShowClusterAlerts shows cluster alerts with the given labels and severity.
func ShowClusterAlerts(ctx context.Context, client ClusterAlertGetter, w io.Writer, labels map[string]string, minSeverity, maxSeverity types.AlertSeverity) error {
// get any "on login" alerts
alertCtx, cancelAlertCtx := context.WithTimeout(ctx, constants.TimeoutGetClusterAlerts)
defer cancelAlertCtx()
alerts, err := client.GetClusterAlerts(alertCtx, types.GetClusterAlertsRequest{
Labels: labels,
Severity: minSeverity,
})
if err != nil && !trace.IsNotImplemented(err) {
return trace.Wrap(err)
}
types.SortClusterAlerts(alerts)
var errs []error
for _, alert := range alerts {
if err := alert.CheckMessage(); err != nil {
errs = append(errs, trace.Errorf("invalid alert %q: %w", alert.Metadata.Name, err))
continue
}
if alert.Spec.Severity <= maxSeverity {
fmt.Fprintf(w, "%s\n\n", utils.FormatAlert(alert))
}
}
return trace.NewAggregate(errs...)
}