Native PostgreSQL driver / client for Zig
0

Configure Feed

Select the types of activity you want to include in your feed.

add support for verify-all and custom root certs

+310 -66
+13 -9
Makefile
··· 4 4 t: 5 5 TEST_FILTER="${F}" zig build test --summary all -freference-trace 6 6 7 - .PHONY: .d 7 + .PHONY: d 8 8 d: 9 - # docker build tests/ -f tests/Dockerfile -t "pgzig:pg" 10 - docker run -p 5432:5432 -it --rm \ 11 - -v $(shell pwd)/tests/pg_hba.conf:/etc/postgresql/pg_hba.conf \ 12 - -e POSTGRES_PASSWORD=root_pw \ 13 - -e POSTGRES_USER=postgres \ 14 - pgzig:pg \ 15 - postgres \ 16 - -c 'hba_file=/etc/postgresql/pg_hba.conf' 9 + cd tests && docker compose up 10 + 11 + .PHONY: ssl 12 + ssl: 13 + openssl req -days 3650 -new -text -nodes -subj '/C=SG/ST=SG/L=SG/O=Personal/OU=Personal/CN=localhost' -keyout tests/server.key -out tests/server.csr 14 + openssl req -days 3650 -x509 -text -in tests/server.csr -key tests/server.key -out tests/server.crt 15 + rm tests/server.csr 16 + cp tests/server.crt tests/root.crt 17 + 18 + openssl req -days 3650 -new -nodes -subj '/C=SG/ST=SG/L=SG/O=Personal/OU=Personal/CN=localhost/CN=testclient1' -keyout tests/client.key -out tests/client.csr 19 + openssl x509 -days 3650 -req -CAcreateserial -in tests/client.csr -CA tests/root.crt -CAkey tests/server.key -out tests/client.crt 20 + rm tests/client.csr
+5 -1
build.zig
··· 62 62 .test_runner = b.path("test_runner.zig"), 63 63 }); 64 64 addLibs(lib_test, modules); 65 + lib_test.addLibraryPath(std.Build.LazyPath{.cwd_relative = "/opt/openssl/lib"}); 66 + lib_test.addIncludePath(std.Build.LazyPath{.cwd_relative = "/opt/openssl/include"}); 67 + lib_test.linkSystemLibrary("crypto"); 68 + lib_test.linkSystemLibrary("ssl"); 65 69 66 70 { 67 71 const options = b.addOptions(); 68 - options.addOption(bool, "openssl", false); 72 + options.addOption(bool, "openssl", true); 69 73 lib_test.root_module.addOptions("config", options); 70 74 } 71 75
+31 -33
readme.md
··· 4 4 5 5 See or run [example/main.zig](https://github.com/karlseguin/pg.zig/blob/master/example/main.zig) for a number of examples. 6 6 7 - ## Experimental TLS 8 - This branch has experimental TLS support via openssl. Custom certificates are not yet supported. 9 - 10 - When loading the module, you must enable openssl by including at least 1 openssl setting: 11 - 12 - ```zig 13 - const pg_module = b.dependency("pg", .{ 14 - .target = target, 15 - .optimize = optimize, 16 - .openssl_lib_name = "ssl", 17 - .openssl_lib_path = std.Build.LazyPath{.cwd_relative = "/path/to/openssl/lib"}, 18 - .openssl_include_path = std.Build.LazyPath{.cwd_relative = "/path/to/openssl/include"}, 19 - }).module("pg") 20 - 21 - The system defaults are use for the library and include paths. These should only be set if openssl is installed in a non-default location. In most cases specifying `.openssl_lib_name = "ssl"` or, for some systems `.openssl_lib_name = "openssl"` should be enough. 22 - 23 - Set the connection's `tls` option to true, or specify `sslmode=required` when using a postgresql url path: 24 - 25 - ```zig 26 - var pool = try pg.Pool.init(allocator, .{ 27 - .connect = .{ .port = 5432, .host = "ip_or_hostname", .tls = true}, 28 - .auth = .{ .... }, 29 - .size = 5, 30 - }); 31 - 32 - // OR 33 - const uri = try std.Uri.parse("postgresql://user:password@hostname/DBNAME?sslmode=require"); 34 - var pool = try pg.Pool.initUri(allocator, uri, 10, 5_000); 35 - ``` 36 - 37 - If you get an error, please call `pg.printSSLError();` to hopefully print an error message to stderr which can be included in a ticket. This can safely be called in a `catch` clause, and will display nothing if the error is NOT SSL-related. 38 - 39 7 ## Install 40 8 1) Add pg.zig as a dependency in your `build.zig.zon`: 41 9 ··· 66 34 .auth = .{ 67 35 .username = "postgres", 68 36 .database = "postgres", 69 - .password = "root_pw", 37 + .password = "postgres", 70 38 .timeout = 10_000, 71 39 } 72 40 }); ··· 594 562 * `pg_alloc_params` - counts the number of parameter states that were allocated. This indicates that your queries have more parameters than `result_state_size`. If this happens often, consider increasing `result_state_size`. 595 563 * `pg_alloc_columns` - counts the number of columns states that were allocated. This indicates that your queries are returning more columns than `result_state_size`. If this happens often, consider increasing `result_state_size`. 596 564 * `pg_alloc_reader` - counts the number of bytes allocated while reading messages from PostgreSQL. This generally happens as a result of large result (e.g. selecting large text fields). Controlled by the `read_buffer` configuration option. 565 + 566 + ## TLS (Experimental) 567 + TLS is supported via openssl. When loading the module, you must enable openssl by including at least 1 openssl setting: 568 + 569 + ```zig 570 + const pg_module = b.dependency("pg", .{ 571 + .target = target, 572 + .optimize = optimize, 573 + .openssl_lib_name = "ssl", 574 + .openssl_lib_path = std.Build.LazyPath{.cwd_relative = "/path/to/openssl/lib"}, 575 + .openssl_include_path = std.Build.LazyPath{.cwd_relative = "/path/to/openssl/include"}, 576 + }).module("pg") 577 + 578 + When not specified, the system defaults are use for the library and include paths. These should only be set if openssl is installed in a non-default location. In most cases specifying `.openssl_lib_name = "ssl"` or, for some systems `.openssl_lib_name = "openssl"` should be enough. 579 + 580 + Set the connection's `tls` option to either `.required` or `.{verify_full = null}`. When using a custom root certificate, specify the path: `.{verify_full = "/path/to/root.crt"}`. 581 + 582 + ```zig 583 + var pool = try pg.Pool.init(allocator, .{ 584 + .connect = .{ .port = 5432, .host = "ip_or_hostname", .tls = .{.verify_full = null}}, 585 + .auth = .{ .... }, 586 + .size = 5, 587 + }); 588 + 589 + // OR 590 + const uri = try std.Uri.parse("postgresql://user:password@hostname/DBNAME?sslmode=require"); 591 + var pool = try pg.Pool.initUri(allocator, uri, 10, 5_000); 592 + ``` 593 + 594 + In your main file, you can define a global `pub const pg_stderr_tls = true;` to have pg.zig print possible TLS-related errors to stderr. Alternatively, if you get an error, you `pg.printSSLError();` to hopefully print an error message to stderr which can be included in a ticket. This can safely be called in a `catch` clause, and will display nothing if the error is NOT SSL-related. Note that using the global `pg_stderr_tls` is more likely to print useful information in the case of certification verification problems. 597 595 598 596 ## Tests 599 597
+40 -7
src/conn.zig
··· 77 77 write_buffer: ?u16 = null, 78 78 read_buffer: ?u16 = null, 79 79 result_state_size: u16 = 32, 80 - tls: bool = false, 80 + tls: TLS = .off, 81 81 _hostz: ?[:0]const u8 = null, 82 + 83 + pub const TLS = union(enum) { 84 + off: void, 85 + require: void, 86 + verify_full: ?[]const u8, 87 + }; 82 88 }; 83 89 84 90 pub const QueryOpts = struct { ··· 109 115 110 116 pub fn open(allocator: Allocator, opts: Opts) !Conn { 111 117 var ssl_ctx: ?*SSLCtx = null; 112 - if (comptime lib.has_openssl) { 113 - if (opts.tls) { 114 - ssl_ctx = try lib.initializeSSLContext(); 115 - } 118 + switch (opts.tls) { 119 + .off => {}, 120 + else => |tls_config| { 121 + if (comptime lib.has_openssl == false) { 122 + return error.OpenSSLNotConfigured; 123 + } 124 + ssl_ctx = try lib.initializeSSLContext(tls_config); 125 + }, 116 126 } 117 127 errdefer lib.freeSSLContext(ssl_ctx); 118 128 var conn = try openWithContext(allocator, opts, ssl_ctx); ··· 449 459 var conn = try Conn.open(t.allocator, .{}); 450 460 defer conn.deinit(); 451 461 try t.expectError(error.PG, conn.auth(.{ .username = "does_not_exist" })); 452 - try t.expectString("password authentication failed for user \"does_not_exist\"", conn.err.?.message); 462 + try t.expectEqual(true, std.mem.indexOf(u8, conn.err.?.message, "user \"does_not_exist\"") != null); 453 463 } 454 464 455 465 test "Conn: auth cleartext password" { ··· 1649 1659 } 1650 1660 1651 1661 test "open URI" { 1652 - const uri = try std.Uri.parse("postgresql://postgres:root_pw@localhost:5432/postgres?tcp_user_timeout=5000"); 1662 + const uri = try std.Uri.parse("postgresql://postgres:postgres@localhost:5432/postgres?tcp_user_timeout=5000"); 1653 1663 var conn = try Conn.openAndAuthUri(t.allocator, uri); 1654 1664 conn.deinit(); 1665 + } 1666 + 1667 + test "Conn: TLS required" { 1668 + { 1669 + var conn = try Conn.open(t.allocator, .{.tls = .off}); 1670 + defer conn.deinit(); 1671 + try t.expectError(error.PG, conn.auth(.{ .username = "pgz_user_ssl" })); 1672 + try t.expectEqual(true, std.mem.indexOf(u8, conn.err.?.message, "no encryption") != null); 1673 + } 1674 + 1675 + { 1676 + var conn = t.connect(.{.tls = .require, .username = "pgz_user_ssl", .password = "pgz_user_ssl_pw"}); 1677 + defer conn.deinit(); 1678 + } 1679 + } 1680 + 1681 + test "Conn: TLS verify-full" { 1682 + try t.expectError(error.SSLCertificationVerificationError, Conn.open(t.allocator, .{.tls = .{.verify_full = null}})); 1683 + 1684 + { 1685 + var conn = t.connect(.{.tls = .{.verify_full = "tests/root.crt"}, .username = "pgz_user_ssl", .password = "pgz_user_ssl_pw"}); 1686 + defer conn.deinit(); 1687 + } 1655 1688 } 1656 1689 1657 1690 fn expectNumeric(numeric: types.Numeric, expected: []const u8) !void {
+35 -5
src/lib.zig
··· 43 43 } 44 44 }; 45 45 46 + pub const _stderr_tls = blk: { 47 + if (@hasDecl(root, "pg_stderr_tls")) { 48 + break :blk root.pg_stderr_tls; 49 + } 50 + break :blk false; 51 + }; 52 + 46 53 pub fn assert(ok: bool) void { 47 54 if (comptime _assert) { 48 55 std.debug.assert(ok); ··· 110 117 errdefer arena.deinit(); 111 118 const aa = arena.allocator(); 112 119 113 - var tls = false; 120 + var tls: Conn.Opts.TLS = .off; 114 121 var tcp_user_timeout: ?u32 = null; 115 122 if (uri.query) |qry| { 116 123 const query_string = try qry.toRawMaybeAlloc(aa); ··· 123 130 tcp_user_timeout = try std.fmt.parseInt(u32, val, 10); 124 131 } else if (std.mem.eql(u8, key, "sslmode")) { 125 132 if (std.mem.eql(u8, val, "require")) { 126 - tls = true; 133 + tls = .require; 134 + } else if (std.mem.eql(u8, val, "verify-full")) { 135 + tls = .{.verify_full = null}; 127 136 } else if (std.mem.eql(u8, val, "disable") == false) { 128 137 return error.UnsupportedSSLModeValue; 129 138 } ··· 151 160 } }; 152 161 } 153 162 154 - pub fn initializeSSLContext() !*SSLCtx { 163 + pub fn initializeSSLContext(config: Conn.Opts.TLS) !*SSLCtx { 155 164 // OpenSSL documentation says these are implicitly called, and only need to 156 165 // be called if you're doing something special 157 166 ··· 174 183 175 184 _ = openssl.SSL_CTX_set_mode(ctx, openssl.SSL_MODE_AUTO_RETRY); 176 185 177 - if (openssl.SSL_CTX_set_default_verify_paths(ctx) != 1) { 178 - return error.SSLVerityPaths; 186 + switch (config) { 187 + .off, .require => {}, 188 + .verify_full => |path_to_root| { 189 + if (path_to_root) |p| { 190 + var pathz: [std.fs.max_path_bytes + 1]u8 = undefined; 191 + @memcpy(pathz[0..p.len], p); 192 + pathz[p.len] = 0; 193 + if (openssl.SSL_CTX_load_verify_locations(ctx, pathz[0..p.len + 1].ptr, null) != 1) { 194 + if (comptime _stderr_tls) { 195 + printSSLError(); 196 + } 197 + return error.SSLVerifyPaths; 198 + } 199 + } else { 200 + if (openssl.SSL_CTX_set_default_verify_paths(ctx) != 1) { 201 + if (comptime _stderr_tls) { 202 + printSSLError(); 203 + } 204 + return error.SSLDefaultVerifyPaths; 205 + } 206 + } 207 + openssl.SSL_CTX_set_verify(ctx, openssl.SSL_VERIFY_PEER, null); 208 + }, 179 209 } 180 210 181 211 return ctx;
+9 -6
src/pool.zig
··· 49 49 var opts_copy = opts; 50 50 var ssl_ctx: ?*SSLCtx = null; 51 51 if (comptime lib.has_openssl) { 52 - if (opts.connect.tls) { 53 - ssl_ctx = try lib.initializeSSLContext(); 54 - } 55 - if (opts.connect.host) |h| { 56 - opts_copy.connect._hostz = try aa.dupeZ(u8, h); 52 + switch (opts.connect.tls) { 53 + .off => {}, 54 + else => |tls_config| { 55 + if (opts.connect.host) |h| { 56 + opts_copy.connect._hostz = try aa.dupeZ(u8, h); 57 + } 58 + ssl_ctx = try lib.initializeSSLContext(tls_config); 59 + }, 57 60 } 58 61 } 59 62 errdefer lib.freeSSLContext(ssl_ctx); ··· 322 325 .auth = .{ 323 326 .database = "postgres", 324 327 .username = "postgres", 325 - .password = "root_pw", 328 + .password = "postgres", 326 329 }, 327 330 }); 328 331 defer pool.deinit();
+14 -1
src/stream.zig
··· 56 56 return error.SSLHostNameFailed; 57 57 } 58 58 } 59 + switch (opts.tls) { 60 + .verify_full => openssl.SSL_set_verify(ssl, openssl.SSL_VERIFY_PEER, null), 61 + else => {}, 62 + } 59 63 } 60 64 61 65 if (openssl.SSL_set_fd(ssl, socket) != 1) { ··· 65 69 { 66 70 const ret = openssl.SSL_connect(ssl); 67 71 if (ret != 1) { 68 - lib.printSSLError(); 72 + const verification_code = openssl.SSL_get_verify_result(ssl); 73 + if (comptime lib._stderr_tls) { 74 + lib.printSSLError(); 75 + } 76 + if (verification_code != openssl.X509_V_OK) { 77 + if (comptime lib._stderr_tls) { 78 + std.debug.print("ssl verification error: {s}\n", .{openssl.X509_verify_cert_error_string(verification_code)}); 79 + } 80 + return error.SSLCertificationVerificationError; 81 + } 69 82 return error.SSLConnectFailed; 70 83 } 71 84 }
+4 -1
src/t.zig
··· 51 51 \\ drop user if exists pgz_user_nopass; 52 52 \\ drop user if exists pgz_user_clear; 53 53 \\ drop user if exists pgz_user_scram_sha256; 54 + \\ drop user if exists pgz_user_ssl; 54 55 \\ create user pgz_user_nopass; 55 56 \\ create user pgz_user_clear with password 'pgz_user_clear_pw'; 56 57 \\ create user pgz_user_scram_sha256 with password 'pgz_user_scram_sha256_pw'; 58 + \\ create user pgz_user_ssl with password 'pgz_user_ssl_pw'; 57 59 , .{}) catch |err| try fail(c, err); 58 60 59 61 _ = c.exec( ··· 199 201 const T = @TypeOf(opts); 200 202 201 203 var c = Conn.open(allocator, .{ 204 + .tls = if (@hasField(T, "tls")) opts.tls else .off, 202 205 .host = if (@hasField(T, "host")) opts.host else "localhost", 203 206 .read_buffer = if (@hasField(T, "read_buffer")) opts.read_buffer else 2000, 204 207 }) catch unreachable; ··· 217 220 return .{ 218 221 .database = if (@hasField(T, "database")) opts.database else "postgres", 219 222 .username = if (@hasField(T, "username")) opts.username else "postgres", 220 - .password = if (@hasField(T, "password")) opts.password else "root_pw", 223 + .password = if (@hasField(T, "password")) opts.password else "postgres", 221 224 }; 222 225 } 223 226
+22
tests/client.crt
··· 1 + -----BEGIN CERTIFICATE----- 2 + MIIDqDCCApCgAwIBAgIUbR2RMBCPcwkULT7q9WyFvoKL4HYwDQYJKoZIhvcNAQEL 3 + BQAwYTELMAkGA1UEBhMCU0cxCzAJBgNVBAgMAlNHMQswCQYDVQQHDAJTRzERMA8G 4 + A1UECgwIUGVyc29uYWwxETAPBgNVBAsMCFBlcnNvbmFsMRIwEAYDVQQDDAlsb2Nh 5 + bGhvc3QwHhcNMjQxMDI3MTIyMzAxWhcNMzQxMDI1MTIyMzAxWjB3MQswCQYDVQQG 6 + EwJTRzELMAkGA1UECAwCU0cxCzAJBgNVBAcMAlNHMREwDwYDVQQKDAhQZXJzb25h 7 + bDERMA8GA1UECwwIUGVyc29uYWwxEjAQBgNVBAMMCWxvY2FsaG9zdDEUMBIGA1UE 8 + AwwLdGVzdGNsaWVudDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM 9 + kNNsex4aZ+omuP9hRPM32tY0D41whMghDQrMm7s6jXA0G+RmUU2r7QxBHwtokvl6 10 + +jVjzPOtW+z7zfLOoPCsmJ/6HOg1tJiwblwQ4EhJnMhl7kppWsgMx/kIEKlUcMNz 11 + i2Ahu3CNuWLs/k/IPDHvkXkINjIks4GBYLkEzsE76uJujEob0BtFdChhkW76brGa 12 + 0PAt70nB07C2IC53g47G7w99WVWFdlFZucgwCVqnByNmZQ4IpBatmiSruic65cYY 13 + EJ/oY0vKjbQ768HCrYqfM6wwwXX+VeuOqmyqdjKXFvsFug0UDQzq/TCqhat1B5vR 14 + Yi8M1pVarP6PBcxeABUFAgMBAAGjQjBAMB0GA1UdDgQWBBThEs2PJk6yiMoYfCD0 15 + tH0x2vtf3DAfBgNVHSMEGDAWgBRWE0c0yVuc9KFcICpWB5J0aing4zANBgkqhkiG 16 + 9w0BAQsFAAOCAQEARk3Hkdx4t/QTduzpJBIJ8xVzxjqTpbviaZO1FX9JSgzKLy5m 17 + IheVLZhybFjCsxadIj9gvW2cBoPmQ2Y1vjXFkK4tds5I6xVu4exmX4efRZWO97pV 18 + bdZPq2db+qKwUQksX5oFeFAQM4zDhZD2GCWgL+8h8Fk+B5JRIvrRc2iySbRyjfDv 19 + VSh3p2szn2PI+p9f5W7DYVGk6Mht2HsJAIanUdQrINcjj+7qoxvxC1NmtXygFS/E 20 + kXEFdN6JFZnrrn9od63IX+yJMONTLA4FaJJgXB5I8zAo2YJOd2IO8tXnlx6PQb3x 21 + cf/jWsyX6cwPpsMxqsuBEasoLazAzSf0HCYn9Q== 22 + -----END CERTIFICATE-----
+28
tests/client.key
··· 1 + -----BEGIN PRIVATE KEY----- 2 + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMkNNsex4aZ+om 3 + uP9hRPM32tY0D41whMghDQrMm7s6jXA0G+RmUU2r7QxBHwtokvl6+jVjzPOtW+z7 4 + zfLOoPCsmJ/6HOg1tJiwblwQ4EhJnMhl7kppWsgMx/kIEKlUcMNzi2Ahu3CNuWLs 5 + /k/IPDHvkXkINjIks4GBYLkEzsE76uJujEob0BtFdChhkW76brGa0PAt70nB07C2 6 + IC53g47G7w99WVWFdlFZucgwCVqnByNmZQ4IpBatmiSruic65cYYEJ/oY0vKjbQ7 7 + 68HCrYqfM6wwwXX+VeuOqmyqdjKXFvsFug0UDQzq/TCqhat1B5vRYi8M1pVarP6P 8 + BcxeABUFAgMBAAECggEAEYnbLpem/ubo4DVdOTGIVBdwOloZAMwe58KD/1iHZrTo 9 + qUxjj9LUVh4Gk8YTHCikY22fSoqwW60gINNJSCZBQYhRCEhr2kA9FRH+f7iS9LNl 10 + 9Q3x6vLMaFgexZkUGM1q3HWsd3KSwFE5e43ZjkEm8N4SjT3ZnQ7s1rL8ZJP2D5UO 11 + R3WnOI/hycHGLJmC2LsdBF4jacderpgV9OZjS28u+NeSGOoJaUv/sVx2PhDi5icV 12 + Ycokxy/w75q5pKrnav3TgD+PRm7tVmU6WMYlmaYPVH3cxqX2P1WiZq2jqWisOKvB 13 + NxkDQlLCwBQu17yFqJ6z/FhUOY0fRCjVz63gdsn+YwKBgQD2oHwYGoXir9kfYT1+ 14 + TBsRbCZFCzb06luY5nq60v4/6Rman6c1M7t0ZKYiLER+22rTXq5dXF6hjuz6nrTP 15 + 9jHRwn/+myCLF0X5hZ1YhwQzE/qmy6O59duWYe66IyXQvG6mEKFEggLWyUbl9t1n 16 + u4vFiTTRH1lbXbQQ/RgV5sj6+wKBgQDUVx0v7BWLSV0ql9cgyj4CyO3pUplzTQb4 17 + XfaeE2EfJdNwfDgq0D/fGuaLwU4BrXcUfsVnPHg8vlhsska5horxNbzgW87sl17+ 18 + DxMgbZ6XLNOezmG5VN3KE+h9vm9rJ9yiMKw13R2zXRLWZUpzlmplxEdfGkCV4Szu 19 + AJCl1A4v/wKBgG5vGmIorj79gvncLw74wT4h8VkFVoyAzJdAzUAO7q5rkH1+c/8M 20 + tSm/T+0JaXpsgf837Ff93pn1SARJQKnGkjRdJbc6e24M89ZxkC1t9+FvVtONaDkC 21 + 8Fr8a0uKJYq8dceCttPYa7EF2+tpiWbDwiin8bCamwaghNr+meRkvSY1AoGBAJ2N 22 + Qa/UGSwvNDytS0ceKKLCWZy81/TwW1KfzaP+txp4Y4lb8gT6Xdn5yMQ7mtitz+Ra 23 + J7hw6roPdea45Lc1uBQ/jjReiouLyUTzBHsUOw7qiN6VPXdZG/Obj+71BRDaE+AY 24 + Az84IJh8X8TKhVJ8cdeuqlJLVU6gNEkoDCuuyxQbAoGBAI1jP5TAdOeXmucE1PYw 25 + mc4A/GfthWZGwCs15DVQIBTjEQuCvtxJeetraobMkBJAYXHYfUIkPm72/CTcJ5DZ 26 + Hcg6OatkYi9ZfDbapK0e2wMzNM8oUl9XTADhY4mRkaGiOdy16HwEdcrImxSyGrj4 27 + f+6nb0iajHppuJnJDwS1WDn2 28 + -----END PRIVATE KEY-----
+8 -1
tests/compose.yml
··· 3 3 image: postgres:latest 4 4 environment: 5 5 POSTGRES_USER: "postgres" 6 - POSTGRES_PASSWORD: "root_pw" 6 + POSTGRES_PASSWORD: "postgres" 7 7 PGDATA: "/var/lib/postgresql/pgdata/" 8 8 LANG: "en_US.utf8" 9 9 ports: 10 10 - 5432:5432 11 11 volumes: 12 + - "./server.crt:/etc/postgresql/server.crt:ro" 13 + - "./server.key:/etc/postgresql/server.key:ro" 12 14 - "./pg_hba.conf:/etc/postgresql/pg_hba.conf:ro" 15 + - "./postgresql.conf:/etc/postgresql/postgresql.conf:ro" 16 + - "./init_ssl.sql:/docker-entrypoint-initdb.d/init_ssl.sql:ro" 13 17 command: 14 18 - "postgres" 15 19 - "-c" 20 + - "config_file=/etc/postgresql/postgresql.conf" 21 + - "-c" 16 22 - "hba_file=/etc/postgresql/pg_hba.conf" 23 +
+4
tests/init_ssl.sql
··· 1 + ALTER SYSTEM SET ssl_ca_file TO '/etc/postgresql/root.key'; 2 + ALTER SYSTEM SET ssl_key_file TO '/etc/postgresql/server.key'; 3 + ALTER SYSTEM SET ssl_cert_file TO '/etc/postgresql/server.crt'; 4 + ALTER SYSTEM SET ssl TO 'ON';
+3 -2
tests/pg_hba.conf
··· 1 - local all postgres trust 1 + local all postgres trust 2 + host all postgres all trust 2 3 host all pgz_user_clear all password 3 4 host all pgz_user_nopass all trust 4 5 host all pgz_user_scram_sha256 all scram-sha-256 5 - host all all all scram-sha-256 6 + hostssl all pgz_user_ssl all password
+13
tests/postgresql.conf
··· 1 + max_connections = 30 2 + shared_buffers = 512MB 3 + listen_addresses = '0.0.0.0' 4 + work_mem = 4MB 5 + effective_cache_size = 512MB 6 + log_timezone = 'UTC' 7 + datestyle = 'iso, mdy' 8 + timezone = 'UTC' 9 + lc_messages = 'en_US.UTF-8' 10 + lc_monetary = 'en_US.UTF-8' 11 + lc_numeric = 'en_US.UTF-8' 12 + lc_time = 'en_US.UTF-8' 13 + fsync = false
+80
tests/root.crt
··· 1 + Certificate: 2 + Data: 3 + Version: 3 (0x2) 4 + Serial Number: 5 + 49:11:94:cb:0d:85:c6:f7:94:d8:c4:73:80:14:20:f6:04:fb:b0:01 6 + Signature Algorithm: sha256WithRSAEncryption 7 + Issuer: C=SG, ST=SG, L=SG, O=Personal, OU=Personal, CN=localhost 8 + Validity 9 + Not Before: Oct 27 12:23:01 2024 GMT 10 + Not After : Oct 25 12:23:01 2034 GMT 11 + Subject: C=SG, ST=SG, L=SG, O=Personal, OU=Personal, CN=localhost 12 + Subject Public Key Info: 13 + Public Key Algorithm: rsaEncryption 14 + Public-Key: (2048 bit) 15 + Modulus: 16 + 00:e5:d6:79:4c:e9:f3:49:88:f2:26:38:0a:ce:a9: 17 + c4:f5:8a:58:09:53:5e:cc:ed:15:32:b0:8c:56:03: 18 + f2:8c:ac:75:40:e9:9f:6d:20:84:05:38:ea:c4:f4: 19 + da:20:9c:fb:b6:35:8f:bc:7d:dd:38:c7:56:46:e1: 20 + ff:63:5c:41:63:16:10:57:fa:47:28:a2:5e:16:5c: 21 + 1d:20:ea:a2:75:e3:99:d0:5e:c6:33:22:34:78:fc: 22 + 75:8a:9e:57:e4:1c:8e:93:53:b7:65:8b:a1:45:ce: 23 + 09:e2:b7:4e:79:bb:26:fc:3a:2b:c8:b4:75:15:b7: 24 + 43:4d:bc:1e:db:4e:87:8c:42:68:5d:74:37:cd:41: 25 + c5:e8:89:65:93:59:7c:a4:cd:01:98:f2:a9:2a:33: 26 + 8f:78:26:c4:9f:b2:5b:1b:14:b0:d2:2b:5d:19:22: 27 + 0b:0a:1c:f9:cf:a9:6c:f9:34:96:d3:e1:4f:44:20: 28 + 5a:c5:b8:16:16:ad:f9:7b:59:ab:5e:a2:b9:45:09: 29 + 74:ca:7b:6d:ab:df:32:b2:cd:c1:64:bd:4a:71:14: 30 + c7:ac:08:0d:de:76:66:86:35:c4:07:a9:75:7c:2a: 31 + 5f:7d:ed:56:ae:2f:69:f0:ad:a5:c6:f4:d6:54:67: 32 + df:12:26:e7:2f:df:d2:c8:20:e5:41:20:97:62:ab: 33 + 43:2b 34 + Exponent: 65537 (0x10001) 35 + X509v3 extensions: 36 + X509v3 Subject Key Identifier: 37 + 56:13:47:34:C9:5B:9C:F4:A1:5C:20:2A:56:07:92:74:6A:29:E0:E3 38 + X509v3 Authority Key Identifier: 39 + 56:13:47:34:C9:5B:9C:F4:A1:5C:20:2A:56:07:92:74:6A:29:E0:E3 40 + X509v3 Basic Constraints: critical 41 + CA:TRUE 42 + Signature Algorithm: sha256WithRSAEncryption 43 + Signature Value: 44 + 2f:76:09:f8:7a:12:bb:25:9d:b9:8a:b2:b3:87:0c:e0:8c:62: 45 + 49:83:2a:33:da:90:ff:58:d9:0f:29:f9:8a:02:86:83:0b:f3: 46 + 6f:86:e5:9d:ef:fa:0a:af:7f:9d:51:a4:0c:67:00:04:a8:e4: 47 + be:55:f5:43:91:1b:b7:93:16:38:be:4b:67:20:e1:8d:12:d1: 48 + 0f:60:6d:73:f3:2a:e4:f3:73:b4:1d:da:cf:df:b0:1f:b1:ed: 49 + 09:4f:1a:4a:c5:00:76:d5:e0:de:67:81:2d:a2:0a:2e:be:68: 50 + 6b:f2:54:8e:7b:85:04:cd:c5:0b:86:82:cc:0a:94:14:f1:cb: 51 + bd:2f:dd:24:5a:84:bb:17:79:c0:79:2f:47:35:cd:97:75:fd: 52 + 88:52:e0:e2:6f:c8:d0:19:6f:3c:ed:e6:9a:94:a8:93:05:e6: 53 + cd:b5:7a:6d:bb:f0:3d:34:28:7d:5f:ca:1b:21:67:2b:62:b0: 54 + d6:7d:d3:d1:5f:ec:83:2a:af:d5:a2:0a:19:24:e7:60:7a:96: 55 + 1a:04:47:30:67:44:f0:f4:1c:ba:2a:78:ed:60:56:d3:f5:de: 56 + c5:2c:23:1f:f0:a2:1b:b8:ec:e2:66:07:ca:98:9b:a0:c8:68: 57 + e4:b7:ca:ac:73:c2:5b:2d:46:ea:1d:41:33:e6:f6:08:8a:8e: 58 + 5e:96:56:06 59 + -----BEGIN CERTIFICATE----- 60 + MIIDozCCAougAwIBAgIUSRGUyw2FxveU2MRzgBQg9gT7sAEwDQYJKoZIhvcNAQEL 61 + BQAwYTELMAkGA1UEBhMCU0cxCzAJBgNVBAgMAlNHMQswCQYDVQQHDAJTRzERMA8G 62 + A1UECgwIUGVyc29uYWwxETAPBgNVBAsMCFBlcnNvbmFsMRIwEAYDVQQDDAlsb2Nh 63 + bGhvc3QwHhcNMjQxMDI3MTIyMzAxWhcNMzQxMDI1MTIyMzAxWjBhMQswCQYDVQQG 64 + EwJTRzELMAkGA1UECAwCU0cxCzAJBgNVBAcMAlNHMREwDwYDVQQKDAhQZXJzb25h 65 + bDERMA8GA1UECwwIUGVyc29uYWwxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJ 66 + KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOXWeUzp80mI8iY4Cs6pxPWKWAlTXszt 67 + FTKwjFYD8oysdUDpn20ghAU46sT02iCc+7Y1j7x93TjHVkbh/2NcQWMWEFf6Ryii 68 + XhZcHSDqonXjmdBexjMiNHj8dYqeV+QcjpNTt2WLoUXOCeK3Tnm7Jvw6K8i0dRW3 69 + Q028HttOh4xCaF10N81BxeiJZZNZfKTNAZjyqSozj3gmxJ+yWxsUsNIrXRkiCwoc 70 + +c+pbPk0ltPhT0QgWsW4Fhat+XtZq16iuUUJdMp7bavfMrLNwWS9SnEUx6wIDd52 71 + ZoY1xAepdXwqX33tVq4vafCtpcb01lRn3xIm5y/f0sgg5UEgl2KrQysCAwEAAaNT 72 + MFEwHQYDVR0OBBYEFFYTRzTJW5z0oVwgKlYHknRqKeDjMB8GA1UdIwQYMBaAFFYT 73 + RzTJW5z0oVwgKlYHknRqKeDjMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL 74 + BQADggEBAC92Cfh6ErslnbmKsrOHDOCMYkmDKjPakP9Y2Q8p+YoChoML82+G5Z3v 75 + +gqvf51RpAxnAASo5L5V9UORG7eTFji+S2cg4Y0S0Q9gbXPzKuTzc7Qd2s/fsB+x 76 + 7QlPGkrFAHbV4N5ngS2iCi6+aGvyVI57hQTNxQuGgswKlBTxy70v3SRahLsXecB5 77 + L0c1zZd1/YhS4OJvyNAZbzzt5pqUqJMF5s21em278D00KH1fyhshZytisNZ909Ff 78 + 7IMqr9WiChkk52B6lhoERzBnRPD0HLoqeO1gVtP13sUsIx/wohu47OJmB8qYm6DI 79 + aOS3yqxzwlstRuodQTPm9giKjl6WVgY= 80 + -----END CERTIFICATE-----
+1
tests/root.srl
··· 1 + 6D1D9130108F7309142D3EEAF56C85BE828BE076