Add support for container kernel capabilities (#716)

This patch adds two new command-line flags to specify one or
more kernel capabilities to add or remove from the workflow
containers.

The command-line flag `--container-cap-add` allows for adding
specific capabilities on the workflow containers; where as,

The command-line flag `--container-cap-drop` allows for removing
specific capabilities on the workflow containers.

This was developed to specifically be able to add `SYS_PTRACE`
to a workflow I maintain. It involves using this capability to
monitor a make build, to then build a compilation database.

Signed-off-by: Joseph Benden <joe@benden.us>
This commit is contained in:
Joseph Benden 2021-06-04 09:06:59 -07:00 committed by GitHub
parent 8a9167da82
commit 6b4d359737
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 17 additions and 7 deletions

View file

@ -32,6 +32,8 @@ type Input struct {
noWorkflowRecurse bool
useGitIgnore bool
githubInstance string
containerCapAdd []string
containerCapDrop []string
}
func (i *Input) resolve(path string) string {

View file

@ -50,6 +50,8 @@ func Execute(ctx context.Context, version string) {
rootCmd.Flags().BoolVar(&input.privileged, "privileged", false, "use privileged mode")
rootCmd.Flags().StringVar(&input.usernsMode, "userns", "", "user namespace to use")
rootCmd.Flags().BoolVar(&input.useGitIgnore, "use-gitignore", true, "Controls whether paths specified in .gitignore should be copied into container")
rootCmd.Flags().StringArrayVarP(&input.containerCapAdd, "container-cap-add", "", []string{}, "kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)")
rootCmd.Flags().StringArrayVarP(&input.containerCapDrop, "container-cap-drop", "", []string{}, "kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)")
rootCmd.PersistentFlags().StringVarP(&input.actor, "actor", "a", "nektos/act", "user that triggered the event")
rootCmd.PersistentFlags().StringVarP(&input.workflowsPath, "workflows", "W", "./.github/workflows/", "path to workflow file(s)")
rootCmd.PersistentFlags().BoolVarP(&input.noWorkflowRecurse, "no-recurse", "", false, "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag")
@ -259,6 +261,8 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
ContainerDaemonSocket: input.containerDaemonSocket,
UseGitIgnore: input.useGitIgnore,
GitHubInstance: input.githubInstance,
ContainerCapAdd: input.containerCapAdd,
ContainerCapDrop: input.containerCapDrop,
}
r, err := runner.New(config)
if err != nil {

View file

@ -63,7 +63,7 @@ type FileEntry struct {
// Container for managing docker run containers
type Container interface {
Create() common.Executor
Create(capAdd []string, capDrop []string) common.Executor
Copy(destPath string, files ...*FileEntry) common.Executor
CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor
Pull(forcePull bool) common.Executor
@ -100,14 +100,14 @@ func supportsContainerImagePlatform(cli *client.Client) bool {
return constraint.Check(sv)
}
func (cr *containerReference) Create() common.Executor {
func (cr *containerReference) Create(capAdd []string, capDrop []string) common.Executor {
return common.
NewDebugExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd).
Then(
common.NewPipelineExecutor(
cr.connect(),
cr.find(),
cr.create(),
cr.create(capAdd, capDrop),
).IfNot(common.Dryrun),
)
}
@ -274,7 +274,7 @@ func (cr *containerReference) remove() common.Executor {
}
}
func (cr *containerReference) create() common.Executor {
func (cr *containerReference) create(capAdd []string, capDrop []string) common.Executor {
return func(ctx context.Context) error {
if cr.id != "" {
return nil
@ -315,6 +315,8 @@ func (cr *containerReference) create() common.Executor {
}
}
resp, err := cr.cli.ContainerCreate(ctx, config, &container.HostConfig{
CapAdd: capAdd,
CapDrop: capDrop,
Binds: input.Binds,
Mounts: mounts,
NetworkMode: container.NetworkMode(input.NetworkMode),

View file

@ -148,7 +148,7 @@ func (rc *RunContext) startJobContainer() common.Executor {
return common.NewPipelineExecutor(
rc.JobContainer.Pull(rc.Config.ForcePull),
rc.stopJobContainer(),
rc.JobContainer.Create(),
rc.JobContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
rc.JobContainer.Start(false),
rc.JobContainer.UpdateFromEnv("/etc/environment", &rc.Env),
rc.JobContainer.Exec([]string{"mkdir", "-m", "0777", "-p", ActPath}, rc.Env, "root"),

View file

@ -40,6 +40,8 @@ type Config struct {
ContainerDaemonSocket string // Path to Docker daemon socket
UseGitIgnore bool // controls if paths in .gitignore should not be copied into container, default true
GitHubInstance string // GitHub instance to use, default "github.com"
ContainerCapAdd []string // list of kernel capabilities to add to the containers
ContainerCapDrop []string // list of kernel capabilities to remove from the containers
}
// Resolves the equivalent host path inside the container

View file

@ -299,7 +299,7 @@ func (sc *StepContext) runUsesContainer() common.Executor {
return common.NewPipelineExecutor(
stepContainer.Pull(rc.Config.ForcePull),
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers),
stepContainer.Create(),
stepContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
stepContainer.Start(true),
).Finally(
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers),
@ -517,7 +517,7 @@ func (sc *StepContext) execAsDocker(ctx context.Context, action *model.Action, a
prepImage,
stepContainer.Pull(rc.Config.ForcePull),
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers),
stepContainer.Create(),
stepContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
stepContainer.Start(true),
).Finally(
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers),