Skip to content

Commit 9f7af81

Browse files
Merge pull request #26718 from ninja-quokka/machine_init_tls_verify
Add support for configuring tls verification with machine init
2 parents f0ec320 + 67ec203 commit 9f7af81

File tree

10 files changed

+108
-34
lines changed

10 files changed

+108
-34
lines changed

cmd/podman/machine/init.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/containers/common/pkg/completion"
1111
"github.com/containers/common/pkg/strongunits"
12+
"github.com/containers/image/v5/types"
1213
"github.com/containers/podman/v5/cmd/podman/registry"
1314
ldefine "github.com/containers/podman/v5/libpod/define"
1415
"github.com/containers/podman/v5/libpod/events"
@@ -41,6 +42,7 @@ var (
4142
// Flags which have a meaning when unspecified that differs from the flag default
4243
type InitOptionalFlags struct {
4344
UserModeNetworking bool
45+
tlsVerify bool
4446
}
4547

4648
// maxMachineNameSize is set to thirty to limit huge machine names primarily
@@ -154,6 +156,9 @@ func init() {
154156
userModeNetFlagName := "user-mode-networking"
155157
flags.BoolVar(&initOptionalFlags.UserModeNetworking, userModeNetFlagName, false,
156158
"Whether this machine should use user-mode networking, routing traffic through a host user-space process")
159+
160+
flags.BoolVar(&initOptionalFlags.tlsVerify, "tls-verify", true,
161+
"Require HTTPS and verify certificates when contacting registries")
157162
}
158163

159164
func initMachine(cmd *cobra.Command, args []string) error {
@@ -219,6 +224,16 @@ func initMachine(cmd *cobra.Command, args []string) error {
219224
}
220225
}
221226

227+
// initOpts.SkipTlsVerify defaults to OptionalBoolUndefined, which means the backend library
228+
// decides whether to verify TLS. We only explicitly set it if the user specifies the
229+
// --tls-verify flag on the CLI.
230+
//
231+
// The flag value from initOptionalFlags.tlsVerify indicates whether TLS verification is desired.
232+
// Since we are converting tlsVerify -> SkipTlsVerify, we must invert the bool accordingly.
233+
if cmd.Flags().Changed("tls-verify") {
234+
initOpts.SkipTlsVerify = types.NewOptionalBool(!initOptionalFlags.tlsVerify)
235+
}
236+
222237
// TODO need to work this back in
223238
// if finished, err := vm.Init(initOpts); err != nil || !finished {
224239
// // Finished = true, err = nil - Success! Log a message with further instructions

docs/source/markdown/options/tls-verify.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
####> This option file is used in:
2-
####> podman artifact pull, artifact push, auto update, build, container runlabel, create, farm build, kube play, login, manifest add, manifest create, manifest inspect, manifest push, pull, push, run, search
2+
####> podman artifact pull, artifact push, auto update, build, container runlabel, create, farm build, kube play, login, machine init, manifest add, manifest create, manifest inspect, manifest push, pull, push, run, search
33
####> If file is edited, make sure the changes
44
####> are applicable to all of those.
55
#### **--tls-verify**

docs/source/markdown/podman-machine-init.1.md.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ means to use the timezone of the machine host.
119119
The timezone setting is not used with WSL. WSL automatically sets the timezone to the same
120120
as the host Windows operating system.
121121

122+
@@option tls-verify
123+
122124
#### **--usb**=*bus=number,devnum=number* or *vendor=hexadecimal,product=hexadecimal*
123125

124126
Assign a USB device from the host to the VM via USB passthrough.

pkg/machine/define/initopts.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package define
22

3-
import "net/url"
3+
import (
4+
"net/url"
5+
6+
"github.com/containers/image/v5/types"
7+
)
48

59
type InitOptions struct {
610
PlaybookPath string
@@ -21,4 +25,5 @@ type InitOptions struct {
2125
UID string // uid of the user that called machine
2226
UserModeNetworking *bool // nil = use backend/system default, false = disable, true = enable
2327
USBs []string
28+
SkipTlsVerify types.OptionalBool
2429
}

pkg/machine/e2e/basic_test.go

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -288,18 +288,39 @@ var _ = Describe("run basic podman commands", func() {
288288

289289
It("CVE-2025-6032 regression test - HTTP", func() {
290290
// ensure that trying to pull from a local HTTP server fails and the connection will be rejected
291-
testImagePullTLS(nil)
291+
// ensure that tlsVerify is true by default
292+
testImagePullTLS(nil, nil)
292293
})
293294

294295
It("CVE-2025-6032 regression test - HTTPS unknown cert", func() {
295-
// ensure that trying to pull from an local HTTPS server with invalid certs fails and the connection will be rejected
296+
// ensure that trying to pull from a local HTTPS server with invalid certs fails and the connection will be rejected
297+
// ensure that tlsVerify is true by default
296298
testImagePullTLS(&TLSConfig{
297299
// Key/Cert was generated with:
298300
// openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 3650 \
299301
// -nodes -keyout test-tls.key -out test-tls.crt -subj "/CN=test.podman.io" -addext "subjectAltName=IP:127.0.0.1"
300302
key: "test-tls.key",
301303
cert: "test-tls.crt",
302-
})
304+
}, nil)
305+
})
306+
307+
It("machine init should not fail on TLS validation with --tls-verfy=false - HTTP", func() {
308+
// ensure that trying to pull from a local HTTP server doesn't fail when --tls-verify=false is set
309+
tlsVerify := false
310+
testImagePullTLS(nil, &tlsVerify)
311+
})
312+
313+
It("machine init should not fail on TLS validation with --tls-verfy=false - HTTPS", func() {
314+
// ensure that trying to pull from a local HTTPS server with invalid certs
315+
// doesn't fail due to tls validation when --tls-verify=false is set
316+
tlsVerify := false
317+
testImagePullTLS(&TLSConfig{
318+
// Key/Cert was generated with:
319+
// openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 3650 \
320+
// -nodes -keyout test-tls.key -out test-tls.crt -subj "/CN=test.podman.io" -addext "subjectAltName=IP:127.0.0.1"
321+
key: "test-tls.key",
322+
cert: "test-tls.crt",
323+
}, &tlsVerify)
303324
})
304325
})
305326

@@ -339,7 +360,7 @@ type TLSConfig struct {
339360

340361
// setup a local webserver in the test and then point podman machine init to it
341362
// to verify the connection details.
342-
func testImagePullTLS(tls *TLSConfig) {
363+
func testImagePullTLS(tls *TLSConfig, tlsVerify *bool) {
343364
listener, err := net.Listen("tcp4", "127.0.0.1:0")
344365
Expect(err).ToNot(HaveOccurred())
345366
serverAddr := listener.Addr().String()
@@ -367,17 +388,29 @@ func testImagePullTLS(tls *TLSConfig) {
367388
}
368389
}()
369390

370-
name := randomString()
371391
i := new(initMachine)
372-
session, err := mb.setName(name).setCmd(i.withImage("docker://" + serverAddr + "/testimage")).run()
392+
393+
i.withImage("docker://" + serverAddr + "/testimage")
394+
395+
if tlsVerify != nil {
396+
i.withTlsVerify(tlsVerify)
397+
}
398+
399+
name := randomString()
400+
session, err := mb.setName(name).setCmd(i).run()
401+
373402
Expect(err).ToNot(HaveOccurred())
374403
Expect(session).To(Exit(125))
375404

376405
// Note because we don't run a real registry the error you get when TLS is not checked is:
377406
// Error: wrong manifest type for disk artifact: text/plain
378407
// As such we match the errors strings exactly to ensure we have proper error messages that indicate the TLS error.
379408
expectedErr := "Error: pinging container registry " + serverAddr + ": Get \"https://" + serverAddr + "/v2/\": "
380-
if tls != nil {
409+
410+
switch {
411+
case tlsVerify != nil && *tlsVerify == false: // tls-verify explicitly disabled
412+
expectedErr = "Error: wrong manifest type for disk artifact: text/plain\n"
413+
case tls != nil:
381414
expectedErr += "tls: failed to verify certificate: x509: "
382415
if runtime.GOOS == "darwin" {
383416
// Apple doesn't like such long valid certs so the error is different but the purpose
@@ -387,13 +420,18 @@ func testImagePullTLS(tls *TLSConfig) {
387420
} else {
388421
expectedErr += "certificate signed by unknown authority\n"
389422
}
390-
} else {
423+
default:
424+
// With both tlsVerify and tls being nil, a HTTP server will be ran and machine init should
425+
// default to using tlsVerify
391426
expectedErr += "http: server gave HTTP response to HTTPS client\n"
392427
}
428+
393429
Expect(session.errorToString()).To(Equal(expectedErr))
394430

395431
// if the client enforces TLS verification then we should not have received any request
396-
Expect(loggedRequests).To(BeEmpty(), "the server should have not process any request from the client")
432+
if tlsVerify == nil || *tlsVerify == true {
433+
Expect(loggedRequests).To(BeEmpty(), "the server should have not process any request from the client")
434+
}
397435

398436
srv.Close()
399437
Expect(<-serverErr).To(Equal(http.ErrServerClosed))

pkg/machine/e2e/config_init_test.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ import (
1111

1212
type initMachine struct {
1313
/*
14-
--cpus uint Number of CPUs (default 1)
15-
--disk-size uint Disk size in GiB (default 100)
16-
--ignition-path string Path to ignition file
17-
--username string Username of the remote user (default "core" for FCOS, "user" for Fedora)
18-
--image-path string Path to bootable image (default "testing")
19-
-m, --memory uint Memory in MiB (default 2048)
20-
--now Start machine now
21-
--rootful Whether this machine should prefer rootful container execution
22-
--playbook string Run an ansible playbook after first boot
23-
--timezone string Set timezone (default "local")
24-
-v, --volume stringArray Volumes to mount, source:target
25-
--volume-driver string Optional volume driver
26-
14+
--cpus uint Number of CPUs (default 1)
15+
--disk-size uint Disk size in GiB (default 100)
16+
--ignition-path string Path to ignition file
17+
--username string Username of the remote user (default "core" for FCOS, "user" for Fedora)
18+
--image-path string Path to bootable image (default "testing")
19+
-m, --memory uint Memory in MiB (default 2048)
20+
--now Start machine now
21+
--rootful Whether this machine should prefer rootful container execution
22+
--playbook string Run an ansible playbook after first boot
23+
--tls-verify Require HTTPS and verify certificates when contacting registries
24+
--timezone string Set timezone (default "local")
25+
-v, --volume stringArray Volumes to mount, source:target
26+
--volume-driver string Optional volume driver
2727
*/
2828
playbook string
2929
cpus *uint
@@ -38,6 +38,7 @@ type initMachine struct {
3838
rootful bool
3939
volumes []string
4040
userModeNetworking bool
41+
tlsVerify *bool
4142

4243
cmd []string
4344
}
@@ -85,6 +86,9 @@ func (i *initMachine) buildCmd(m *machineTestBuilder) []string {
8586
if i.swap != nil {
8687
cmd = append(cmd, "--swap", strconv.Itoa(int(*i.swap)))
8788
}
89+
if i.tlsVerify != nil {
90+
cmd = append(cmd, "--tls-verify="+strconv.FormatBool(*i.tlsVerify))
91+
}
8892
name := m.name
8993
cmd = append(cmd, name)
9094

@@ -172,6 +176,11 @@ func (i *initMachine) withRunPlaybook(p string) *initMachine {
172176
return i
173177
}
174178

179+
func (i *initMachine) withTlsVerify(tlsVerify *bool) *initMachine {
180+
i.tlsVerify = tlsVerify
181+
return i
182+
}
183+
175184
func (i *initMachine) withUserModeNetworking(r bool) *initMachine { //nolint:unused,nolintlint
176185
i.userModeNetworking = r
177186
return i

pkg/machine/e2e/machine_pull_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"runtime"
88
"strings"
99

10+
"github.com/containers/image/v5/types"
1011
"github.com/containers/podman/v5/pkg/machine/compression"
1112
"github.com/containers/podman/v5/pkg/machine/define"
1213
"github.com/containers/podman/v5/pkg/machine/ocipull"
@@ -22,7 +23,9 @@ func pullOCITestDisk(finalDir string, vmType define.VMType) error {
2223
return err
2324
}
2425
dirs := define.MachineDirs{ImageCacheDir: imageCacheDir}
25-
ociArtPull, err := ocipull.NewOCIArtifactPull(context.Background(), &dirs, "", "e2emachine", vmType, unusedFinalPath)
26+
27+
var skipTlsVerify types.OptionalBool
28+
ociArtPull, err := ocipull.NewOCIArtifactPull(context.Background(), &dirs, "", "e2emachine", vmType, unusedFinalPath, skipTlsVerify)
2629
if err != nil {
2730
return err
2831
}

pkg/machine/ocipull/ociartifact.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,8 @@ type DiskArtifactOpts struct {
7171
7272
*/
7373

74-
func NewOCIArtifactPull(ctx context.Context, dirs *define.MachineDirs, endpoint string, vmName string, vmType define.VMType, finalPath *define.VMFile) (*OCIArtifactDisk, error) {
75-
var (
76-
arch string
77-
)
74+
func NewOCIArtifactPull(ctx context.Context, dirs *define.MachineDirs, endpoint string, vmName string, vmType define.VMType, finalPath *define.VMFile, skipTlsVerify types.OptionalBool) (*OCIArtifactDisk, error) {
75+
var arch string
7876

7977
artifactVersion := getVersion()
8078
switch runtime.GOARCH {
@@ -108,8 +106,10 @@ func NewOCIArtifactPull(ctx context.Context, dirs *define.MachineDirs, endpoint
108106
imageEndpoint: endpoint,
109107
machineVersion: artifactVersion,
110108
name: vmName,
111-
pullOptions: &PullOptions{},
112-
vmType: vmType,
109+
pullOptions: &PullOptions{
110+
SkipTLSVerify: skipTlsVerify,
111+
},
112+
vmType: vmType,
113113
}
114114
return &ociDisk, nil
115115
}

pkg/machine/shim/diskpull/diskpull.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@ import (
44
"context"
55
"strings"
66

7+
"github.com/containers/image/v5/types"
78
"github.com/containers/podman/v5/pkg/machine/define"
89
"github.com/containers/podman/v5/pkg/machine/ocipull"
910
"github.com/containers/podman/v5/pkg/machine/stdpull"
1011
)
1112

12-
func GetDisk(userInputPath string, dirs *define.MachineDirs, imagePath *define.VMFile, vmType define.VMType, name string) error {
13+
func GetDisk(userInputPath string, dirs *define.MachineDirs, imagePath *define.VMFile, vmType define.VMType, name string, skipTlsVerify types.OptionalBool) error {
1314
var (
1415
err error
1516
mydisk ocipull.Disker
1617
)
1718

1819
if userInputPath == "" || strings.HasPrefix(userInputPath, "docker://") {
19-
mydisk, err = ocipull.NewOCIArtifactPull(context.Background(), dirs, userInputPath, name, vmType, imagePath)
20+
mydisk, err = ocipull.NewOCIArtifactPull(context.Background(), dirs, userInputPath, name, vmType, imagePath, skipTlsVerify)
2021
} else {
2122
if strings.HasPrefix(userInputPath, "http") {
2223
// TODO probably should use tempdir instead of datadir
@@ -28,5 +29,6 @@ func GetDisk(userInputPath string, dirs *define.MachineDirs, imagePath *define.V
2829
if err != nil {
2930
return err
3031
}
32+
3133
return mydisk.Get()
3234
}

pkg/machine/shim/host.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) error {
172172
// "/path
173173
// "docker://quay.io/something/someManifest
174174

175-
if err := diskpull.GetDisk(opts.Image, dirs, mc.ImagePath, mp.VMType(), mc.Name); err != nil {
175+
if err := diskpull.GetDisk(opts.Image, dirs, mc.ImagePath, mp.VMType(), mc.Name, opts.SkipTlsVerify); err != nil {
176176
return err
177177
}
178178

0 commit comments

Comments
 (0)