Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:SSL for postgres #2473

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
daa8cf2
SSL for postgres
Apr 8, 2024
53e2135
Add entrypoint wrapper
Apr 8, 2024
bd3360d
Add in init so we can test ssl+init path
Apr 8, 2024
c3fd69b
Remove unused fields from options
Apr 8, 2024
445a575
Remove unused consts
Apr 8, 2024
8814e8c
Separate entrypoint from ssl
Apr 9, 2024
2aecc1b
Use external cert generation
Apr 11, 2024
eac665d
Make entrypoint not-optional
Apr 12, 2024
302472c
Add docstring
Apr 12, 2024
3099790
Spaces to tab in entrypoint
Apr 24, 2024
e067d0f
Add postgres ssl docs
Apr 24, 2024
2c7f621
Remove WithEntrypoint
Apr 24, 2024
b9cd59b
Update docs/modules/postgres.md
bearrito Apr 24, 2024
ef017c9
Update docs/modules/postgres.md
bearrito Apr 24, 2024
fd3d3e5
Update docs/modules/postgres.md
bearrito Apr 24, 2024
cd1b63f
Update modules/postgres/postgres_test.go
bearrito Apr 24, 2024
c7eebeb
Update modules/postgres/postgres_test.go
bearrito Apr 24, 2024
a36eafa
Embed resources + Use custom conf automatically
Apr 24, 2024
7ea323a
Update docs/modules/postgres.md
bearrito Apr 26, 2024
0557c9d
Update docs/modules/postgres.md
bearrito Apr 26, 2024
5d0fa1e
Update docs/modules/postgres.md
bearrito Apr 26, 2024
7805e1f
Update modules/postgres/postgres_test.go
bearrito Apr 26, 2024
c80fa83
Update modules/postgres/postgres_test.go
bearrito Apr 26, 2024
e73f9a5
Update modules/postgres/postgres_test.go
bearrito Apr 26, 2024
1be6a31
Update modules/postgres/postgres_test.go
bearrito Apr 26, 2024
4e6c6d7
Revert to use passed in conf
Apr 26, 2024
e28361a
Update doc for required conf
Apr 26, 2024
8502649
Merge branch 'main' into feature/postgres-ssl
bearrito Apr 26, 2024
5d8598f
Error checking in the customizer
Apr 26, 2024
dffe996
Few formatting fix
Apr 26, 2024
53d9a1a
Use non-nil error when err is nil
Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions modules/postgres/options.go
@@ -0,0 +1,25 @@
package postgres

type SSLVerificationMode string

const (
SSLVerificationModeNone SSLVerificationMode = "disable"
SSLVerificationModeRequire SSLVerificationMode = "require"
)

type SSLSettings struct {
// Path to the CA certificate file
CACertFile string
// Path to the client certificate file
CertFile string
// Path to the key file
KeyFile string
//
Entrypoint string
// Verification mode
VerificationMode SSLVerificationMode
// Fail if no certificate is provided
FailIfNoCert bool
// Depth of certificate chain verification
VerificationDepth int
}
42 changes: 40 additions & 2 deletions modules/postgres/postgres.go
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

const (
Expand All @@ -26,10 +27,9 @@ type PostgresContainer struct {
snapshotName string
}


// MustConnectionString panics if the address cannot be determined.
func (c *PostgresContainer) MustConnectionString(ctx context.Context, args ...string) string {
addr, err := c.ConnectionString(ctx,args...)
addr, err := c.ConnectionString(ctx, args...)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -170,6 +170,44 @@ func WithSnapshotName(name string) SnapshotOption {
}
}

func WithSSLSettings(sslSettings SSLSettings) testcontainers.CustomizeRequestOption {
mdelapenya marked this conversation as resolved.
Show resolved Hide resolved
const postgresCaCertPath = "/tmp/data/ca_cert.pem"
const postgresCertPath = "/tmp/data/server.cert"
const postgresKeyPath = "/tmp/data/server.key"
const entrypointPath = "/usr/local/bin/docker-entrypoint-ssl.bash"

const defaultPermission = 0o600

return func(req *testcontainers.GenericContainerRequest) {
bearrito marked this conversation as resolved.
Show resolved Hide resolved
req.Files = append(req.Files, testcontainers.ContainerFile{
HostFilePath: sslSettings.CACertFile,
ContainerFilePath: postgresCaCertPath,
FileMode: defaultPermission,
})
req.Files = append(req.Files, testcontainers.ContainerFile{
HostFilePath: sslSettings.CertFile,
ContainerFilePath: postgresCertPath,
FileMode: defaultPermission,
})
req.Files = append(req.Files, testcontainers.ContainerFile{
HostFilePath: sslSettings.KeyFile,
ContainerFilePath: postgresKeyPath,
FileMode: defaultPermission,
})
req.Files = append(req.Files, testcontainers.ContainerFile{
HostFilePath: sslSettings.Entrypoint,
ContainerFilePath: entrypointPath,
FileMode: 0o666,
})

req.Entrypoint = []string{"sh", "/usr/local/bin/docker-entrypoint-ssl.bash"}
bearrito marked this conversation as resolved.
Show resolved Hide resolved

// TODO: Can we detect TLS by port. I don't think so...
// Probably use logs
req.WaitingFor = wait.ForAll(req.WaitingFor, wait.ForLog("database system is ready to accept connections"))
}
}

// Snapshot takes a snapshot of the current state of the database as a template, which can then be restored using
// the Restore method. By default, the snapshot will be created under a database called migrated_template, you can
// customize the snapshot name with the options.
Expand Down
54 changes: 50 additions & 4 deletions modules/postgres/postgres_test.go
Expand Up @@ -87,12 +87,12 @@ func TestPostgres(t *testing.T) {
connStr, err := container.ConnectionString(ctx, "sslmode=disable", "application_name=test")
// }
require.NoError(t, err)
mustConnStr := container.MustConnectionString(ctx,"sslmode=disable", "application_name=test")
if mustConnStr!=connStr{

mustConnStr := container.MustConnectionString(ctx, "sslmode=disable", "application_name=test")
if mustConnStr != connStr {
t.Errorf("ConnectionString was not equal to MustConnectionString")
}

// Ensure connection string is using generic format
id, err := container.MappedPort(ctx, "5432/tcp")
require.NoError(t, err)
Expand Down Expand Up @@ -188,6 +188,52 @@ func TestWithConfigFile(t *testing.T) {
defer db.Close()
}

func TestWithSSLEnabledConfigFile(t *testing.T) {
ctx := context.Background()

sslSettings := postgres.SSLSettings{
CACertFile: filepath.Join("testdata", "certs", "server_ca.pem"),
CertFile: filepath.Join("testdata", "certs", "server_cert.pem"),
KeyFile: filepath.Join("testdata", "certs", "server_key.pem"),
Entrypoint: filepath.Join("testdata", "docker-entrypoint-ssl.bash"),
VerificationMode: postgres.SSLVerificationModeRequire,
FailIfNoCert: true,
VerificationDepth: 1,
}

container, err := postgres.RunContainer(ctx,
postgres.WithConfigFile(filepath.Join("testdata", "my-postgres-ssl.conf")),
bearrito marked this conversation as resolved.
Show resolved Hide resolved
postgres.WithInitScripts(filepath.Join("testdata", "init-user-db.sh")),
postgres.WithDatabase(dbname),
postgres.WithUsername(user),
postgres.WithPassword(password),
testcontainers.WithWaitStrategy(wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5*time.Second)),
postgres.WithSSLSettings(sslSettings),
bearrito marked this conversation as resolved.
Show resolved Hide resolved
)
if err != nil {
t.Fatal(err)
}

t.Cleanup(func() {
if err := container.Terminate(ctx); err != nil {
t.Fatalf("failed to terminate container: %s", err)
}
})

// explicitly set sslmode=disable because the container is not configured to use TLS
bearrito marked this conversation as resolved.
Show resolved Hide resolved
connStr, err := container.ConnectionString(ctx, "sslmode=require")
require.NoError(t, err)

db, err := sql.Open("postgres", connStr)
require.NoError(t, err)
assert.NotNil(t, db)
defer db.Close()

result, err := db.Exec("SELECT * FROM testdb;")
require.NoError(t, err)
assert.NotNil(t, result)
}

func TestWithInitScript(t *testing.T) {
ctx := context.Background()

Expand Down
20 changes: 20 additions & 0 deletions modules/postgres/testdata/certs/server_ca.pem
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDRzCCAi+gAwIBAgIJAJJIMzvZuRzlMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNV
BAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMCAXDTE5
MDUwMjA3MjI0OVoYDzIxMTkwNDA4MDcyMjQ5WjAxMSAwHgYDVQQDDBdUTFNHZW5T
ZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAKko8FmfzrLHyZckvdR1oiSZf80m0t66TMqtLat1Oxjh
CjsxvswwJ/m2I5dM48hwZ+0b2ufkvaudLPq/8jDGyONVfjMGlbe1YlmQMDC7YWdI
XM1nCWAZIKaOHwIkfswuVBAdBVYV4Polu6wjVt5edEpl/IWEpPicXjLOY1Fw3q67
5tP2Mmo6TJg5YqgB4fH4SmajtP3j+H4puQ8ZPIs26mInEgfCyrMWey/oQX8qqMph
pKMEJYE7DHawriFraOooJadJYojbY5H27nmJe8yXURb3wSQSaKnFZL25cmVm2kue
/lw+n+a2wLdHdU4cmghCURalhcXUNZe7UbdRZ9e9r2cCAwEAAaNgMF4wCwYDVR0P
BAQDAgEGMB0GA1UdDgQWBBSZiNur/XHsqSfdWnB1NPi/ql5+tzAfBgNVHSMEGDAW
gBSZiNur/XHsqSfdWnB1NPi/ql5+tzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQAar/db/T7izD4pyh2titl7Dkgp2iTditfgqRlU0yVGiiB6rLmY
sYE2QAuFhgqyRLPcjVV8F39iRJHQ17SGT8e2iAaUTnbQj0AiskKjonF9+quKuVbr
TpYHk+guS0Jn2rU6HK8WQeYZOh3WdLTu4ArXkxywgwVssQQ9JmpTd9YEYePWfs7i
WZB6AQyL9CD3z1j4i1G4ft6pB1Ps5XjznqMZ2//7AUpoRTrettWqorPWwudQ9yna
B4S6KtvpnxUQSeHJW6Q4NvTrOsvHEOCa6OtwYbWmLf+qbpPb8oHt9UF3ze2PJopB
QzsQop1+gPudG0DX0SgyuQT+SsFjYlDazZdZ
-----END CERTIFICATE-----
21 changes: 21 additions & 0 deletions modules/postgres/testdata/certs/server_cert.pem
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDajCCAlKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAxMSAwHgYDVQQDDBdUTFNH
ZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDAgFw0xOTA1MDIwNzIy
NDlaGA8yMTE5MDQwODA3MjI0OVowIzEQMA4GA1UEAwwHQzY1U1RUMjEPMA0GA1UE
CgwGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0QXKtb
KVeEuCmZGcZAlAlTBC8E/G3UuX6qKwTR1xEOvUWeBH1n0WeXXGd/p/y6P4lRBeWN
BZ9KcvIlNDeDMy05NfxnO1vnJk9E8/0xwMiY1LJdMHzIzhmrrqXo0u3DT8MmoNR6
7CTcnG21gi1GrjW8a747yFF0xfukEc6FkyVqLsjtCkHPwrc/sBHVS3aivNWGkJzA
eBXBdWJAg3ZC6T9U+Y8cndWQrpYMJvek1IewlyDSspHZDFmM1OwVwypnMt4fGgaX
5IlUMnNgKmisOSuI529rxLF+mvYIQLRl5bP+1/c9JD5MZ5krA3SrjdwRFS3sQXC3
nuHqJofFXNkbXQIDAQABo4GYMIGVMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMG
A1UdJQQMMAoGCCsGAQUFBwMBMCYGA1UdEQQfMB2CB0M2NVNUVDKCB0M2NVNUVDKC
CWxvY2FsaG9zdDAdBgNVHQ4EFgQURq22sa46tA0SGHhEm9jxGP9aDrswHwYDVR0j
BBgwFoAUmYjbq/1x7Kkn3VpwdTT4v6pefrcwDQYJKoZIhvcNAQELBQADggEBAKUP
7RgmJyMVoHxg46F1fjWVhlF4BbQuEtB8mC+4G4e68lDU/TPAbmB3aj91oQDgBiTd
R2O7U6tyitxxrU2r7rFAHGhFHeyCQ3yZMwydO2V3Nm2Ywzdyk8er4yghjg9FS8tH
egDGDDod3l1yrAbHHuXmzDjnAFwHwRkm5cYUz00/IuZ3sQZ70XofL3KXNj1tAtfK
PSpdSAxSTO99ofjVKjlyywQSZKNbXfqD5DGz8e0rmqPfZ+3zi75E5nEuJ3UI2wXg
LuI4j6FIzNQyei/FdSynktcIm+hefQEyex4cho4C8RYB2S5S8RWrnP9jOzsaQFHn
bHXf7dKwRfA6/u8JmtQ=
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions modules/postgres/testdata/certs/server_key.pem
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqR0QXKtbKVeEuCmZGcZAlAlTBC8E/G3UuX6qKwTR1xEOvUWe
BH1n0WeXXGd/p/y6P4lRBeWNBZ9KcvIlNDeDMy05NfxnO1vnJk9E8/0xwMiY1LJd
MHzIzhmrrqXo0u3DT8MmoNR67CTcnG21gi1GrjW8a747yFF0xfukEc6FkyVqLsjt
CkHPwrc/sBHVS3aivNWGkJzAeBXBdWJAg3ZC6T9U+Y8cndWQrpYMJvek1IewlyDS
spHZDFmM1OwVwypnMt4fGgaX5IlUMnNgKmisOSuI529rxLF+mvYIQLRl5bP+1/c9
JD5MZ5krA3SrjdwRFS3sQXC3nuHqJofFXNkbXQIDAQABAoIBAA0dxvYZCEIFmrKZ
71jzanDQ5FJvvyhA8H3OmC4r+oZ+uTDu5FmezF2OdkvhbyI9VMi2wsT9T9m+yAxw
QXhyUce3WzeXsv4Em8H55fQykBhOtqPQja/EDeMGVK2ACrXJYRufnDBfKoWEOmQb
kjddgZzjaBDHOWXJA5CTet8ysGOAJBTxyzU69k5Vj9B5abG9CofNzGOFF+Uleff5
ip3sz7JpDXCex3oEs98veco6+8i/MZNo3BnwB5J+P+2MFFKONfPwuNyKAWBza2/X
66Lk3xXBjLJJ+Ww16jkqueTXEq6GCFXavNfdL9aonth5V5YYR/cj+2u2LM1oj9cJ
bp0xbvUCgYEA2Svq1DyR9cfTwrbc/0J2JfrjavClzDYU2oeO2fSU85WEEjJguaja
17Vdo/UsJtiUiSq4UhI1n0haaIpTBCeF2tHGXVEYZ7ZBi1zzdWbWlDxFmi+rcE57
ytx5w+iLE366tQEMa/Jn3bly54pG5JZAr9TXkpg9sMbzWZri2ocyU/cCgYEAx1l/
9X9C/OruDp/MhhmVwKfw/X2+RhZRuv0pPcpJu7/gIoLgaxNj41XSeLqLYMlisaRk
GFU17GFXtfRGE1a3z+jj8UPTP2sHk3w8m0yI+pgWgsvG0TJ0B+XsRfpVxFiIoaEs
3AsBaGR+hrRY1dpaJ9Cu3J9mEeToTpbCzPzVDksCgYEAzwSvWNvYY4u2UFHSvz2S
tMfBzCpUUiNno50/ToN5De4ENPhy/eh5nNDVz7qh+PHSPiNMC2gyV4E4NZlOY5Jt
Zdc8ma35brvtJTVZGxwKBsqhqsYwTeFy3kFnjZn6IX5X6r1yIuCzpEfowdEtnS+h
wDtLuAGKJR6x0UP1Zk0ka6cCgYBGE6I1rJzhx7wTi/0bjtbjuKWwlolSnfnxH5ll
zTyKMXMa7qLxQQm2Gq84HWtthJ2bEMzW+O1RwQ5SOiKAHdXT0mx+nXcfLgKlx+CO
PyNP5DLVm8iyNWgwdpTOLKgFs5GkL8JTP9Mo3VrVA4TO+EkFAgjWKXp6A9vd9IVa
Be7nbQKBgAVtFKuf9nbCMfN+W1gN0vlW2lwxCTa4w0KHgIlGIIvnYVuixSgu9fGt
uylQcQirEjqrdzdVF9L2BQ37ZcLaGh1LoCmx8XVCX/HhbwW2RP798P3Z1P7htm16
ha5OfuPjHvoZklbYJo6EORJZQehS2VP63pjdnmUeMHPFzrPUevI5
-----END RSA PRIVATE KEY-----
10 changes: 10 additions & 0 deletions modules/postgres/testdata/docker-entrypoint-ssl.bash
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
bearrito marked this conversation as resolved.
Show resolved Hide resolved
set -Eeo pipefail

# Hardcoded user id from pg11-alpine image
bearrito marked this conversation as resolved.
Show resolved Hide resolved
chown 70:70 /tmp/data/ca_cert.pem
chown 70:70 /tmp/data/server.cert
chown 70:70 /tmp/data/server.key

ls -lah /tmp/data
bearrito marked this conversation as resolved.
Show resolved Hide resolved
/usr/local/bin/docker-entrypoint.sh "$@"