mirror of
https://github.com/containers/podman.git
synced 2026-03-13 08:01:19 +08:00
PARTIALLY TESTED: Add --tls-details, use it to affect libimage and the like
For remote operation, start the remote service with --tls-details:
using --tls-details on the client side will only affect client's
connection.
This should eventually include many more tests - track down all current
uses of libpod.Runtime.{SystemContext,imageContext,LibimageRuntime}.
That will come later
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
@@ -66,6 +66,10 @@ func (p *PodmanTestIntegration) StartRemoteService() {
|
||||
if _, found := os.LookupEnv("DEBUG_SERVICE"); found {
|
||||
args = append(args, "--log-level", "trace")
|
||||
}
|
||||
if p.RemoteTLSDetails != "" {
|
||||
args = append(args, "--tls-details", p.RemoteTLSDetails)
|
||||
}
|
||||
|
||||
remoteSocket := p.RemoteSocket
|
||||
args = append(args, "system", "service", "--time", "0")
|
||||
|
||||
|
||||
1
test/e2e/testdata/tls-details-1.3.yaml
vendored
Normal file
1
test/e2e/testdata/tls-details-1.3.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
minVersion: "1.3"
|
||||
1
test/e2e/testdata/tls-details-anything.yaml
vendored
Normal file
1
test/e2e/testdata/tls-details-anything.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{} # No fields
|
||||
3
test/e2e/testdata/tls-details-pqc-only.yaml
vendored
Normal file
3
test/e2e/testdata/tls-details-pqc-only.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
minVersion: "1.3"
|
||||
namedGroups:
|
||||
- "X25519MLKEM768"
|
||||
244
test/e2e/tls_test.go
Normal file
244
test/e2e/tls_test.go
Normal file
@@ -0,0 +1,244 @@
|
||||
//go:build linux || freebsd
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/pem"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/containers/podman/v6/test/utils"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
// tlsConfigServer returns http.StatusTeapot. So if we see that, that indicates a successful TLS connection.
|
||||
// But we need to special-case that in podmanFailTLSDetailsWithCAKnowledge.
|
||||
const teapotRegex = `\b418\b`
|
||||
|
||||
var _ = Describe("--tls-details", func() {
|
||||
var (
|
||||
defaultServer *tlsConfigServer
|
||||
tls12Server *tlsConfigServer
|
||||
nonPQCserver *tlsConfigServer
|
||||
pqcServer *tlsConfigServer
|
||||
expected []expectedBehavior
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
defaultServer = newServer(&tls.Config{})
|
||||
tls12Server = newServer(&tls.Config{
|
||||
MaxVersion: tls.VersionTLS12,
|
||||
})
|
||||
nonPQCserver = newServer(&tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521},
|
||||
})
|
||||
pqcServer = newServer(&tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
CurvePreferences: []tls.CurveID{tls.X25519MLKEM768},
|
||||
})
|
||||
|
||||
expected = []expectedBehavior{
|
||||
{
|
||||
server: defaultServer,
|
||||
tlsDetails: "testdata/tls-details-anything.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: tls12Server,
|
||||
tlsDetails: "testdata/tls-details-anything.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: nonPQCserver,
|
||||
tlsDetails: "testdata/tls-details-anything.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: pqcServer,
|
||||
tlsDetails: "testdata/tls-details-anything.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
|
||||
{
|
||||
server: defaultServer,
|
||||
tlsDetails: "testdata/tls-details-1.3.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: tls12Server,
|
||||
tlsDetails: "testdata/tls-details-1.3.yaml",
|
||||
expected: `protocol version not supported`,
|
||||
},
|
||||
{
|
||||
server: nonPQCserver,
|
||||
tlsDetails: "testdata/tls-details-1.3.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: pqcServer,
|
||||
tlsDetails: "testdata/tls-details-1.3.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
|
||||
{
|
||||
server: defaultServer,
|
||||
tlsDetails: "testdata/tls-details-pqc-only.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
{
|
||||
server: tls12Server,
|
||||
tlsDetails: "testdata/tls-details-pqc-only.yaml",
|
||||
expected: `protocol version not supported`,
|
||||
},
|
||||
{
|
||||
server: nonPQCserver,
|
||||
tlsDetails: "testdata/tls-details-pqc-only.yaml",
|
||||
expected: `handshake failure`,
|
||||
},
|
||||
{
|
||||
server: pqcServer,
|
||||
tlsDetails: "testdata/tls-details-pqc-only.yaml",
|
||||
expected: teapotRegex,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// FIXME: this should contain many more tests to exercise libimage.Runtime.{SystemContext,imageContext,LibimageRuntime}.
|
||||
|
||||
It("podman --tls-details pull", func() {
|
||||
caDir := GinkgoT().TempDir()
|
||||
caPath := filepath.Join(caDir, "ca.crt")
|
||||
|
||||
for _, e := range expected {
|
||||
err := os.WriteFile(caPath, e.server.certBytes, 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// --cert-dir is not available in the remote client.
|
||||
if !IsRemote() {
|
||||
podmanFailTLSDetails(&e, "pull", "--cert-dir", caDir, "docker://"+e.server.hostPort+"/repo")
|
||||
} else {
|
||||
podmanFailTLSDetailsNoCA(&e, "pull", "docker://"+e.server.hostPort+"/repo")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
It("podman --tls-details push", func() {
|
||||
podmanTest.AddImageToRWStore(ALPINE)
|
||||
|
||||
caDir := GinkgoT().TempDir()
|
||||
caPath := filepath.Join(caDir, "ca.crt")
|
||||
|
||||
for _, e := range expected {
|
||||
err := os.WriteFile(caPath, e.server.certBytes, 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
podmanFailTLSDetails(&e, "push", "--cert-dir", caDir, ALPINE, "docker://"+e.server.hostPort+"/repo")
|
||||
}
|
||||
})
|
||||
|
||||
It("podman --tls-details run", func() {
|
||||
caDir := GinkgoT().TempDir()
|
||||
caPath := filepath.Join(caDir, "ca.crt")
|
||||
|
||||
for _, e := range expected {
|
||||
err := os.WriteFile(caPath, e.server.certBytes, 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// --cert-dir is not available in the remote client.
|
||||
if !IsRemote() {
|
||||
podmanFailTLSDetails(&e, "run", "--cert-dir", caDir, "--rm", "docker://"+e.server.hostPort+"/repo", "true")
|
||||
} else {
|
||||
podmanFailTLSDetailsNoCA(&e, "run", "--rm", "docker://"+e.server.hostPort+"/repo", "true")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
type expectedBehavior struct {
|
||||
server *tlsConfigServer
|
||||
tlsDetails string
|
||||
expected string
|
||||
}
|
||||
|
||||
// tlsConfigServer serves TLS with a specific configuration.
|
||||
// It returns StatusTeapot on all requests; we use that to detect that the TLS negotiation succeeded,
|
||||
// without bothering to actually implement any of the protocols.
|
||||
type tlsConfigServer struct {
|
||||
server *httptest.Server
|
||||
hostPort string
|
||||
certBytes []byte
|
||||
certPath string
|
||||
}
|
||||
|
||||
func newServer(config *tls.Config) *tlsConfigServer {
|
||||
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusTeapot)
|
||||
}))
|
||||
DeferCleanup(server.Close)
|
||||
|
||||
server.TLS = config.Clone()
|
||||
server.StartTLS()
|
||||
|
||||
certBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: server.Certificate().Raw,
|
||||
})
|
||||
certDir := GinkgoT().TempDir()
|
||||
certPath := filepath.Join(certDir, "cert.pem")
|
||||
err := os.WriteFile(certPath, certBytes, 0o644)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
return &tlsConfigServer{
|
||||
server: server,
|
||||
hostPort: server.Listener.Addr().String(),
|
||||
certBytes: certBytes,
|
||||
certPath: certPath,
|
||||
}
|
||||
}
|
||||
|
||||
// podmanFailTLSDetails runs a podman command with args, setting up --tls-details from e,
|
||||
// and asserting an expected error.
|
||||
func podmanFailTLSDetails(e *expectedBehavior, args ...string) {
|
||||
GinkgoHelper()
|
||||
podmanFailTLSDetailsWithCAKnowledge(e, true, args...)
|
||||
}
|
||||
|
||||
// podmanFailTLSDetailsNoCA runs a podman command with args, setting up --tls-details from e,
|
||||
// and asserting an expected error (assuming that the command does not trust the server’s CA).
|
||||
func podmanFailTLSDetailsNoCA(e *expectedBehavior, args ...string) {
|
||||
GinkgoHelper()
|
||||
podmanFailTLSDetailsWithCAKnowledge(e, false, args...)
|
||||
}
|
||||
|
||||
// podmanFailTLSDetailsWithCAKnowledge runs a podman command with args, setting up --tls-details from e,
|
||||
// and asserting an expected error.
|
||||
// knownCA indicates whether the client trusts the server’s CA.
|
||||
func podmanFailTLSDetailsWithCAKnowledge(e *expectedBehavior, knownCA bool, args ...string) {
|
||||
GinkgoHelper()
|
||||
session := podmanTLSDetailsSessionWithOptions(e, PodmanExecOptions{}, args...)
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
// Frequently, we don’t expose trusted CA configuration for individual operations,
|
||||
// especially in the remote CLI. Checking for a successful HTTP connection is better,
|
||||
// but if we get far enough to be worrying about certificates,
|
||||
// we already negotiated the TLS version and named group.
|
||||
expected := e.expected
|
||||
if expected == teapotRegex && (IsRemote() || !knownCA) {
|
||||
expected = `certificate signed by unknown authority`
|
||||
}
|
||||
Expect(session).Should(ExitWithErrorRegex(125, expected))
|
||||
}
|
||||
|
||||
// podmanTLSDetailsSessionWithOptions creates a PodmanSessionIntegration with e.tlsDetails.
|
||||
func podmanTLSDetailsSessionWithOptions(e *expectedBehavior, options PodmanExecOptions, args ...string) *PodmanSessionIntegration {
|
||||
GinkgoHelper()
|
||||
if !IsRemote() {
|
||||
args = append([]string{"--tls-details", e.tlsDetails}, args...)
|
||||
} else {
|
||||
podmanTest.RemoteTLSDetails = e.tlsDetails
|
||||
podmanTest.RestartRemoteService()
|
||||
}
|
||||
return podmanTest.PodmanWithOptions(options, args...)
|
||||
}
|
||||
@@ -65,6 +65,7 @@ type PodmanTest struct {
|
||||
RemoteTLSServerCAPool *x509.CertPool
|
||||
RemoteTLSClientCertFile string
|
||||
RemoteTLSClientKeyFile string
|
||||
RemoteTLSDetails string
|
||||
RemoteTest bool
|
||||
TempDir string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user