Skip to content

Commit aa45d61

Browse files
authored
Merge pull request #40485 from saschagrunert/spo-oci-blog
Add blog post about OCI security profiles
2 parents 4947c88 + b07cde4 commit aa45d61

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
layout: blog
3+
title: "Using OCI artifacts to distribute security profiles for seccomp, SELinux and AppArmor"
4+
date: 2023-05-24
5+
slug: oci-security-profiles
6+
---
7+
8+
**Author**: Sascha Grunert
9+
10+
The [Security Profiles Operator (SPO)][spo] makes managing seccomp, SELinux and
11+
AppArmor profiles within Kubernetes easier than ever. It allows cluster
12+
administrators to define the profiles in a predefined custom resource YAML,
13+
which then gets distributed by the SPO into the whole cluster. Modification and
14+
removal of the security profiles are managed by the operator in the same way,
15+
but that’s a small subset of its capabilities.
16+
17+
[spo]: https://github.com/kubernetes-sigs/security-profiles-operator
18+
19+
Another core feature of the SPO is being able to stack seccomp profiles. This
20+
means that users can define a `baseProfileName` in the YAML specification, which
21+
then gets automatically resolved by the operator and combines the syscall rules.
22+
If a base profile has another `baseProfileName`, then the operator will
23+
recursively resolve the profiles up to a certain depth. A common use case is to
24+
define base profiles for low level container runtimes (like [runc][runc] or
25+
[crun][crun]) which then contain syscalls which are required in any case to run
26+
the container. Alternatively, application developers can define seccomp base
27+
profiles for their standard distribution containers and stack dedicated profiles
28+
for the application logic on top. This way developers can focus on maintaining
29+
seccomp profiles which are way simpler and scoped to the application logic,
30+
without having a need to take the whole infrastructure setup into account.
31+
32+
[runc]: https://github.com/opencontainers/runc
33+
[crun]: https://github.com/containers/crun
34+
35+
But how to maintain those base profiles? For example, the amount of required
36+
syscalls for a runtime can change over its release cycle in the same way it can
37+
change for the main application. Base profiles have to be available in the same
38+
cluster, otherwise the main seccomp profile will fail to deploy. This means that
39+
they’re tightly coupled to the main application profiles, which acts against the
40+
main idea of base profiles. Distributing and managing them as plain files feels
41+
like an additional burden to solve.
42+
43+
## OCI artifacts to the rescue
44+
45+
The [v0.8.0][spo-latest] release of the Security Profiles Operator supports
46+
managing base profiles as OCI artifacts! Imagine OCI artifacts as lightweight
47+
container images, storing files in layers in the same way images do, but without
48+
a process to be executed. Those artifacts can be used to store security profiles
49+
like regular container images in compatible registries. This means they can be
50+
versioned, namespaced and annotated similar to regular container images.
51+
52+
[spo-latest]: https://github.com/kubernetes-sigs/security-profiles-operator/releases/v0.8.0
53+
54+
To see how that works in action, specify a `baseProfileName` prefixed with
55+
`oci://` within a seccomp profile CRD, for example:
56+
57+
```yaml
58+
apiVersion: security-profiles-operator.x-k8s.io/v1beta1
59+
kind: SeccompProfile
60+
metadata:
61+
name: test
62+
spec:
63+
defaultAction: SCMP_ACT_ERRNO
64+
baseProfileName: oci://ghcr.io/security-profiles/runc:v1.1.5
65+
syscalls:
66+
- action: SCMP_ACT_ALLOW
67+
names:
68+
- uname
69+
```
70+
71+
The operator will take care of pulling the content by using [oras][oras], as
72+
well as verifying the [sigstore (cosign)][cosign] signatures of the artifact. If
73+
the artifacts are not signed, then the SPO will reject them. The resulting
74+
profile `test` will then contain all base syscalls from the remote `runc`
75+
profile plus the additional allowed `uname` one. It is also possible to
76+
reference the base profile by its digest (SHA256) making the artifact to be
77+
pulled more specific, for example by referencing
78+
`oci://ghcr.io/security-profiles/runc@sha256:380…`.
79+
80+
[oras]: https://oras.land
81+
[cosign]: https://github.com/sigstore/cosign
82+
83+
The operator internally caches pulled artifacts up to 24 hours for 1000
84+
profiles, meaning that they will be refreshed after that time period, if the
85+
cache is full or the operator daemon gets restarted.
86+
87+
Because the overall resulting syscalls are hidden from the user (I only have the
88+
`baseProfileName` listed in the SeccompProfile, and not the syscalls themselves), I'll additionally
89+
annotate that SeccompProfile with the final `syscalls`.
90+
91+
Here's how the SeccompProfile looks after I annotate it:
92+
93+
```console
94+
> kubectl describe seccompprofile test
95+
Name: test
96+
Namespace: security-profiles-operator
97+
Labels: spo.x-k8s.io/profile-id=SeccompProfile-test
98+
Annotations: syscalls:
99+
[{"names":["arch_prctl","brk","capget","capset","chdir","clone","close",...
100+
API Version: security-profiles-operator.x-k8s.io/v1beta1
101+
```
102+
103+
The SPO maintainers provide all public base profiles as part of the [“Security
104+
Profiles” GitHub organization][org].
105+
106+
[org]: https://github.com/orgs/security-profiles/packages
107+
108+
## Managing OCI security profiles
109+
110+
Alright, now the official SPO provides a bunch of base profiles, but how can I
111+
define my own? Well, first of all we have to choose a working registry. There
112+
are a bunch of registries that already supports OCI artifacts:
113+
114+
- [CNCF Distribution](https://github.com/distribution/distribution)
115+
- [Azure Container Registry](https://aka.ms/acr)
116+
- [Amazon Elastic Container Registry](https://aws.amazon.com/ecr)
117+
- [Google Artifact Registry](https://cloud.google.com/artifact-registry)
118+
- [GitHub Packages container registry](https://docs.github.com/en/packages/guides/about-github-container-registry)
119+
- [Bundle Bar](https://bundle.bar/docs/supported-clients/oras)
120+
- [Docker Hub](https://hub.docker.com)
121+
- [Zot Registry](https://zotregistry.io)
122+
123+
The Security Profiles Operator ships a new command line interface called `spoc`,
124+
which is a little helper tool for managing OCI profiles among doing various other
125+
things which are out of scope of this blog post. But, the command `spoc push`
126+
can be used to push a security profile to a registry:
127+
128+
```
129+
> export USERNAME=my-user
130+
> export PASSWORD=my-pass
131+
> spoc push -f ./examples/baseprofile-crun.yaml ghcr.io/security-profiles/crun:v1.8.3
132+
16:35:43.899886 Pushing profile ./examples/baseprofile-crun.yaml to: ghcr.io/security-profiles/crun:v1.8.3
133+
16:35:43.899939 Creating file store in: /tmp/push-3618165827
134+
16:35:43.899947 Adding profile to store: ./examples/baseprofile-crun.yaml
135+
16:35:43.900061 Packing files
136+
16:35:43.900282 Verifying reference: ghcr.io/security-profiles/crun:v1.8.3
137+
16:35:43.900310 Using tag: v1.8.3
138+
16:35:43.900313 Creating repository for ghcr.io/security-profiles/crun
139+
16:35:43.900319 Using username and password
140+
16:35:43.900321 Copying profile to repository
141+
16:35:46.976108 Signing container image
142+
Generating ephemeral keys...
143+
Retrieving signed certificate...
144+
145+
Note that there may be personally identifiable information associated with this signed artifact.
146+
This may include the email address associated with the account with which you authenticate.
147+
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
148+
149+
By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.
150+
Your browser will now be opened to:
151+
https://oauth2.sigstore.dev/auth/auth?access_type=…
152+
Successfully verified SCT...
153+
tlog entry created with index: 16520520
154+
Pushing signature to: ghcr.io/security-profiles/crun
155+
```
156+
157+
You can see that the tool automatically signs the artifact and pushes the
158+
`./examples/baseprofile-crun.yaml` to the registry, which is then directly ready
159+
for usage within the SPO. If username and password authentication is required,
160+
either use the `--username`, `-u` flag or export the `USERNAME` environment
161+
variable. To set the password, export the `PASSWORD` environment variable.
162+
163+
It is possible to add custom annotations to the security profile by using the
164+
`--annotations` / `-a` flag multiple times in `KEY:VALUE` format. Those have no
165+
effect for now, but at some later point additional features of the operator may
166+
rely them.
167+
168+
The `spoc` client is also able to pull security profiles from OCI artifact
169+
compatible registries. To do that, just run `spoc pull`:
170+
171+
```console
172+
> spoc pull ghcr.io/security-profiles/runc:v1.1.5
173+
16:32:29.795597 Pulling profile from: ghcr.io/security-profiles/runc:v1.1.5
174+
16:32:29.795610 Verifying signature
175+
176+
Verification for ghcr.io/security-profiles/runc:v1.1.5 --
177+
The following checks were performed on each of these signatures:
178+
- Existence of the claims in the transparency log was verified offline
179+
- The code-signing certificate was verified using trusted certificate authority certificates
180+
181+
[{"critical":{"identity":{"docker-reference":"ghcr.io/security-profiles/runc"},…}}]
182+
16:32:33.208695 Creating file store in: /tmp/pull-3199397214
183+
16:32:33.208713 Verifying reference: ghcr.io/security-profiles/runc:v1.1.5
184+
16:32:33.208718 Creating repository for ghcr.io/security-profiles/runc
185+
16:32:33.208742 Using tag: v1.1.5
186+
16:32:33.208743 Copying profile from repository
187+
16:32:34.119652 Reading profile
188+
16:32:34.119677 Trying to unmarshal seccomp profile
189+
16:32:34.120114 Got SeccompProfile: runc-v1.1.5
190+
16:32:34.120119 Saving profile in: /tmp/profile.yaml
191+
```
192+
193+
The profile can be now found in `/tmp/profile.yaml` or the specified output file
194+
`--output-file` / `-o`. We can specify an username and password in the same way
195+
as for `spoc push`.
196+
197+
`spoc` makes it easy to manage security profiles as OCI artifacts, which can be
198+
then consumed directly by the operator itself.
199+
200+
That was our compact journey through the latest possibilities of the Security
201+
Profiles Operator! If you're interested in more, providing feedback or asking
202+
for help, then feel free to get in touch with us directly via [Slack
203+
(#security-profiles-operator)][slack] or [the mailing list][mail].
204+
205+
[slack]: https://kubernetes.slack.com/messages/security-profiles-operator
206+
[mail]: https://groups.google.com/forum/#!forum/kubernetes-dev

0 commit comments

Comments
 (0)