4
4
package policyfilter
5
5
6
6
import (
7
+ "context"
7
8
"fmt"
9
+ "os"
10
+ "path"
8
11
"path/filepath"
9
12
"strconv"
13
+ "strings"
14
+ "text/tabwriter"
10
15
16
+ "github.com/cilium/tetragon/api/v1/tetragon"
17
+ "github.com/cilium/tetragon/cmd/tetra/common"
11
18
"github.com/cilium/tetragon/cmd/tetra/debug"
12
19
"github.com/cilium/tetragon/pkg/cgroups"
20
+ "github.com/cilium/tetragon/pkg/cri"
13
21
"github.com/cilium/tetragon/pkg/defaults"
14
22
"github.com/cilium/tetragon/pkg/logger"
15
23
"github.com/cilium/tetragon/pkg/policyfilter"
@@ -29,6 +37,7 @@ func New() *cobra.Command {
29
37
addCommand (),
30
38
cgroupGetIDCommand (),
31
39
dumpDebugCmd (),
40
+ listPoliciesForContainer (),
32
41
)
33
42
34
43
return ret
@@ -138,3 +147,131 @@ func addCgroup(fname string, polID policyfilter.PolicyID, cgID policyfilter.Cgro
138
147
}
139
148
140
149
}
150
+
151
+ func listPoliciesForContainer () * cobra.Command {
152
+ var endpoint , cgroupMnt string
153
+ mapFname := filepath .Join (defaults .DefaultMapRoot , defaults .DefaultMapPrefix , policyfilter .MapName )
154
+ ret := & cobra.Command {
155
+ Use : "listpolicies [container id]" ,
156
+ Short : "list all Kubernetes Identity Aware policies that apply to a specific container" ,
157
+ Args : cobra .ExactArgs (1 ),
158
+ RunE : func (_ * cobra.Command , args []string ) error {
159
+ ctx := context .Background ()
160
+ client , err := cri .NewClient (ctx , endpoint )
161
+ if err != nil {
162
+ return err
163
+ }
164
+
165
+ cgroupPath , err := cri .CgroupPath (ctx , client , args [0 ])
166
+ if err != nil {
167
+ return err
168
+ }
169
+
170
+ if cgroupMnt == "" {
171
+ cgroupMnt = defaults .Cgroup2Dir
172
+ }
173
+ fullCgroupPath := path .Join (cgroupMnt , cgroupPath )
174
+ if common .Debug {
175
+ logger .GetLogger ().WithField ("path" , fullCgroupPath ).Info ("cgroup" )
176
+ }
177
+
178
+ cgID , err := cgroups .GetCgroupIdFromPath (fullCgroupPath )
179
+ if err != nil {
180
+ logger .GetLogger ().WithError (err ).Fatal ("Failed to parse cgroup" )
181
+ }
182
+
183
+ if common .Debug {
184
+ logger .GetLogger ().WithField ("id" , cgID ).Info ("cgroup" )
185
+ }
186
+
187
+ m , err := policyfilter .OpenMap (mapFname )
188
+ if err != nil {
189
+ logger .GetLogger ().WithError (err ).Fatal ("Failed to open policyfilter map" )
190
+ return err
191
+ }
192
+ defer m .Close ()
193
+
194
+ data , err := m .Dump ()
195
+ if err != nil {
196
+ logger .GetLogger ().WithError (err ).Fatal ("Failed to open policyfilter map" )
197
+ return err
198
+ }
199
+
200
+ policyIds , ok := data .Reverse [policyfilter .CgroupID (cgID )]
201
+ if ! ok {
202
+ return nil
203
+ }
204
+
205
+ c , err := common .NewClientWithDefaultContextAndAddress ()
206
+ if err != nil {
207
+ return fmt .Errorf ("failed create gRPC client: %w" , err )
208
+ }
209
+ defer c .Close ()
210
+
211
+ res , err := c .Client .ListTracingPolicies (c .Ctx , & tetragon.ListTracingPoliciesRequest {})
212
+ if err != nil || res == nil {
213
+ return fmt .Errorf ("failed to list tracing policies: %w" , err )
214
+ }
215
+
216
+ // tabwriter config imitates kubectl default output, i.e. 3 spaces padding
217
+ w := tabwriter .NewWriter (os .Stdout , 0 , 0 , 3 , ' ' , 0 )
218
+ fmt .Fprintln (w , "ID\t NAME\t STATE\t FILTERID\t NAMESPACE\t SENSORS\t KERNELMEMORY" )
219
+
220
+ for _ , pol := range res .Policies {
221
+ namespace := pol .Namespace
222
+ if namespace == "" {
223
+ namespace = "(global)"
224
+ }
225
+
226
+ sensors := strings .Join (pol .Sensors , "," )
227
+
228
+ // From v0.11 and before, enabled, filterID and error were
229
+ // bundled in a string. To have a retro-compatible tetra
230
+ // command, we scan the string. If the scan fails, it means
231
+ // something else might be in Info and we print it.
232
+ //
233
+ // we can drop the following block (and comment) when we
234
+ // feel tetra should support only version after v0.11
235
+ if pol .Info != "" {
236
+ var parsedEnabled bool
237
+ var parsedFilterID uint64
238
+ var parsedError string
239
+ var parsedName string
240
+ str := strings .NewReader (pol .Info )
241
+ _ , err := fmt .Fscanf (str , "%253s enabled:%t filterID:%d error:%512s" , & parsedName , & parsedEnabled , & parsedFilterID , & parsedError )
242
+ if err == nil {
243
+ if parsedEnabled {
244
+ pol .State = tetragon .TracingPolicyState_TP_STATE_ENABLED
245
+ }
246
+ pol .FilterId = parsedFilterID
247
+ pol .Error = parsedError
248
+ pol .Info = ""
249
+ }
250
+ }
251
+
252
+ if _ , ok := policyIds [policyfilter .PolicyID (pol .FilterId )]; ! ok {
253
+ continue
254
+ }
255
+
256
+ fmt .Fprintf (w , "%d\t %s\t %s\t %d\t %s\t %s\t %s\t \n " ,
257
+ pol .Id ,
258
+ pol .Name ,
259
+ strings .TrimPrefix (strings .ToLower (pol .State .String ()), "tp_state_" ),
260
+ pol .FilterId ,
261
+ namespace ,
262
+ sensors ,
263
+ common .HumanizeByteCount (int (pol .KernelMemoryBytes )),
264
+ )
265
+ }
266
+ w .Flush ()
267
+
268
+ return nil
269
+ },
270
+ }
271
+
272
+ flags := ret .Flags ()
273
+ flags .StringVarP (& endpoint , "runtime-endpoint" , "r" , "" , "CRI endpoint" )
274
+ flags .StringVar (& mapFname , "map-fname" , mapFname , "policyfilter map filename" )
275
+ flags .StringVar (& cgroupMnt , "cgroup-mount" , cgroupMnt , "cgroupFS mount point" )
276
+ return ret
277
+ }
0 commit comments