github.com/inspektor-gadget/inspektor-gadget@v0.28.1/docs/builtin-gadgets/advise/seccomp-profile.md (about) 1 --- 2 title: 'Using advise seccomp-profile' 3 weight: 20 4 description: > 5 Generate seccomp profiles based on recorded syscalls activity. 6 --- 7 8 The seccomp profile advisor gadget records syscalls that are issued in a 9 specified pod, and then uses this information to generate the corresponding 10 seccomp profile. It can integrate with the [Kubernetes Security Profile 11 Operator](https://github.com/kubernetes-sigs/security-profiles-operator), 12 directly generating the necessary `seccompprofile` resource. 13 14 ### On Kubernetes 15 16 #### Basic usage 17 18 For this demo, we will use a sample Python workload that uses uwsgi, flask 19 and nginx. The deployment is split in two pieces, the `basic.yaml` file 20 that has the infrastructure, and the `unconfined.yaml` file that has the 21 pod definition, with no seccomp profile applied. 22 23 ```bash 24 $ kubectl apply -f docs/examples/seccomp/basic.yaml 25 namespace/seccomp-demo created 26 configmap/app-script created 27 service/hello-python-service created 28 $ kubectl apply -f docs/examples/seccomp/unconfined.yaml 29 pod/hello-python created 30 ``` 31 32 It is now time to monitor system calls made by our pod: 33 34 ```bash 35 $ kubectl gadget advise seccomp-profile start -n seccomp-demo -p hello-python 36 jMzhur2dQjZJxDCI 37 ``` 38 39 The string we receive is the identifier that we will use to refer to the 40 running operation when we want to stop it. 41 42 While the advisor is running, we need to interact with the workload, to get it to generate 43 system calls. In our example, it's a simple webservice, and we can interact 44 with it by forwarding the service port and then querying the service 45 46 ```bash 47 $ kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 & 48 [1] 23574 49 Forwarding from 127.0.0.1:8080 -> 80 50 Forwarding from [::1]:8080 -> 80 51 52 $ curl localhost:8080 53 Handling connection for 8080 54 Hello World! 55 56 $ kill %1 57 [1]+ Terminated kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 58 ``` 59 60 Once we have captured the syscalls, we can ask the gadget to generate the 61 corresponding profile, by stopping the operation with the identifier we had 62 received before. 63 64 ```bash 65 $ kubectl gadget advise seccomp-profile stop jMzhur2dQjZJxDCI 66 { 67 "defaultAction": "SCMP_ACT_ERRNO", 68 "architectures": [ 69 "SCMP_ARCH_X86_64", 70 "SCMP_ARCH_X86", 71 "SCMP_ARCH_X32" 72 ], 73 "syscalls": [ 74 { 75 "names": [ 76 "accept4", 77 "close", 78 "connect", 79 "epoll_ctl", 80 "epoll_wait", 81 "fstat", 82 "getsockname", 83 "getsockopt", 84 "ioctl", 85 "poll", 86 "read", 87 "recvfrom", 88 "setsockopt", 89 "socket", 90 "stat", 91 "wait4", 92 "write", 93 "writev" 94 ], 95 "action": "SCMP_ACT_ALLOW" 96 } 97 ] 98 } 99 ``` 100 101 #### Capturing all syscalls needed to bring up the pod 102 103 That sample policy contains only the syscalls executed for that one single 104 request that we made. If we want to apply a policy to our pod, we need to 105 also include all the calls needed to bring the pod up. To do that, we need 106 to start the trace before the pod is up, then bring up the pod and generate 107 traffic. 108 109 We can delete the current pod, so that we can start a fresh new trace. 110 111 ```bash 112 $ kubectl delete -f docs/examples/seccomp/unconfined.yaml 113 pod "hello-python" deleted 114 ``` 115 116 Now we can create a new trace, and then create the pod again. 117 118 ```bash 119 $ kubectl gadget advise seccomp-profile start -n seccomp-demo -p hello-python 120 TAyR9BXes6GU04rG 121 $ kubectl apply -f docs/examples/seccomp/unconfined.yaml 122 pod/hello-python created 123 ``` 124 125 Once the pod is up, we can once again generate some traffic, like before. 126 127 ```bash 128 $ kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 & 129 [1] 28318 130 Forwarding from 127.0.0.1:8080 -> 80 131 Forwarding from [::1]:8080 -> 80 132 133 $ curl localhost:8080 134 Handling connection for 8080 135 Hello World! 136 137 $ kill %1 138 [1]+ Terminated kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 139 ``` 140 141 And now generate the policy again: 142 143 ```bash 144 $ kubectl gadget advise seccomp-profile stop TAyR9BXes6GU04rG 145 { 146 ... 147 } 148 ``` 149 150 This time, the output field will contain a lot more syscalls, as a lot of 151 operations need to take place to bring up the pod. 152 153 #### Integration with Kubernetes Security Profiles Operator 154 155 We can use the output stored in the trace to create the seccomp policy for our 156 pod. But instead of copying it manually, we can also use the integration with 157 the [Kubernetes Security Profiles Operator 158 (SPO)](https://github.com/kubernetes-sigs/security-profiles-operator). Notice 159 the seccomp gadget uses the seccomp profile API `v1beta1`, so at least SPO 160 v0.4.0 is required. Check the [SPO 161 documentation](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/installation-usage.md#install-operator) 162 for details about installation. Once the SPO is installed, the seccomp gadget 163 can generate `seccompprofile` resources that can be used directly by our pods. 164 165 We need to use the `--output-mode` (or simply `-m`) option to create the 166 `SeccompProfile` resource instead of printing the policy in the terminal 167 (default behaviour). Consider that using the option `--profile-prefix`, 168 we can specify the namespace and the prefix-name of the resource: 169 `namespace/prefix-name`. Notice the namespace is not mandatory. 170 If the option `--profile-prefix` is not used, the resource will be 171 automatically named using the pod name, and it will be created in the 172 trace's namespace (`gadget` if kubectl-gadget CLI was used). 173 174 ```bash 175 # Delete the pod. 176 $ kubectl delete -f docs/examples/seccomp/unconfined.yaml 177 pod "hello-python" deleted 178 179 # Create the pod and start a new trace again 180 $ kubectl gadget advise seccomp-profile start -m seccomp-profile -n seccomp-demo -p hello-python 181 TAyR9BXes6GU04rG 182 $ kubectl apply -f docs/examples/seccomp/unconfined.yaml 183 pod/hello-python created 184 185 # Generate traffic once again 186 $ kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 & 187 [1] 33679 188 Forwarding from 127.0.0.1:8080 -> 80 189 Forwarding from [::1]:8080 -> 80 190 $ curl localhost:8080 191 Handling connection for 8080 192 Hello World! 193 $ kill %1 194 [1]+ Terminated kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 195 196 # Now stop the gadget to generate the seccomp profile. 197 $ kubectl gadget advise seccomp-profile stop TAyR9BXes6GU04rG 198 $ kubectl get seccompprofile -n gadget 199 NAME STATUS AGE 200 hello-python Installed 9s 201 ``` 202 203 This profile can now be used as the seccomp profile for our pod. To do 204 that, we need to edit the configuration and replace the `Unconfined` 205 setting in our profile type, set it to `Localhost`, and add a 206 `localhostProfile` entry that points to the profile we just generated. 207 208 ```yaml 209 spec: 210 securityContext: 211 seccompProfile: 212 type: Localhost 213 localhostProfile: operator/gadget/hello-python.json 214 ``` 215 216 We have this change already applied in the `confined.yaml` file. To apply 217 this change, we need to delete the current pod and create a new one with 218 the new configuration: 219 220 ```bash 221 $ kubectl delete -f docs/examples/seccomp/unconfined.yaml 222 pod "hello-python" deleted 223 $ kubectl apply -f docs/examples/seccomp/confined.yaml 224 pod/hello-python created 225 ``` 226 227 Our workload is now running with the seccomp profile. We can verify that 228 it's running correctly by querying it once again like before: 229 230 ```bash 231 $ kubectl port-forward service/hello-python-service -n seccomp-demo 8080:6000 & 232 [1] 41643 233 $ Forwarding from 127.0.0.1:8080 -> 80 234 Forwarding from [::1]:8080 -> 80 235 236 $ curl localhost:8080 237 Handling connection for 8080 238 Hello World! 239 ``` 240 241 The request is allowed (as expected), but processes that require additional 242 syscalls will be blocked. For example, if we try to execute a shell in our 243 pod: 244 245 ```bash 246 $ kubectl exec -it -n seccomp-demo hello-python -- /bin/bash 247 bash: initialize_job_control: getpgrp failed: Success 248 command terminated with exit code 1 249 ``` 250 251 We see that the seccomp profile is preventing this execution, and it will 252 prevent any other execution that requires syscalls that were not part of 253 the captured calls. 254 255 #### Cleanup 256 257 Once we're done with the demo, we can delete all the resources that we've 258 used by deleting the `seccomp-demo` namespace: 259 260 ```bash 261 $ kubectl delete ns seccomp-demo 262 namespace "seccomp-demo" deleted 263 ``` 264 265 ### With `ig` 266 267 TODO! 268 269 ### Troubleshooting 270 271 1. If the annotations don't do anything, check that the node field is set 272 correctly. You can also look at the `Status` field of the `Trace` for 273 other possible errors. 274 275 2. If the confined pod fails to start with this error: 276 `cannot load seccomp profile "/var/lib/kubelet/seccomp/operator/seccomp-demo/hello-profile.json"`, 277 check that the operator is correctly installed and all pods involved are 278 running.