diff --git a/.github/workflows/ubuntu-tests.yaml b/.github/workflows/ubuntu-tests.yaml index 438f6fa..b739051 100644 --- a/.github/workflows/ubuntu-tests.yaml +++ b/.github/workflows/ubuntu-tests.yaml @@ -1,5 +1,5 @@ # -# Copyright © 2023 – 2024 Red Hat, Inc. +# Copyright © 2023 – 2025 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,6 +55,9 @@ jobs: systemd \ udisks2 + - name: Ensure that 'p11-kit server' is absent + run: sudo rm /usr/libexec/p11-kit/p11-kit-server + - name: Set up PATH for Go 1.21 run: | echo "PATH=/usr/lib/go-1.21/bin:$PATH" >> "$GITHUB_ENV" @@ -131,7 +134,7 @@ jobs: working-directory: containers/toolbox/src - name: Set up build directory - run: meson setup --fatal-meson-warnings builddir + run: meson setup builddir working-directory: containers/toolbox - name: Build diff --git a/meson.build b/meson.build index 6cb9691..3f85363 100644 --- a/meson.build +++ b/meson.build @@ -23,6 +23,27 @@ bats = find_program('bats', required: false) codespell = find_program('codespell', required: false) htpasswd = find_program('htpasswd', required: false) openssl = find_program('openssl', required: false) + +p11kit_server_works = false +p11kit = find_program('p11-kit', required: false) +if p11kit.found() + res = run_command(p11kit, 'server', check: false) + if res.returncode() == 0 + error('Command \'p11-kit server\' was supposed to fail') + endif + + res_stdout = res.stdout() + if res_stdout.contains('--name') and res_stdout.contains('--provider') + p11kit_server_works = true + else + warning('Command \'p11-kit server\' doesn\'t work') + endif +endif + +if not p11kit_server_works + warning('Containers won\'t have access to the CA certificates from the host') +endif + podman = find_program('podman', required: false) shellcheck = find_program('shellcheck', required: false) skopeo = find_program('skopeo', required: false) diff --git a/playbooks/dependencies-centos-9-stream.yaml b/playbooks/dependencies-centos-9-stream.yaml index 92c38e7..2ca6ddd 100644 --- a/playbooks/dependencies-centos-9-stream.yaml +++ b/playbooks/dependencies-centos-9-stream.yaml @@ -38,6 +38,13 @@ - codespell - fish +- name: Ensure that 'p11-kit server' is absent + become: yes + package: + name: + - p11-kit-server + state: absent + - name: Download Go modules command: go mod download -x environment: diff --git a/playbooks/dependencies-fedora-restricted.yaml b/playbooks/dependencies-fedora-restricted.yaml index 13973b6..129668a 100644 --- a/playbooks/dependencies-fedora-restricted.yaml +++ b/playbooks/dependencies-fedora-restricted.yaml @@ -1,5 +1,5 @@ # -# Copyright © 2023 – 2024 Red Hat, Inc. +# Copyright © 2023 – 2025 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -47,6 +47,15 @@ update_cache: "{{ true if zuul.attempts > 1 else false }}" use: "{{ 'dnf' if zuul.attempts > 1 else 'auto' }}" +- name: Ensure that 'p11-kit server' is absent + become: yes + package: + name: + - p11-kit-server + state: absent + update_cache: "{{ true if zuul.attempts > 1 else false }}" + use: "{{ 'dnf' if zuul.attempts > 1 else 'auto' }}" + - name: Ensure that podman(1) is absent become: yes package: diff --git a/playbooks/dependencies-fedora.yaml b/playbooks/dependencies-fedora.yaml index 2ef9ea2..0f10f5a 100644 --- a/playbooks/dependencies-fedora.yaml +++ b/playbooks/dependencies-fedora.yaml @@ -1,5 +1,5 @@ # -# Copyright © 2022 – 2024 Red Hat, Inc. +# Copyright © 2022 – 2025 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,6 +39,15 @@ - udisks2 use: "{{ 'dnf' if zuul.attempts > 1 else 'auto' }}" +- name: Ensure that 'p11-kit server' is absent + become: yes + package: + name: + - p11-kit-server + state: absent + update_cache: "{{ true if zuul.attempts > 1 else false }}" + use: "{{ 'dnf' if zuul.attempts > 1 else 'auto' }}" + - name: Download Go modules command: go mod download -x environment: diff --git a/playbooks/setup-env-migration-path-for-coreos-toolbox.yaml b/playbooks/setup-env-migration-path-for-coreos-toolbox.yaml index 571c4e6..6fe3312 100644 --- a/playbooks/setup-env-migration-path-for-coreos-toolbox.yaml +++ b/playbooks/setup-env-migration-path-for-coreos-toolbox.yaml @@ -20,6 +20,6 @@ - include_tasks: dependencies-centos-9-stream.yaml - name: Set up build directory - command: meson -Dmigration_path_for_coreos_toolbox=true --fatal-meson-warnings builddir + command: meson -Dmigration_path_for_coreos_toolbox=true builddir args: chdir: '{{ zuul.project.src_dir }}' diff --git a/playbooks/setup-env-restricted.yaml b/playbooks/setup-env-restricted.yaml index 11e751f..123177b 100644 --- a/playbooks/setup-env-restricted.yaml +++ b/playbooks/setup-env-restricted.yaml @@ -20,6 +20,6 @@ - include_tasks: dependencies-fedora-restricted.yaml - name: Set up build directory - command: meson setup --fatal-meson-warnings builddir + command: meson setup builddir args: chdir: '{{ zuul.project.src_dir }}' diff --git a/playbooks/setup-env.yaml b/playbooks/setup-env.yaml index bebd09e..dc08f13 100644 --- a/playbooks/setup-env.yaml +++ b/playbooks/setup-env.yaml @@ -20,6 +20,6 @@ - include_tasks: dependencies-fedora.yaml - name: Set up build directory - command: meson setup --fatal-meson-warnings builddir + command: meson setup builddir args: chdir: '{{ zuul.project.src_dir }}' diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index ac9534b..a5c868f 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -301,6 +301,10 @@ func initContainer(cmd *cobra.Command, args []string) error { return err } + if err := configurePKCS11(targetUser); err != nil { + return err + } + if err := configureRPM(); err != nil { return err } @@ -569,6 +573,57 @@ func configureKerberos() error { return nil } +func configurePKCS11(targetUser *user.User) error { + const logPrefix = "Configuring PKCS #11 to read from the host" + logrus.Debugf("%s", logPrefix) + + if path := "/etc/pkcs11/modules"; !utils.PathExists(path) { + logrus.Debugf("%s: directory %s not found", logPrefix, path) + logrus.Debugf("%s: skipping", logPrefix) + return nil + } + + if ok, err := utils.IsP11KitClientPresent(); err != nil { + logrus.Debugf("%s: %s", logPrefix, err) + + if !ok { + logrus.Debugf("%s: p11-kit-client.so not found", logPrefix) + logrus.Debugf("%s: skipping", logPrefix) + return nil + } + } else { + if !ok { + logrus.Debugf("%s: p11-kit-client.so not found", logPrefix) + logrus.Debugf("%s: skipping", logPrefix) + return nil + } + } + + if path, err := utils.GetP11KitServerSocket(targetUser); err != nil { + return err + } else if !utils.PathExists(path) { + logrus.Debugf("%s: socket %s not found", logPrefix, path) + logrus.Debugf("%s: skipping", logPrefix) + return nil + } + + var builder strings.Builder + builder.WriteString("# Written by Toolbx\n") + builder.WriteString("# https://containertoolbx.org/\n") + builder.WriteString("\n") + builder.WriteString("module: p11-kit-client.so\n") + + pkcs11ConfigString := builder.String() + pkcs11ConfigBytes := []byte(pkcs11ConfigString) + if err := renameio.WriteFile("/etc/pkcs11/modules/p11-kit-trust.module", + pkcs11ConfigBytes, + 0644); err != nil { + return fmt.Errorf("failed to configure PKCS #11 to read from the host: %w", err) + } + + return nil +} + func configureRPM() error { if !utils.PathExists("/usr/lib/rpm/macros.d") { return nil diff --git a/src/cmd/run.go b/src/cmd/run.go index 639e460..7094c3a 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -27,6 +27,7 @@ import ( "path/filepath" "strconv" "strings" + "syscall" "time" "github.com/containers/toolbox/pkg/nvidia" @@ -283,6 +284,11 @@ func runCommand(container string, cdiEnviron = append(cdiEnviron, cdiSpecForNvidia.ContainerEdits.Env...) } + p11KitServerEnviron, err := startP11KitServer() + if err != nil { + return err + } + startContainerTimestamp := time.Unix(-1, 0) if entryPointPID <= 0 { @@ -335,10 +341,11 @@ func runCommand(container string, logrus.Debugf("Container %s is initialized", container) + environ := append(cdiEnviron, p11KitServerEnviron...) if err := runCommandWithFallbacks(container, preserveFDs, command, - cdiEnviron, + environ, emitEscapeSequence, fallbackToBash); err != nil { return err @@ -1033,6 +1040,68 @@ func startContainer(container string) error { return nil } +func startP11KitServer() ([]string, error) { + serverSocket, err := utils.GetP11KitServerSocket(currentUser) + if err != nil { + return nil, err + } + + const logPrefix = "Starting 'p11-kit server'" + logrus.Debugf("%s with socket %s", logPrefix, serverSocket) + + serverSocketLock, err := utils.GetP11KitServerSocketLock(currentUser) + if err != nil { + return nil, err + } + + serverSocketLockFile, err := utils.Flock(serverSocketLock, syscall.LOCK_EX) + if err != nil { + logrus.Debugf("%s: %s", logPrefix, err) + + var errFlock *utils.FlockError + + if errors.As(err, &errFlock) { + if errors.Is(err, utils.ErrFlockAcquire) { + err = utils.ErrFlockAcquire + } else if errors.Is(err, utils.ErrFlockCreate) { + err = utils.ErrFlockCreate + } else { + panicMsg := fmt.Sprintf("unexpected %T: %s", err, err) + panic(panicMsg) + } + } + + return nil, err + } + + defer serverSocketLockFile.Close() + + serverSocketAddress := fmt.Sprintf("P11_KIT_SERVER_ADDRESS=unix:path=%s", serverSocket) + serverEnviron := []string{ + serverSocketAddress, + } + + if utils.PathExists(serverSocket) { + logrus.Debugf("%s: socket %s already exists", logPrefix, serverSocket) + logrus.Debugf("%s: skipping", logPrefix) + return serverEnviron, nil + } + + serverArgs := []string{ + "server", + "--name", serverSocket, + "--provider", "p11-kit-trust.so", + "pkcs11:model=p11-kit-trust?write-protected=yes", + } + + if err := shell.Run("p11-kit", nil, nil, nil, serverArgs...); err != nil { + logrus.Debugf("%s failed: %s", logPrefix, err) + return nil, nil + } + + return serverEnviron, nil +} + func (err *entryPointError) Error() string { return err.msg } diff --git a/src/pkg/utils/utils.go b/src/pkg/utils/utils.go index 7b46692..15cfc01 100644 --- a/src/pkg/utils/utils.go +++ b/src/pkg/utils/utils.go @@ -503,6 +503,26 @@ func GetMountOptions(target string) (string, error) { return mountOptions, nil } +func GetP11KitServerSocket(targetUser *user.User) (string, error) { + toolbxRuntimeDirectory, err := GetRuntimeDirectory(targetUser) + if err != nil { + return "", err + } + + p11KitServerSocket := filepath.Join(toolbxRuntimeDirectory, "pkcs11") + return p11KitServerSocket, nil +} + +func GetP11KitServerSocketLock(targetUser *user.User) (string, error) { + toolbxRuntimeDirectory, err := GetRuntimeDirectory(targetUser) + if err != nil { + return "", err + } + + p11KitServerSocketLock := filepath.Join(toolbxRuntimeDirectory, "pkcs11.lock") + return p11KitServerSocketLock, nil +} + func GetRuntimeDirectory(targetUser *user.User) (string, error) { if runtimeDirectories == nil { runtimeDirectories = make(map[string]string)