Skip to content

Commit

Permalink
[#70] TLS support: pgagroal - PostgreSQL
Browse files Browse the repository at this point in the history
Initial support for TLS connections to PostgreSQL, but
doesn't support pooling so we will keep the issue open until fixed
  • Loading branch information
jesperpedersen committed Dec 2, 2021
1 parent e92efff commit 717bbd6
Show file tree
Hide file tree
Showing 18 changed files with 359 additions and 117 deletions.
1 change: 1 addition & 0 deletions doc/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct worker_io
int server_fd; /* The server descriptor */
int slot; /* The slot */
SSL* client_ssl; /* The client SSL context */
SSL* server_ssl; /* The server SSL context */
void* shmem; /* The shared memory segment */
void* pipeline_shmem; /* The shared memory segment for the pipeline */
};
Expand Down
1 change: 1 addition & 0 deletions doc/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ __Danger zone__
| host | | String | Yes | The address of the PostgreSQL instance |
| port | | Int | Yes | The port of the PostgreSQL instance |
| primary | | Bool | No | Identify the instance as primary (hint) |
| tls | `off` | Bool | No | Enable Transport Layer Security (TLS) support (Experimental - no pooling) |

Note, that if `host` starts with a `/` it represents a path and `pgagroal` will connect using a Unix Domain Socket.

Expand Down
3 changes: 3 additions & 0 deletions doc/man/pgagroal.conf.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ port
primary
Identify the instance as the primary instance (hint)

tls
Enable Transport Layer Security (TLS) support (Experimental - no pooling). Default is off

REPORTING BUGS
==============

Expand Down
1 change: 1 addition & 0 deletions src/include/pgagroal.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ struct server
char name[MISC_LENGTH]; /**< The name of the server */
char host[MISC_LENGTH]; /**< The host name of the server */
int port; /**< The port of the server */
bool tls; /**< Use TLS if possible */
atomic_schar state; /**< The state of the server */
} __attribute__ ((aligned (64)));

Expand Down
10 changes: 7 additions & 3 deletions src/include/pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extern "C" {

#include <stdbool.h>
#include <stdlib.h>
#include <openssl/ssl.h>

/**
* Get a connection
Expand All @@ -45,27 +46,30 @@ extern "C" {
* @param reuse Should a slot be reused
* @param transaction_mode Obtain a connection in transaction mode
* @param slot The resulting slot
* @param ssl The resulting SSL (can be NULL)
* @return 0 upon success, 1 if pool is full, otherwise 2
*/
int
pgagroal_get_connection(char* username, char* database, bool reuse, bool transaction_mode, int* slot);
pgagroal_get_connection(char* username, char* database, bool reuse, bool transaction_mode, int* slot, SSL** ssl);

/**
* Return a connection
* @param slot The slot
* @param ssl The SSL connection (can be NULL)
* @param transaction_mode Is the connection returned in transaction mode
* @return 0 upon success, otherwise 1
*/
int
pgagroal_return_connection(int slot, bool transaction_mode);
pgagroal_return_connection(int slot, SSL* ssl, bool transaction_mode);

/**
* Kill a connection
* @param slot The slot
* @param ssl The SSL connection (can be NULL)
* @return 0 upon success, otherwise 1
*/
int
pgagroal_kill_connection(int slot);
pgagroal_kill_connection(int slot, SSL* ssl);

/**
* Perform idle timeout
Expand Down
6 changes: 4 additions & 2 deletions src/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,23 @@ extern "C" {
* @param address The client address
* @param slot The resulting slot
* @param client_ssl The client SSL context
* @param server_ssl The server SSL context
* @return 0 upon success, otherwise 1
*/
int
pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl);
pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, SSL** server_ssl);

/**
* Authenticate a prefill connection
* @param username The user name
* @param password The password
* @param database The database
* @param slot The resulting slot
* @param server_ssl The server SSL context
* @return 0 upon success, otherwise 1
*/
int
pgagroal_prefill_auth(char* username, char* password, char* database, int* slot);
pgagroal_prefill_auth(char* username, char* password, char* database, int* slot, SSL** server_ssl);

/**
* Authenticate a remote management user
Expand Down
4 changes: 3 additions & 1 deletion src/include/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern "C" {
#include <pgagroal.h>

#include <stdlib.h>
#include <openssl/ssl.h>

/**
* Get the primary server
Expand All @@ -49,10 +50,11 @@ pgagroal_get_primary(int* server);
* Update the server state
* @param slot The slot
* @param socket The descriptor
* @param ssl The SSL connection
* @return 0 upon success, otherwise 1
*/
int
pgagroal_update_server_state(int slot, int socket);
pgagroal_update_server_state(int slot, int socket, SSL* ssl);

/**
* Print the state of the servers
Expand Down
1 change: 1 addition & 0 deletions src/include/worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct worker_io
int server_fd; /**< The server descriptor */
int slot; /**< The slot */
SSL* client_ssl; /**< The client SSL context */
SSL* server_ssl; /**< The server SSL context */
};

extern volatile int running;
Expand Down
16 changes: 16 additions & 0 deletions src/libpgagroal/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,13 @@ pgagroal_read_configuration(void* shm, char* filename)
unknown = true;
}
}
else if (strlen(section) > 0)
{
if (as_bool(value, &srv.tls))
{
unknown = true;
}
}
else
{
unknown = true;
Expand Down Expand Up @@ -1020,6 +1027,15 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s
}
}

for (int i = 0; i < config->number_of_servers; i++)
{
if (config->servers[i].tls)
{
pgagroal_log_fatal("pgagroal: Transaction pipeline does not support TLS to a server");
return 1;
}
}

if (config->blocking_timeout > 0)
{
pgagroal_log_warn("pgagroal: Using blocking_timeout for the transaction pipeline is not recommended");
Expand Down
4 changes: 2 additions & 2 deletions src/libpgagroal/management.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ pgagroal_management_transfer_connection(int32_t slot)
if (cmptr)
free(cmptr);
pgagroal_disconnect(fd);
pgagroal_kill_connection(slot);
pgagroal_kill_connection(slot, NULL);

return 1;
}
Expand Down Expand Up @@ -1105,7 +1105,7 @@ pgagroal_management_client_fd(int32_t slot, pid_t pid)
error:
free(cmptr);
pgagroal_disconnect(fd);
pgagroal_kill_connection(slot);
pgagroal_kill_connection(slot, NULL);

return 1;
}
Expand Down
10 changes: 8 additions & 2 deletions src/libpgagroal/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,11 +1349,17 @@ ssl_write_message(SSL* ssl, struct message* msg)
keep_write = true;
break;
case SSL_ERROR_SYSCALL:
pgagroal_log_error("SSL_ERROR_SYSCALL: %s (%d)", strerror(errno), SSL_get_fd(ssl));
pgagroal_log_error("SSL_ERROR_SYSCALL: FD %d", SSL_get_fd(ssl));
pgagroal_log_error("%s", ERR_error_string(err, NULL));
pgagroal_log_error("%s", ERR_lib_error_string(err));
pgagroal_log_error("%s", ERR_reason_error_string(err));
errno = 0;
break;
case SSL_ERROR_SSL:
pgagroal_log_error("SSL_ERROR_SSL: %s (%d)", strerror(errno), SSL_get_fd(ssl));
pgagroal_log_error("SSL_ERROR_SSL: FD %d", SSL_get_fd(ssl));
pgagroal_log_error("%s", ERR_error_string(err, NULL));
pgagroal_log_error("%s", ERR_lib_error_string(err));
pgagroal_log_error("%s", ERR_reason_error_string(err));
errno = 0;
break;
}
Expand Down
18 changes: 16 additions & 2 deletions src/libpgagroal/pipeline_perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,14 @@ performance_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
if (likely(msg->kind != 'X'))
{
status = pgagroal_write_socket_message(wi->server_fd, msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_write_socket_message(wi->server_fd, msg);
}
else
{
status = pgagroal_write_ssl_message(wi->server_ssl, msg);
}
if (unlikely(status != MESSAGE_STATUS_OK))
{
goto server_error;
Expand Down Expand Up @@ -195,7 +202,14 @@ performance_server(struct ev_loop *loop, struct ev_io *watcher, int revents)

wi = (struct worker_io*)watcher;

status = pgagroal_read_socket_message(wi->server_fd, &msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_read_socket_message(wi->server_fd, &msg);
}
else
{
status = pgagroal_read_ssl_message(wi->server_ssl, &msg);
}
if (likely(status == MESSAGE_STATUS_OK))
{
status = pgagroal_write_socket_message(wi->client_fd, msg);
Expand Down
18 changes: 16 additions & 2 deletions src/libpgagroal/pipeline_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,14 @@ session_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
}
}

status = pgagroal_write_socket_message(wi->server_fd, msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_write_socket_message(wi->server_fd, msg);
}
else
{
status = pgagroal_write_ssl_message(wi->server_ssl, msg);
}
if (unlikely(status == MESSAGE_STATUS_ERROR))
{
if (config->failover)
Expand Down Expand Up @@ -401,7 +408,14 @@ session_server(struct ev_loop *loop, struct ev_io *watcher, int revents)

client_active(wi->slot);

status = pgagroal_read_socket_message(wi->server_fd, &msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_read_socket_message(wi->server_fd, &msg);
}
else
{
status = pgagroal_read_ssl_message(wi->server_ssl, &msg);
}
if (likely(status == MESSAGE_STATUS_OK))
{
pgagroal_prometheus_network_received_add(msg->length);
Expand Down
31 changes: 24 additions & 7 deletions src/libpgagroal/pipeline_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ transaction_start(struct ev_loop* loop, struct worker_io* w)
pgagroal_tracking_event_slot(TRACKER_TX_RETURN_CONNECTION_START, w->slot);

is_new = config->connections[w->slot].new;
pgagroal_return_connection(w->slot, true);
pgagroal_return_connection(w->slot, w->server_ssl, true);

w->server_fd = -1;
w->slot = -1;
Expand Down Expand Up @@ -176,7 +176,7 @@ transaction_stop(struct ev_loop* loop, struct worker_io* w)

ev_io_stop(loop, (struct ev_io*)&server_io);
pgagroal_tracking_event_slot(TRACKER_TX_RETURN_CONNECTION_STOP, w->slot);
pgagroal_return_connection(slot, true);
pgagroal_return_connection(slot, w->server_ssl, true);
slot = -1;
}

Expand All @@ -197,6 +197,7 @@ static void
transaction_client(struct ev_loop* loop, struct ev_io* watcher, int revents)
{
int status = MESSAGE_STATUS_ERROR;
SSL* s_ssl = NULL;
struct worker_io* wi = NULL;
struct message* msg = NULL;
struct configuration* config = NULL;
Expand All @@ -208,13 +209,14 @@ transaction_client(struct ev_loop* loop, struct ev_io* watcher, int revents)
if (slot == -1)
{
pgagroal_tracking_event_basic(TRACKER_TX_GET_CONNECTION, &username[0], &database[0]);
if (pgagroal_get_connection(&username[0], &database[0], true, true, &slot))
if (pgagroal_get_connection(&username[0], &database[0], true, true, &slot, &s_ssl))
{
pgagroal_write_pool_full(wi->client_ssl, wi->client_fd);
goto get_error;
}

wi->server_fd = config->connections[slot].fd;
wi->server_ssl = s_ssl;
wi->slot = slot;

memcpy(&config->connections[slot].appname[0], &appname[0], MAX_APPLICATION_NAME);
Expand All @@ -224,6 +226,7 @@ transaction_client(struct ev_loop* loop, struct ev_io* watcher, int revents)
server_io.server_fd = config->connections[slot].fd;
server_io.slot = slot;
server_io.client_ssl = wi->client_ssl;
server_io.server_ssl = wi->server_ssl;

fatal = false;

Expand Down Expand Up @@ -292,7 +295,14 @@ transaction_client(struct ev_loop* loop, struct ev_io* watcher, int revents)
}
}

status = pgagroal_write_socket_message(wi->server_fd, msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_write_socket_message(wi->server_fd, msg);
}
else
{
status = pgagroal_write_ssl_message(wi->server_ssl, msg);
}
if (unlikely(status == MESSAGE_STATUS_ERROR))
{
if (config->failover)
Expand Down Expand Up @@ -399,7 +409,14 @@ transaction_server(struct ev_loop *loop, struct ev_io *watcher, int revents)
goto client_error;
}

status = pgagroal_read_socket_message(wi->server_fd, &msg);
if (wi->server_ssl == NULL)
{
status = pgagroal_read_socket_message(wi->server_fd, &msg);
}
else
{
status = pgagroal_read_ssl_message(wi->server_ssl, &msg);
}
if (likely(status == MESSAGE_STATUS_OK))
{
pgagroal_prometheus_network_received_add(msg->length);
Expand Down Expand Up @@ -474,12 +491,12 @@ transaction_server(struct ev_loop *loop, struct ev_io *watcher, int revents)

if (deallocate)
{
pgagroal_write_deallocate_all(NULL, wi->server_fd);
pgagroal_write_deallocate_all(wi->server_ssl, wi->server_fd);
deallocate = false;
}

pgagroal_tracking_event_slot(TRACKER_TX_RETURN_CONNECTION, slot);
if (pgagroal_return_connection(slot, true))
if (pgagroal_return_connection(slot, wi->server_ssl, true))
{
goto return_error;
}
Expand Down
Loading

0 comments on commit 717bbd6

Please sign in to comment.