istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/istio-iptables/pkg/cmd/root.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  
    21  	"github.com/spf13/cobra"
    22  
    23  	"istio.io/istio/pkg/flag"
    24  	"istio.io/istio/pkg/log"
    25  	"istio.io/istio/tools/istio-iptables/pkg/capture"
    26  	"istio.io/istio/tools/istio-iptables/pkg/config"
    27  	"istio.io/istio/tools/istio-iptables/pkg/constants"
    28  	dep "istio.io/istio/tools/istio-iptables/pkg/dependencies"
    29  	"istio.io/istio/tools/istio-iptables/pkg/validation"
    30  )
    31  
    32  const InvalidDropByIptables = "INVALID_DROP"
    33  
    34  func handleErrorWithCode(err error, code int) {
    35  	log.Error(err)
    36  	os.Exit(code)
    37  }
    38  
    39  func bindCmdlineFlags(cfg *config.Config, cmd *cobra.Command) {
    40  	fs := cmd.Flags()
    41  	flag.Bind(fs, constants.EnvoyPort, "p", "Specify the envoy port to which redirect all TCP traffic.", &cfg.ProxyPort)
    42  
    43  	flag.BindEnv(fs, constants.InboundCapturePort, "z",
    44  		"Port to which all inbound TCP traffic to the pod/VM should be redirected to.",
    45  		&cfg.InboundCapturePort)
    46  
    47  	flag.BindEnv(fs, constants.InboundTunnelPort, "e",
    48  		"Specify the istio tunnel port for inbound tcp traffic.",
    49  		&cfg.InboundTunnelPort)
    50  
    51  	flag.BindEnv(fs, constants.ProxyUID, "u",
    52  		"Specify the UID of the user for which the redirection is not applied. Typically, this is the UID of the proxy container.",
    53  		&cfg.ProxyUID)
    54  
    55  	flag.BindEnv(fs, constants.ProxyGID, "g",
    56  		"Specify the GID of the user for which the redirection is not applied (same default value as -u param).",
    57  		&cfg.ProxyGID)
    58  
    59  	flag.BindEnv(fs, constants.InboundInterceptionMode, "m",
    60  		"The mode used to redirect inbound connections to Envoy, either \"REDIRECT\" or \"TPROXY\".",
    61  		&cfg.InboundInterceptionMode)
    62  
    63  	flag.BindEnv(fs, constants.InboundPorts, "b",
    64  		"Comma separated list of inbound ports for which traffic is to be redirected to Envoy (optional). "+
    65  			"The wildcard character \"*\" can be used to configure redirection for all ports. An empty list will disable.",
    66  		&cfg.InboundPortsInclude)
    67  
    68  	flag.BindEnv(fs, constants.LocalExcludePorts, "d",
    69  		"Comma separated list of inbound ports to be excluded from redirection to Envoy (optional). "+
    70  			"Only applies when all inbound traffic (i.e. \"*\") is being redirected.",
    71  		&cfg.InboundPortsExclude)
    72  
    73  	flag.BindEnv(fs, constants.ExcludeInterfaces, "c",
    74  		"Comma separated list of NIC (optional). Neither inbound nor outbound traffic will be captured.",
    75  		&cfg.ExcludeInterfaces)
    76  
    77  	flag.BindEnv(fs, constants.ServiceCidr, "i",
    78  		"Comma separated list of IP ranges in CIDR form to redirect to envoy (optional). "+
    79  			"The wildcard character \"*\" can be used to redirect all outbound traffic. An empty list will disable all outbound.",
    80  		&cfg.OutboundIPRangesInclude)
    81  
    82  	flag.BindEnv(fs, constants.ServiceExcludeCidr, "x",
    83  		"Comma separated list of IP ranges in CIDR form to be excluded from redirection. "+
    84  			"Only applies when all  outbound traffic (i.e. \"*\") is being redirected.",
    85  		&cfg.OutboundIPRangesExclude)
    86  
    87  	flag.BindEnv(fs, constants.OutboundPorts, "q",
    88  		"Comma separated list of outbound ports to be explicitly included for redirection to Envoy.",
    89  		&cfg.OutboundPortsInclude)
    90  
    91  	flag.BindEnv(fs, constants.LocalOutboundPortsExclude, "o",
    92  		"Comma separated list of outbound ports to be excluded from redirection to Envoy.",
    93  		&cfg.OutboundPortsExclude)
    94  
    95  	flag.BindEnv(fs, constants.KubeVirtInterfaces, "k",
    96  		"Comma separated list of virtual interfaces whose inbound traffic (from VM) will be treated as outbound.",
    97  		&cfg.KubeVirtInterfaces)
    98  
    99  	flag.BindEnv(fs, constants.InboundTProxyMark, "t", "", &cfg.InboundTProxyMark)
   100  
   101  	flag.BindEnv(fs, constants.InboundTProxyRouteTable, "r", "", &cfg.InboundTProxyRouteTable)
   102  
   103  	flag.BindEnv(fs, constants.DryRun, "n", "Do not call any external dependencies like iptables.",
   104  		&cfg.DryRun)
   105  
   106  	flag.BindEnv(fs, constants.TraceLogging, "", "Insert tracing logs for each iptables rules, using the LOG chain.", &cfg.TraceLogging)
   107  
   108  	flag.BindEnv(fs, constants.RestoreFormat, "f", "Print iptables rules in iptables-restore interpretable format.",
   109  		&cfg.RestoreFormat)
   110  
   111  	flag.BindEnv(fs, constants.IptablesProbePort, "", "Set listen port for failure detection.", &cfg.IptablesProbePort)
   112  
   113  	flag.BindEnv(fs, constants.ProbeTimeout, "", "Failure detection timeout.", &cfg.ProbeTimeout)
   114  
   115  	flag.BindEnv(fs, constants.SkipRuleApply, "", "Skip iptables apply.", &cfg.SkipRuleApply)
   116  
   117  	flag.BindEnv(fs, constants.RunValidation, "", "Validate iptables.", &cfg.RunValidation)
   118  
   119  	flag.BindEnv(fs, constants.RedirectDNS, "", "Enable capture of dns traffic by istio-agent.", &cfg.RedirectDNS)
   120  	// Allow binding to a different var, for consistency with other components
   121  	flag.AdditionalEnv(fs, constants.RedirectDNS, "ISTIO_META_DNS_CAPTURE")
   122  
   123  	flag.BindEnv(fs, constants.DropInvalid, "", "Enable invalid drop in the iptables rules.", &cfg.DropInvalid)
   124  	// This could have just used the default but for backwards compat we support the old env.
   125  	flag.AdditionalEnv(fs, constants.DropInvalid, InvalidDropByIptables)
   126  
   127  	flag.BindEnv(fs, constants.DualStack, "", "Enable ipv4/ipv6 redirects for dual-stack.", &cfg.DualStack)
   128  	// Allow binding to a different var, for consistency with other components
   129  	flag.AdditionalEnv(fs, constants.DualStack, "ISTIO_DUAL_STACK")
   130  
   131  	flag.BindEnv(fs, constants.CaptureAllDNS, "",
   132  		"Instead of only capturing DNS traffic to DNS server IP, capture all DNS traffic at port 53. This setting is only effective when redirect dns is enabled.",
   133  		&cfg.CaptureAllDNS)
   134  
   135  	flag.BindEnv(fs, constants.NetworkNamespace, "", "The network namespace that iptables rules should be applied to.",
   136  		&cfg.NetworkNamespace)
   137  
   138  	flag.BindEnv(fs, constants.CNIMode, "", "Whether to run as CNI plugin.", &cfg.CNIMode)
   139  }
   140  
   141  func GetCommand(logOpts *log.Options) *cobra.Command {
   142  	cfg := config.DefaultConfig()
   143  	cmd := &cobra.Command{
   144  		Use:   "istio-iptables",
   145  		Short: "Set up iptables rules for Istio Sidecar",
   146  		Long:  "istio-iptables is responsible for setting up port forwarding for Istio Sidecar.",
   147  		PreRunE: func(cmd *cobra.Command, args []string) error {
   148  			if err := log.Configure(logOpts); err != nil {
   149  				return err
   150  			}
   151  			return nil
   152  		},
   153  		Run: func(cmd *cobra.Command, args []string) {
   154  			if err := cfg.FillConfigFromEnvironment(); err != nil {
   155  				handleErrorWithCode(err, 1)
   156  			}
   157  			if err := cfg.Validate(); err != nil {
   158  				handleErrorWithCode(err, 1)
   159  			}
   160  			if err := ProgramIptables(cfg); err != nil {
   161  				handleErrorWithCode(err, 1)
   162  			}
   163  
   164  			if cfg.RunValidation {
   165  				validator := validation.NewValidator(cfg)
   166  
   167  				if err := validator.Run(); err != nil {
   168  					// nolint: revive, stylecheck
   169  					msg := fmt.Errorf(`iptables validation failed; workload is not ready for Istio.
   170  When using Istio CNI, this can occur if a pod is scheduled before the node is ready.
   171  
   172  If installed with 'cni.repair.deletePods=true', this pod should automatically be deleted and retry.
   173  Otherwise, this pod will need to be manually removed so that it is scheduled on a node with istio-cni running, allowing iptables rules to be established.
   174  `)
   175  					handleErrorWithCode(msg, constants.ValidationErrorCode)
   176  				}
   177  			}
   178  		},
   179  	}
   180  	bindCmdlineFlags(cfg, cmd)
   181  	return cmd
   182  }
   183  
   184  type IptablesError struct {
   185  	Error    error
   186  	ExitCode int
   187  }
   188  
   189  func ProgramIptables(cfg *config.Config) error {
   190  	var ext dep.Dependencies
   191  	if cfg.DryRun {
   192  		log.Info("running iptables in dry-run mode, no rule changes will be made")
   193  		ext = &dep.DependenciesStub{}
   194  	} else {
   195  		ext = &dep.RealDependencies{
   196  			CNIMode:          cfg.CNIMode,
   197  			NetworkNamespace: cfg.NetworkNamespace,
   198  		}
   199  	}
   200  
   201  	iptConfigurator := capture.NewIptablesConfigurator(cfg, ext)
   202  
   203  	if !cfg.SkipRuleApply {
   204  		if err := iptConfigurator.Run(); err != nil {
   205  			return err
   206  		}
   207  		if err := capture.ConfigureRoutes(cfg); err != nil {
   208  			return fmt.Errorf("failed to configure routes: %v", err)
   209  		}
   210  	}
   211  	return nil
   212  }