Skip to content

Commit

Permalink
Merge pull request #1668 from saschagrunert/attach-exec-tls
Browse files Browse the repository at this point in the history
Add TLS support for `crictl` `exec`, `portforward` and `attach`
  • Loading branch information
k8s-ci-robot authored Nov 6, 2024
2 parents c9a62f2 + 2cf1580 commit 3ef9e8d
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 16 deletions.
33 changes: 29 additions & 4 deletions cmd/crictl/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ var runtimeAttachCommand = &cli.Command{
Value: transportSpdy,
Usage: fmt.Sprintf("Transport protocol to use, one of: %s|%s", transportSpdy, transportWebsocket),
},
&cli.StringFlag{
Name: flagTLSSNI,
Usage: "Server name used in the TLS client to check server certificates against",
Aliases: []string{"tls-server-name"},
Value: "localhost",
},
&cli.StringFlag{
Name: flagTLSCA,
Usage: "Path to the streaming TLS CA certificate",
},
&cli.StringFlag{
Name: flagTLSCert,
Usage: "Path to the streaming TLS certificate",
},
&cli.StringFlag{
Name: flagTLSKey,
Usage: "Path to the streaming TLS key",
},
},
Action: func(c *cli.Context) error {
id := c.Args().First()
Expand All @@ -70,10 +88,17 @@ var runtimeAttachCommand = &cli.Command{
defer cancel()

opts := attachOptions{
id: id,
tty: c.Bool("tty"),
stdin: c.Bool("stdin"),
id: id,
tty: c.Bool("tty"),
stdin: c.Bool("stdin"),
transport: c.String("transport"),
}

opts.tlsConfig, err = tlsConfigFromFlags(c)
if err != nil {
return fmt.Errorf("get TLS config from flags: %w", err)
}

if err = Attach(ctx, runtimeClient, opts); err != nil {
return fmt.Errorf("attaching running container failed: %w", err)
}
Expand Down Expand Up @@ -116,5 +141,5 @@ func Attach(ctx context.Context, client internalapi.RuntimeService, opts attachO
}

logrus.Debugf("Attach URL: %v", URL)
return stream(ctx, opts.stdin, opts.tty, opts.transport, URL)
return stream(ctx, opts.stdin, opts.tty, opts.transport, URL, opts.tlsConfig)
}
68 changes: 59 additions & 9 deletions cmd/crictl/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@ var runtimeExecCommand = &cli.Command{
Aliases: []string{"x"},
Usage: "Run the command in parallel if multiple containers are selected",
},
&cli.StringFlag{
Name: flagTLSSNI,
Usage: "Server name used in the TLS client to check server certificates against",
Aliases: []string{"tls-server-name"},
Value: "localhost",
},
&cli.StringFlag{
Name: flagTLSCA,
Usage: "Path to the streaming TLS CA certificate",
},
&cli.StringFlag{
Name: flagTLSCert,
Usage: "Path to the streaming TLS certificate",
},
&cli.StringFlag{
Name: flagTLSKey,
Usage: "Path to the streaming TLS key",
},
},
Action: func(c *cli.Context) error {
if c.NArg() < 1 {
Expand Down Expand Up @@ -200,6 +218,11 @@ var runtimeExecCommand = &cli.Command{
transport: c.String(transportFlag),
}

opts.tlsConfig, err = tlsConfigFromFlags(c)
if err != nil {
return fmt.Errorf("get TLS config from flags: %w", err)
}

funcs := []func() error{}
for _, id := range ids {
funcs = append(funcs, func() error {
Expand All @@ -210,7 +233,7 @@ var runtimeExecCommand = &cli.Command{
fmt.Println(id + ":")
}
if c.Bool("sync") {
exitCode, err := ExecSync(runtimeClient, optsCopy)
exitCode, err := ExecSync(runtimeClient, &optsCopy)
if err != nil {
return fmt.Errorf("execing command in container %s synchronously: %w", id, err)
}
Expand All @@ -220,7 +243,7 @@ var runtimeExecCommand = &cli.Command{
} else {
ctx, cancel := context.WithCancel(c.Context)
defer cancel()
err = Exec(ctx, runtimeClient, optsCopy)
err = Exec(ctx, runtimeClient, &optsCopy)
if err != nil {
return fmt.Errorf("execing command in container %s: %w", id, err)
}
Expand All @@ -241,10 +264,37 @@ var runtimeExecCommand = &cli.Command{
},
}

const (
flagTLSSNI = "tls-sni"
flagTLSCA = "tls-ca"
flagTLSCert = "tls-cert"
flagTLSKey = "tls-key"
)

func tlsConfigFromFlags(ctx *cli.Context) (*rest.TLSClientConfig, error) {
cfg := &rest.TLSClientConfig{
ServerName: ctx.String(flagTLSSNI),
CAFile: ctx.String(flagTLSCA),
CertFile: ctx.String(flagTLSCert),
KeyFile: ctx.String(flagTLSKey),
}
if cfg.CAFile == "" && cfg.CertFile == "" && cfg.KeyFile == "" {
return &rest.TLSClientConfig{Insecure: true}, nil
}
if cfg.CAFile == "" || cfg.CertFile == "" || cfg.KeyFile == "" {
return nil, fmt.Errorf(
"all three flags --%s, --%s and --%s are required for TLS streaming",
flagTLSCA, flagTLSCert, flagTLSKey,
)
}

return cfg, nil
}

// ExecSync sends an ExecSyncRequest to the server, and parses
// the returned ExecSyncResponse. The function returns the corresponding exit
// code beside an general error.
func ExecSync(client internalapi.RuntimeService, opts execOptions) (int, error) {
func ExecSync(client internalapi.RuntimeService, opts *execOptions) (int, error) {
request := &pb.ExecSyncRequest{
ContainerId: opts.id,
Cmd: opts.cmd,
Expand All @@ -271,7 +321,7 @@ func ExecSync(client internalapi.RuntimeService, opts execOptions) (int, error)
}

// Exec sends an ExecRequest to server, and parses the returned ExecResponse.
func Exec(ctx context.Context, client internalapi.RuntimeService, opts execOptions) error {
func Exec(ctx context.Context, client internalapi.RuntimeService, opts *execOptions) error {
request := &pb.ExecRequest{
ContainerId: opts.id,
Cmd: opts.cmd,
Expand Down Expand Up @@ -305,11 +355,11 @@ func Exec(ctx context.Context, client internalapi.RuntimeService, opts execOptio
}

logrus.Debugf("Exec URL: %v", URL)
return stream(ctx, opts.stdin, opts.tty, opts.transport, URL)
return stream(ctx, opts.stdin, opts.tty, opts.transport, URL, opts.tlsConfig)
}

func stream(ctx context.Context, in, tty bool, transport string, parsedURL *url.URL) error {
executor, err := getExecutor(transport, parsedURL)
func stream(ctx context.Context, in, tty bool, transport string, parsedURL *url.URL, tlsConfig *rest.TLSClientConfig) error {
executor, err := getExecutor(transport, parsedURL, tlsConfig)
if err != nil {
return fmt.Errorf("get executor: %w", err)
}
Expand Down Expand Up @@ -348,8 +398,8 @@ func stream(ctx context.Context, in, tty bool, transport string, parsedURL *url.
return t.Safe(func() error { return executor.StreamWithContext(ctx, streamOptions) })
}

func getExecutor(transport string, parsedURL *url.URL) (exec remoteclient.Executor, err error) {
config := &rest.Config{TLSClientConfig: rest.TLSClientConfig{Insecure: true}}
func getExecutor(transport string, parsedURL *url.URL, tlsConfig *rest.TLSClientConfig) (exec remoteclient.Executor, err error) {
config := &rest.Config{TLSClientConfig: *tlsConfig}

switch transport {
case transportSpdy:
Expand Down
30 changes: 27 additions & 3 deletions cmd/crictl/portforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ var runtimePortForwardCommand = &cli.Command{
Value: transportSpdy,
Usage: fmt.Sprintf("Transport protocol to use, one of: %s|%s", transportSpdy, transportWebsocket),
},
&cli.StringFlag{
Name: flagTLSSNI,
Usage: "Server name used in the TLS client to check server certificates against",
Aliases: []string{"tls-server-name"},
Value: "localhost",
},
&cli.StringFlag{
Name: flagTLSCA,
Usage: "Path to the streaming TLS CA certificate",
},
&cli.StringFlag{
Name: flagTLSCert,
Usage: "Path to the streaming TLS certificate",
},
&cli.StringFlag{
Name: flagTLSKey,
Usage: "Path to the streaming TLS key",
},
},
Action: func(c *cli.Context) error {
if c.NArg() < 2 {
Expand All @@ -61,6 +79,12 @@ var runtimePortForwardCommand = &cli.Command{
ports: c.Args().Tail(),
transport: c.String(transportFlag),
}

opts.tlsConfig, err = tlsConfigFromFlags(c)
if err != nil {
return fmt.Errorf("get TLS config from flags: %w", err)
}

if err = PortForward(runtimeClient, opts); err != nil {
return fmt.Errorf("port forward: %w", err)
}
Expand Down Expand Up @@ -99,7 +123,7 @@ func PortForward(client internalapi.RuntimeService, opts portforwardOptions) err
}

logrus.Debugf("PortForward URL: %v", parsedURL)
dialer, err := getDialer(opts.transport, parsedURL)
dialer, err := getDialer(opts.transport, parsedURL, opts.tlsConfig)
if err != nil {
return fmt.Errorf("get dialer: %w", err)
}
Expand All @@ -114,8 +138,8 @@ func PortForward(client internalapi.RuntimeService, opts portforwardOptions) err
return pf.ForwardPorts()
}

func getDialer(transport string, parsedURL *url.URL) (exec httpstream.Dialer, err error) {
config := &rest.Config{TLSClientConfig: rest.TLSClientConfig{Insecure: true}}
func getDialer(transport string, parsedURL *url.URL, tlsConfig *rest.TLSClientConfig) (exec httpstream.Dialer, err error) {
config := &rest.Config{TLSClientConfig: *tlsConfig}

switch transport {
case transportSpdy:
Expand Down
8 changes: 8 additions & 0 deletions cmd/crictl/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"google.golang.org/protobuf/protoadapt"
"google.golang.org/protobuf/runtime/protoiface"
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/rest"
internalapi "k8s.io/cri-api/pkg/apis"
pb "k8s.io/cri-api/pkg/apis/runtime/v1"
"sigs.k8s.io/yaml"
Expand Down Expand Up @@ -157,7 +158,10 @@ type execOptions struct {
cmd []string
// transport to be used
transport string
// TLS configuration for streaming
tlsConfig *rest.TLSClientConfig
}

type attachOptions struct {
// id of container
id string
Expand All @@ -167,6 +171,8 @@ type attachOptions struct {
stdin bool
// transport to be used
transport string
// TLS configuration for streaming
tlsConfig *rest.TLSClientConfig
}

type portforwardOptions struct {
Expand All @@ -176,6 +182,8 @@ type portforwardOptions struct {
ports []string
// transport to be used
transport string
// TLS configuration for streaming
tlsConfig *rest.TLSClientConfig
}

func getSortedKeys(m map[string]string) []string {
Expand Down

0 comments on commit 3ef9e8d

Please sign in to comment.