github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/flag/kubernetes_flags.go (about) 1 package flag 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/samber/lo" 9 corev1 "k8s.io/api/core/v1" 10 ) 11 12 var ( 13 ClusterContextFlag = Flag{ 14 Name: "context", 15 ConfigName: "kubernetes.context", 16 Default: "", 17 Usage: "specify a context to scan", 18 Aliases: []Alias{ 19 {Name: "ctx"}, 20 }, 21 } 22 K8sNamespaceFlag = Flag{ 23 Name: "namespace", 24 ConfigName: "kubernetes.namespace", 25 Shorthand: "n", 26 Default: "", 27 Usage: "specify a namespace to scan", 28 } 29 KubeConfigFlag = Flag{ 30 Name: "kubeconfig", 31 ConfigName: "kubernetes.kubeconfig", 32 Default: "", 33 Usage: "specify the kubeconfig file path to use", 34 } 35 ComponentsFlag = Flag{ 36 Name: "components", 37 ConfigName: "kubernetes.components", 38 Default: []string{ 39 "workload", 40 "infra", 41 }, 42 Values: []string{ 43 "workload", 44 "infra", 45 }, 46 Usage: "specify which components to scan", 47 } 48 K8sVersionFlag = Flag{ 49 Name: "k8s-version", 50 ConfigName: "kubernetes.k8s.version", 51 Default: "", 52 Usage: "specify k8s version to validate outdated api by it (example: 1.21.0)", 53 } 54 TolerationsFlag = Flag{ 55 Name: "tolerations", 56 ConfigName: "kubernetes.tolerations", 57 Default: []string{}, 58 Usage: "specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule)", 59 } 60 AllNamespaces = Flag{ 61 Name: "all-namespaces", 62 ConfigName: "kubernetes.all.namespaces", 63 Shorthand: "A", 64 Default: false, 65 Usage: "fetch resources from all cluster namespaces", 66 } 67 NodeCollectorNamespace = Flag{ 68 Name: "node-collector-namespace", 69 ConfigName: "node.collector.namespace", 70 Default: "trivy-temp", 71 Usage: "specify the namespace in which the node-collector job should be deployed", 72 } 73 ExcludeOwned = Flag{ 74 Name: "exclude-owned", 75 ConfigName: "kubernetes.exclude.owned", 76 Default: false, 77 Usage: "exclude resources that have an owner reference", 78 } 79 ExcludeNodes = Flag{ 80 Name: "exclude-nodes", 81 ConfigName: "exclude.nodes", 82 Default: []string{}, 83 Usage: "indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)", 84 } 85 ) 86 87 type K8sFlagGroup struct { 88 ClusterContext *Flag 89 Namespace *Flag 90 KubeConfig *Flag 91 Components *Flag 92 K8sVersion *Flag 93 Tolerations *Flag 94 AllNamespaces *Flag 95 NodeCollectorNamespace *Flag 96 ExcludeOwned *Flag 97 ExcludeNodes *Flag 98 } 99 100 type K8sOptions struct { 101 ClusterContext string 102 Namespace string 103 KubeConfig string 104 Components []string 105 K8sVersion string 106 Tolerations []corev1.Toleration 107 AllNamespaces bool 108 NodeCollectorNamespace string 109 ExcludeOwned bool 110 ExcludeNodes map[string]string 111 } 112 113 func NewK8sFlagGroup() *K8sFlagGroup { 114 return &K8sFlagGroup{ 115 ClusterContext: &ClusterContextFlag, 116 Namespace: &K8sNamespaceFlag, 117 KubeConfig: &KubeConfigFlag, 118 Components: &ComponentsFlag, 119 K8sVersion: &K8sVersionFlag, 120 Tolerations: &TolerationsFlag, 121 AllNamespaces: &AllNamespaces, 122 NodeCollectorNamespace: &NodeCollectorNamespace, 123 ExcludeOwned: &ExcludeOwned, 124 ExcludeNodes: &ExcludeNodes, 125 } 126 } 127 128 func (f *K8sFlagGroup) Name() string { 129 return "Kubernetes" 130 } 131 132 func (f *K8sFlagGroup) Flags() []*Flag { 133 return []*Flag{ 134 f.ClusterContext, 135 f.Namespace, 136 f.KubeConfig, 137 f.Components, 138 f.K8sVersion, 139 f.Tolerations, 140 f.AllNamespaces, 141 f.NodeCollectorNamespace, 142 f.ExcludeOwned, 143 f.ExcludeNodes, 144 } 145 } 146 147 func (f *K8sFlagGroup) ToOptions() (K8sOptions, error) { 148 tolerations, err := optionToTolerations(getStringSlice(f.Tolerations)) 149 if err != nil { 150 return K8sOptions{}, err 151 } 152 153 exludeNodeLabels := make(map[string]string) 154 exludeNodes := getStringSlice(f.ExcludeNodes) 155 for _, exludeNodeValue := range exludeNodes { 156 excludeNodeParts := strings.Split(exludeNodeValue, ":") 157 if len(excludeNodeParts) != 2 { 158 return K8sOptions{}, fmt.Errorf("exclude node %s must be a key:value", exludeNodeValue) 159 } 160 exludeNodeLabels[excludeNodeParts[0]] = excludeNodeParts[1] 161 } 162 163 return K8sOptions{ 164 ClusterContext: getString(f.ClusterContext), 165 Namespace: getString(f.Namespace), 166 KubeConfig: getString(f.KubeConfig), 167 Components: getStringSlice(f.Components), 168 K8sVersion: getString(f.K8sVersion), 169 Tolerations: tolerations, 170 AllNamespaces: getBool(f.AllNamespaces), 171 NodeCollectorNamespace: getString(f.NodeCollectorNamespace), 172 ExcludeOwned: getBool(f.ExcludeOwned), 173 ExcludeNodes: exludeNodeLabels, 174 }, nil 175 } 176 177 func optionToTolerations(tolerationsOptions []string) ([]corev1.Toleration, error) { 178 var tolerations []corev1.Toleration 179 for _, toleration := range tolerationsOptions { 180 tolerationParts := strings.Split(toleration, ":") 181 if len(tolerationParts) < 2 { 182 return []corev1.Toleration{}, fmt.Errorf("toleration must include key and effect") 183 } 184 if corev1.TaintEffect(tolerationParts[1]) != corev1.TaintEffectNoSchedule && 185 corev1.TaintEffect(tolerationParts[1]) != corev1.TaintEffectPreferNoSchedule && 186 corev1.TaintEffect(tolerationParts[1]) != corev1.TaintEffectNoExecute { 187 return []corev1.Toleration{}, fmt.Errorf("toleration effect must be a valid value") 188 } 189 keyValue := strings.Split(tolerationParts[0], "=") 190 operator := corev1.TolerationOpEqual 191 if keyValue[1] == "" { 192 operator = corev1.TolerationOpExists 193 } 194 toleration := corev1.Toleration{ 195 Key: keyValue[0], 196 Value: keyValue[1], 197 Operator: operator, 198 Effect: corev1.TaintEffect(tolerationParts[1]), 199 } 200 var tolerationSec int 201 var err error 202 if len(tolerationParts) == 3 { 203 tolerationSec, err = strconv.Atoi(tolerationParts[2]) 204 if err != nil { 205 return nil, fmt.Errorf("TolerationSeconds must must be a number") 206 } 207 toleration.TolerationSeconds = lo.ToPtr(int64(tolerationSec)) 208 } 209 tolerations = append(tolerations, toleration) 210 } 211 return tolerations, nil 212 }