istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/authz/authz.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 authz 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "os" 22 23 "github.com/spf13/cobra" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 26 "istio.io/istio/istioctl/pkg/cli" 27 "istio.io/istio/istioctl/pkg/completion" 28 "istio.io/istio/istioctl/pkg/util" 29 "istio.io/istio/istioctl/pkg/util/configdump" 30 "istio.io/istio/pkg/kube" 31 "istio.io/istio/pkg/log" 32 ) 33 34 var configDumpFile string 35 36 func checkCmd(ctx cli.Context) *cobra.Command { 37 cmd := &cobra.Command{ 38 Use: "check [<type>/]<name>[.<namespace>]", 39 Short: "Check AuthorizationPolicy applied in the pod.", 40 Long: `Check prints the AuthorizationPolicy applied to a pod by directly checking 41 the Envoy configuration of the pod. The command is especially useful for inspecting 42 the policy propagation from Istiod to Envoy and the final AuthorizationPolicy list merged 43 from multiple sources (mesh-level, namespace-level and workload-level). 44 45 The command also supports reading from a standalone config dump file with flag -f.`, 46 Example: ` # Check AuthorizationPolicy applied to pod httpbin-88ddbcfdd-nt5jb: 47 istioctl x authz check httpbin-88ddbcfdd-nt5jb 48 49 # Check AuthorizationPolicy applied to one pod under a deployment 50 istioctl x authz check deployment/productpage-v1 51 52 # Check AuthorizationPolicy from Envoy config dump file: 53 istioctl x authz check -f httpbin_config_dump.json`, 54 Args: func(cmd *cobra.Command, args []string) error { 55 if len(args) > 1 { 56 cmd.Println(cmd.UsageString()) 57 return fmt.Errorf("check requires only <pod-name>[.<pod-namespace>]") 58 } 59 return nil 60 }, 61 RunE: func(cmd *cobra.Command, args []string) error { 62 kubeClient, err := ctx.CLIClient() 63 if err != nil { 64 return fmt.Errorf("failed to create k8s client: %w", err) 65 } 66 var configDump *configdump.Wrapper 67 if configDumpFile != "" { 68 configDump, err = getConfigDumpFromFile(configDumpFile) 69 if err != nil { 70 return fmt.Errorf("failed to get config dump from file %s: %s", configDumpFile, err) 71 } 72 } else if len(args) == 1 { 73 podName, podNamespace, err := ctx.InferPodInfoFromTypedResource(args[0], ctx.Namespace()) 74 if err != nil { 75 return err 76 } 77 configDump, err = getConfigDumpFromPod(kubeClient, podName, podNamespace) 78 if err != nil { 79 return fmt.Errorf("failed to get config dump from pod %s in %s", podName, podNamespace) 80 } 81 } else { 82 return fmt.Errorf("expecting pod name or config dump, found: %d", len(args)) 83 } 84 85 analyzer, err := NewAnalyzer(configDump) 86 if err != nil { 87 return err 88 } 89 analyzer.Print(cmd.OutOrStdout()) 90 return nil 91 }, 92 ValidArgsFunction: completion.ValidPodsNameArgs(ctx), 93 } 94 cmd.PersistentFlags().StringVarP(&configDumpFile, "file", "f", "", 95 "The json file with Envoy config dump to be checked") 96 return cmd 97 } 98 99 func getConfigDumpFromFile(filename string) (*configdump.Wrapper, error) { 100 file, err := os.Open(filename) 101 if err != nil { 102 return nil, err 103 } 104 defer func() { 105 if err := file.Close(); err != nil { 106 log.Errorf("failed to close %s: %s", filename, err) 107 } 108 }() 109 data, err := io.ReadAll(file) 110 if err != nil { 111 return nil, err 112 } 113 114 envoyConfig := &configdump.Wrapper{} 115 if err := envoyConfig.UnmarshalJSON(data); err != nil { 116 return nil, fmt.Errorf("failed to unmarshal proxy config: %s", err) 117 } 118 return envoyConfig, nil 119 } 120 121 func getConfigDumpFromPod(kubeClient kube.CLIClient, podName, podNamespace string) (*configdump.Wrapper, error) { 122 pods, err := kubeClient.GetIstioPods(context.TODO(), podNamespace, metav1.ListOptions{ 123 FieldSelector: "metadata.name=" + podName, 124 }) 125 if err != nil { 126 return nil, fmt.Errorf("failed to get pod: %s", err) 127 } 128 if len(pods) != 1 { 129 return nil, fmt.Errorf("expecting only 1 pod for %s.%s, found: %d", podName, podNamespace, len(pods)) 130 } 131 132 data, err := kubeClient.EnvoyDo(context.TODO(), podName, podNamespace, "GET", "config_dump") 133 if err != nil { 134 return nil, fmt.Errorf("failed to get proxy config for %s.%s: %s", podName, podNamespace, err) 135 } 136 envoyConfig := &configdump.Wrapper{} 137 if err := envoyConfig.UnmarshalJSON(data); err != nil { 138 return nil, fmt.Errorf("failed to unmarshal proxy config: %s", err) 139 } 140 return envoyConfig, nil 141 } 142 143 // AuthZ groups commands used for inspecting and interacting the authorization policy. 144 // Note: this is still under active development and is not ready for real use. 145 func AuthZ(ctx cli.Context) *cobra.Command { 146 cmd := &cobra.Command{ 147 Use: "authz", 148 Short: "Inspect Istio AuthorizationPolicy", 149 } 150 151 cmd.AddCommand(checkCmd(ctx)) 152 cmd.Long += "\n\n" + util.ExperimentalMsg 153 return cmd 154 }