Skip to content

Commit 31f3af0

Browse files
authored
istioctl zc: avoid accidentally selecting random pod (istio#55541)
* istioctl zc: avoid accidentally selecting random pod `ztunnel-config` has two types of commands: * Introspecting config that should be identical across all pods * Introspecting a single instance For the former, allowing eliding a specific pod name is quite nice since, unless debugging out-of-sync issues, the result will be the same. For some commands, though, this just leads to confusion. This PR makes it so certain commands MUST specify a specific pod/node * lint
1 parent 3451516 commit 31f3af0

File tree

1 file changed

+35
-17
lines changed

1 file changed

+35
-17
lines changed

istioctl/pkg/ztunnelconfig/ztunnelconfig.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func certificatesConfigCmd(ctx cli.Context) *cobra.Command {
9191
`,
9292
Aliases: []string{"certificates", "certs", "cert"},
9393
Args: common.validateArgs,
94-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
94+
RunE: runConfigDump(ctx, common, true, func(cw *ztunnelDump.ConfigWriter) error {
9595
switch common.outputFormat {
9696
case summaryOutput:
9797
return cw.PrintSecretSummary()
@@ -124,7 +124,7 @@ func servicesCmd(ctx cli.Context) *cobra.Command {
124124
`,
125125
Aliases: []string{"services", "s", "svc"},
126126
Args: common.validateArgs,
127-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
127+
RunE: runConfigDump(ctx, common, false, func(cw *ztunnelDump.ConfigWriter) error {
128128
filter := ztunnelDump.ServiceFilter{
129129
Namespace: serviceNamespace,
130130
}
@@ -162,7 +162,7 @@ func policiesCmd(ctx cli.Context) *cobra.Command {
162162
`,
163163
Aliases: []string{"policies", "p", "pol"},
164164
Args: common.validateArgs,
165-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
165+
RunE: runConfigDump(ctx, common, false, func(cw *ztunnelDump.ConfigWriter) error {
166166
filter := ztunnelDump.PolicyFilter{
167167
Namespace: policyNamespace,
168168
}
@@ -198,7 +198,7 @@ func allCmd(ctx cli.Context) *cobra.Command {
198198
istioctl ztunnel-config all <ztunnel-name[.namespace]> -o json
199199
`,
200200
Args: common.validateArgs,
201-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
201+
RunE: runConfigDump(ctx, common, false, func(cw *ztunnelDump.ConfigWriter) error {
202202
switch common.outputFormat {
203203
case summaryOutput:
204204
return cw.PrintFullSummary()
@@ -245,7 +245,7 @@ func workloadConfigCmd(ctx cli.Context) *cobra.Command {
245245
`,
246246
Aliases: []string{"w", "workloads"},
247247
Args: common.validateArgs,
248-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
248+
RunE: runConfigDump(ctx, common, false, func(cw *ztunnelDump.ConfigWriter) error {
249249
filter := ztunnelDump.WorkloadFilter{
250250
Namespace: workloadsNamespace,
251251
Address: address,
@@ -280,10 +280,9 @@ func connectionsCmd(ctx cli.Context) *cobra.Command {
280280

281281
common := new(commonFlags)
282282
cmd := &cobra.Command{
283-
Use: "connections [<type>/]<name>[.<namespace>]",
284-
Hidden: true,
285-
Short: "Retrieves connections for the specified Ztunnel pod.",
286-
Long: `Retrieve information about connections for the Ztunnel instance.`,
283+
Use: "connections [<type>/]<name>[.<namespace>]",
284+
Short: "Retrieves connections for the specified Ztunnel pod.",
285+
Long: `Retrieve information about connections for the Ztunnel instance.`,
287286
Example: ` # Retrieve summary about connections for the ztunnel on a specific node.
288287
istioctl ztunnel-config connections --node ambient-worker
289288
@@ -292,7 +291,7 @@ func connectionsCmd(ctx cli.Context) *cobra.Command {
292291
`,
293292
Aliases: []string{"cons"},
294293
Args: common.validateArgs,
295-
RunE: runConfigDump(ctx, common, func(cw *ztunnelDump.ConfigWriter) error {
294+
RunE: runConfigDump(ctx, common, true, func(cw *ztunnelDump.ConfigWriter) error {
296295
filter := ztunnelDump.ConnectionsFilter{
297296
Namespace: workloadsNamespace,
298297
Direction: direction,
@@ -421,7 +420,7 @@ func logCmd(ctx cli.Context) *cobra.Command {
421420
var podNames []string
422421
var podNamespace string
423422
if len(args) == 1 {
424-
podName, ns, err := getComponentPodName(ctx, args[0])
423+
podName, ns, err := getComponentPodName(ctx, args[0], false)
425424
if err != nil {
426425
return err
427426
}
@@ -522,13 +521,22 @@ func setupZtunnelLogs(kubeClient kube.CLIClient, param, podName, podNamespace st
522521
}
523522

524523
// getComponentPodName returns the pod name and namespace of the Istio component
525-
func getComponentPodName(ctx cli.Context, podflag string) (string, string, error) {
524+
func getComponentPodName(ctx cli.Context, podflag string, enforceSinglePod bool) (string, string, error) {
526525
// If user passed --namespace, respect it. Else fallback to --istio-namespace (which is typically defaulted, to istio-system).
527-
return getPodNameWithNamespace(ctx, podflag, model.GetOrDefault(ctx.Namespace(), ctx.IstioNamespace()))
526+
return getPodNameWithNamespace(ctx, podflag, enforceSinglePod, model.GetOrDefault(ctx.Namespace(), ctx.IstioNamespace()))
528527
}
529528

530-
func getPodNameWithNamespace(ctx cli.Context, podflag, ns string) (string, string, error) {
531-
var podName, podNamespace string
529+
func getPodNameWithNamespace(ctx cli.Context, podflag string, enforceSinglePod bool, ns string) (string, string, error) {
530+
if enforceSinglePod {
531+
pods, podNamespace, err := ctx.InferPodsFromTypedResource(podflag, ns)
532+
if err != nil {
533+
return "", "", err
534+
}
535+
if len(pods) != 1 {
536+
return "", "", fmt.Errorf("ztunnel pod name or --node must be set")
537+
}
538+
return pods[0], podNamespace, nil
539+
}
532540
podName, podNamespace, err := ctx.InferPodInfoFromTypedResource(podflag, ns)
533541
if err != nil {
534542
return "", "", err
@@ -587,7 +595,15 @@ func setupFileZtunnelConfigdumpWriter(filename string, out io.Writer) (*ztunnelD
587595
return setupConfigdumpZtunnelConfigWriter(data, out)
588596
}
589597

590-
func runConfigDump(ctx cli.Context, common *commonFlags, f func(cw *ztunnelDump.ConfigWriter) error) func(c *cobra.Command, args []string) error {
598+
// runConfigDump runs a function that acts on a configdump.
599+
// enforceSinglePod can be set for commands where we enforce a user to explicitly specify a pod. This should be 'true' when
600+
// the content is specific to a single Ztunnel pod, but 'false' if it is the same across all pods.
601+
func runConfigDump(
602+
ctx cli.Context,
603+
common *commonFlags,
604+
enforceSinglePod bool,
605+
f func(cw *ztunnelDump.ConfigWriter) error,
606+
) func(c *cobra.Command, args []string) error {
591607
return func(c *cobra.Command, args []string) error {
592608
var podName, podNamespace string
593609
kubeClient, err := ctx.CLIClient()
@@ -601,6 +617,8 @@ func runConfigDump(ctx cli.Context, common *commonFlags, f func(cw *ztunnelDump.
601617
lookup := "daemonset/ztunnel"
602618
if len(args) > 0 {
603619
lookup = args[0]
620+
// If they explicitly asked for an unreliable container, allow it
621+
enforceSinglePod = false
604622
}
605623
if common.node != "" {
606624
nsn, err := PodOnNodeFromDaemonset(common.node, "ztunnel", ctx.IstioNamespace(), kubeClient)
@@ -609,7 +627,7 @@ func runConfigDump(ctx cli.Context, common *commonFlags, f func(cw *ztunnelDump.
609627
}
610628
podName, podNamespace = nsn.Name, nsn.Namespace
611629
} else {
612-
if podName, podNamespace, err = getComponentPodName(ctx, lookup); err != nil {
630+
if podName, podNamespace, err = getComponentPodName(ctx, lookup, enforceSinglePod); err != nil {
613631
return err
614632
}
615633
}

0 commit comments

Comments
 (0)