forked from cri-o/cri-o
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for OCI artifact seccomp profiles
Signed-off-by: Sascha Grunert <[email protected]>
- Loading branch information
1 parent
e9febd3
commit b20d06c
Showing
19 changed files
with
666 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,77 @@ | ||
package ociartifact | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/containers/common/libimage" | ||
"github.com/containers/common/pkg/config" | ||
"github.com/containers/image/v5/types" | ||
"github.com/containers/storage" | ||
|
||
"github.com/cri-o/cri-o/internal/log" | ||
) | ||
|
||
// Impl is the main implementation interface of this package. | ||
type Impl interface { | ||
Pull(context.Context, *types.SystemContext, string) (*Artifact, error) | ||
} | ||
|
||
// New returns a new OCI artifact implementation. | ||
func New() Impl { | ||
return &defaultImpl{} | ||
} | ||
|
||
// Artifact can be used to manage OCI artifacts. | ||
type Artifact struct { | ||
// MountPath is the local path containing the artifact data. | ||
MountPath string | ||
|
||
// Cleanup has to be called if the artifact is not used any more. | ||
Cleanup func() | ||
} | ||
|
||
// defaultImpl is the default implementation for the OCI artifact handling. | ||
type defaultImpl struct{} | ||
|
||
// Pull downloads and mounts the artifact content by using the provided ref. | ||
func (*defaultImpl) Pull(ctx context.Context, sys *types.SystemContext, ref string) (*Artifact, error) { | ||
log.Infof(ctx, "Pulling OCI artifact from ref: %s", ref) | ||
|
||
storeOpts, err := storage.DefaultStoreOptions(false, 0) | ||
if err != nil { | ||
return nil, fmt.Errorf("get default storage options: %w", err) | ||
} | ||
|
||
store, err := storage.GetStore(storeOpts) | ||
if err != nil { | ||
return nil, fmt.Errorf("get container storage: %w", err) | ||
} | ||
|
||
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: sys}) | ||
if err != nil { | ||
return nil, fmt.Errorf("create libimage runtime: %w", err) | ||
} | ||
|
||
images, err := runtime.Pull(ctx, ref, config.PullPolicyAlways, &libimage.PullOptions{}) | ||
if err != nil { | ||
return nil, fmt.Errorf("pull OCI artifact: %w", err) | ||
} | ||
image := images[0] | ||
|
||
mountPath, err := image.Mount(ctx, nil, "") | ||
if err != nil { | ||
return nil, fmt.Errorf("mount OCI artifact: %w", err) | ||
} | ||
|
||
cleanup := func() { | ||
if err := image.Unmount(true); err != nil { | ||
log.Warnf(ctx, "Unable to unmount OCI artifact path %s: %v", mountPath, err) | ||
} | ||
} | ||
|
||
return &Artifact{ | ||
MountPath: mountPath, | ||
Cleanup: cleanup, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
internal/config/seccomp/seccompociartifact/seccompociartifact.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,93 @@ | ||
package seccompociartifact | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/containers/image/v5/types" | ||
|
||
"github.com/cri-o/cri-o/internal/config/ociartifact" | ||
"github.com/cri-o/cri-o/internal/log" | ||
"github.com/cri-o/cri-o/pkg/annotations" | ||
) | ||
|
||
// SeccompOCIArtifact is the main structure for handling seccomp related OCI | ||
// artifacts. | ||
type SeccompOCIArtifact struct { | ||
ociArtifactImpl ociartifact.Impl | ||
} | ||
|
||
// New creates a new seccomp OCI artifact handler. | ||
func New() *SeccompOCIArtifact { | ||
return &SeccompOCIArtifact{ | ||
ociArtifactImpl: ociartifact.New(), | ||
} | ||
} | ||
|
||
// TryPull tries to pull the OCI artifact seccomp profile while evaluating | ||
// the provided annotations. | ||
func (s *SeccompOCIArtifact) TryPull( | ||
ctx context.Context, | ||
sys *types.SystemContext, | ||
containerName string, | ||
podAnnotations, imageAnnotations map[string]string, | ||
) (profile []byte, err error) { | ||
log.Debugf(ctx, "Evaluating seccomp annotations") | ||
|
||
profileRef := "" | ||
containerKey := fmt.Sprintf("%s/%s", annotations.SeccompProfileAnnotation, containerName) | ||
if val, ok := podAnnotations[containerKey]; ok { | ||
log.Infof(ctx, "Found container specific seccomp profile annotation: %s=%s", containerKey, val) | ||
profileRef = val | ||
} else if val, ok := podAnnotations[annotations.SeccompProfileAnnotation]; ok { | ||
log.Infof(ctx, "Found pod specific seccomp profile annotation: %s=%s", annotations.SeccompProfileAnnotation, val) | ||
profileRef = val | ||
} else if val, ok := imageAnnotations[annotations.SeccompProfileAnnotation]; ok { | ||
log.Infof(ctx, "Found image specific seccomp profile annotation: %s=%s", annotations.SeccompProfileAnnotation, val) | ||
profileRef = val | ||
} | ||
|
||
if profileRef == "" { | ||
return nil, nil | ||
} | ||
|
||
artifact, err := s.ociArtifactImpl.Pull(ctx, sys, profileRef) | ||
if err != nil { | ||
return nil, fmt.Errorf("pull OCI artifact: %w", err) | ||
} | ||
defer artifact.Cleanup() | ||
|
||
const jsonExt = ".json" | ||
seccompProfilePath := "" | ||
if err := filepath.Walk(artifact.MountPath, | ||
func(p string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if info.IsDir() || | ||
info.Mode()&os.ModeSymlink == os.ModeSymlink || | ||
filepath.Ext(info.Name()) != jsonExt { | ||
return nil | ||
} | ||
|
||
seccompProfilePath = p | ||
|
||
// TODO(sgrunert): allow merging profiles, not just choosing the first one | ||
return fs.SkipAll | ||
}); err != nil { | ||
return nil, fmt.Errorf("walk %s: %w", artifact.MountPath, err) | ||
} | ||
|
||
log.Infof(ctx, "Trying to read profile from: %s", seccompProfilePath) | ||
profileContent, err := os.ReadFile(seccompProfilePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("read %s from file store: %w", seccompProfilePath, err) | ||
} | ||
|
||
log.Infof(ctx, "Retrieved OCI artifact seccomp profile of len: %d", len(profileContent)) | ||
return profileContent, nil | ||
} |
Oops, something went wrong.