mdb iamproxy auth support (#561)

This commit is contained in:
Ovchinnikov Andrew 2024-02-05 13:25:50 +03:00 committed by GitHub
parent ccd4dbf6e3
commit 0e44d13290
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 327 additions and 2 deletions

View File

@ -49,7 +49,8 @@ set(od_src
hashmap.c
hba.c
hba_reader.c
hba_rule.c)
hba_rule.c
mdb_iamproxy.c)
if (PAM_FOUND)
list(APPEND od_src pam.c)

View File

@ -67,6 +67,19 @@ static inline int od_auth_frontend_cleartext(od_client_t *client)
od_extention_t *extentions = client->global->extentions;
/* support mdb_iamproxy authentication */
if (client->rule->enable_mdb_iamproxy_auth) {
int authentication_result = mdb_iamproxy_authenticate_user(
client->startup.user.value, client_token.password,
instance, client);
kiwi_password_free(&client_token);
machine_msg_free(msg);
if (authentication_result != OK_RESPONSE) {
goto auth_failed; // refence at line 80, 100 and etc
}
return OK_RESPONSE;
}
#ifdef LDAP_FOUND
if (client->rule->ldap_endpoint_name) {
od_debug(&instance->logger, "auth", client, NULL,

View File

@ -72,6 +72,9 @@ struct od_client {
int ldap_storage_password_len;
char *ldap_auth_dn;
#endif
/* external_id for logging additional ifno about client */
char *external_id;
};
static const size_t OD_CLIENT_DEFAULT_HASHMAP_SZ = 420;
@ -108,6 +111,7 @@ static inline void od_client_init(od_client_t *client)
client->ldap_storage_password_len = 0;
client->ldap_auth_dn = NULL;
#endif
client->external_id = NULL;
kiwi_be_startup_init(&client->startup);
kiwi_vars_init(&client->vars);
@ -146,6 +150,9 @@ static inline void od_client_free(od_client_t *client)
if (client->prep_stmt_ids) {
od_hashmap_free(client->prep_stmt_ids);
}
if (client->external_id) {
free(client->external_id);
}
free(client);
}

View File

@ -115,6 +115,8 @@ typedef enum {
OD_LAUTH_QUERY_USER,
OD_LAUTH_LDAP_SERVICE,
OD_LAUTH_PASSWORD_PASSTHROUGH,
OD_LAUTH_MDB_IAMPROXY_ENABLE,
OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH,
OD_LQUANTILES,
OD_LMODULE,
OD_LLDAP_ENDPOINT,
@ -275,6 +277,9 @@ static od_keyword_t od_config_keywords[] = {
od_keyword("password_passthrough", OD_LAUTH_PASSWORD_PASSTHROUGH),
od_keyword("load_module", OD_LMODULE),
od_keyword("hba_file", OD_LHBA_FILE),
od_keyword("enable_mdb_iamproxy_auth", OD_LAUTH_MDB_IAMPROXY_ENABLE),
od_keyword("mdb_iamproxy_socket_path",
OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH),
/* ldap */
od_keyword("ldap_endpoint", OD_LLDAP_ENDPOINT),
@ -1205,6 +1210,7 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
od_extention_t *extentions,
od_storage_watchdog_t *watchdog)
{
rule->mdb_iamproxy_socket_path = NULL;
for (;;) {
od_token_t token;
int rc;
@ -1293,6 +1299,24 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
&rule->auth_module))
return NOT_OK_RESPONSE;
break;
/* mdb_iamproxy authentication */
case OD_LAUTH_MDB_IAMPROXY_ENABLE: {
if (!od_config_reader_yes_no(
reader, &rule->enable_mdb_iamproxy_auth))
return NOT_OK_RESPONSE;
if (rule->mdb_iamproxy_socket_path == NULL)
rule->mdb_iamproxy_socket_path =
"/var/run/iam-auth-proxy/iam-auth-proxy.sock";
break;
}
case OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH: {
if (rule->mdb_iamproxy_socket_path != NULL)
free(rule->mdb_iamproxy_socket_path);
if (!od_config_reader_string(
reader, &rule->mdb_iamproxy_socket_path))
return NOT_OK_RESPONSE;
break;
}
#ifdef PAM_FOUND
/* auth_pam_service */
case OD_LAUTH_PAM_SERVICE:

View File

@ -2340,4 +2340,4 @@ cleanup:
od_router_unroute(router, client);
/* close frontend connection */
od_frontend_close(client);
}
}

View File

@ -215,6 +215,17 @@ od_logger_format(od_logger_t *logger, od_logger_level_t level, char *context,
if (od_unlikely(format_pos == format_end))
break;
switch (*format_pos) {
/* external_id */
case 'x': {
if (client && client->external_id != NULL) {
len = od_snprintf(dst_pos,
dst_end - dst_pos,
"%s",
client->external_id);
dst_pos += len;
break;
}
}
/* unixtime */
case 'n': {
time_t tm = time(NULL);

250
sources/mdb_iamproxy.c Normal file
View File

@ -0,0 +1,250 @@
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
#include <odyssey.h>
#include <machinarium.h>
#include <limits.h>
#include <stdint.h>
#include <malloc.h>
#include <sys/poll.h>
#include <sys/un.h>
#include <sys/socket.h>
/*CONNECTION CALLBACK TYPES*/
#define MDB_IAMPROXY_CONN_ERROR -1
#define MDB_IAMPROXY_CONN_TIMEOUT -1
#define MDB_IAMPROXY_CONN_ACCEPTED 0
#define MDB_IAMPROXY_CONN_DENIED -1
#define MDB_IAMPROXY_RES_ERROR -1
#define MDB_IAMPROXY_RES_OK 0
/*AUTHENTICATION TIMEOUT LIMIT*/
#define MDB_IAMPROXY_DEFAULT_HEADER_SIZE 8
#define MDB_IAMPROXY_DEFAULT_CNT_CONNECTIONS 1
#define MDB_IAMPROXY_MAX_MSG_BODY_SIZE 1048576 // 1 Mb
#define MDB_IAMPROXY_DEFAULT_CONNECTION_TIMEOUT 1000
#define MDB_IAMPROXY_DEFAULT_RECEIVING_HEADER_TIMEOUT 4000
#define MDB_IAMPROXY_DEFAULT_RECEIVING_BODY_TIMEOUT 1000
#define MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT 1000
/*PAM SOCKET FILE*/
#define MDB_IAMPROXY_DEFAULT_SOCKET_FILE \
"/var/run/iam-auth-proxy/iam-auth-proxy.sock" // PAM SOCKET FILE place
void put_header(char dst[], uint64_t src)
{
for (int i = 0; i < MDB_IAMPROXY_DEFAULT_HEADER_SIZE; ++i) {
dst[i] = (src & 0xFF);
src >>= CHAR_BIT;
}
}
void fetch_header(uint64_t *dst, char src[])
{
for (int i = 0; i < MDB_IAMPROXY_DEFAULT_HEADER_SIZE; ++i) {
(*dst) |= (((uint64_t)src[i]) << (i * CHAR_BIT));
}
}
machine_msg_t *mdb_iamproxy_io_read(machine_io_t *io)
{
machine_msg_t *header;
machine_msg_t *msg;
uint64_t body_size = 0;
uint64_t received = 0;
/* RECEIVE HEADER */
header = machine_read(io, MDB_IAMPROXY_DEFAULT_HEADER_SIZE,
MDB_IAMPROXY_DEFAULT_RECEIVING_HEADER_TIMEOUT);
if (header == NULL) {
return NULL;
}
fetch_header(&body_size, (char *)machine_msg_data(header));
machine_msg_free(header);
if (body_size > MDB_IAMPROXY_MAX_MSG_BODY_SIZE) {
return NULL;
}
msg = machine_read(io, body_size,
MDB_IAMPROXY_DEFAULT_RECEIVING_BODY_TIMEOUT);
if (msg == NULL) {
return NULL;
}
return msg;
}
int mdb_iamproxy_io_write(machine_io_t *io, machine_msg_t *msg)
{
/*GET COMMON MSG INFO AND ALLOCATE BUFFER*/
int32_t send_result = MDB_IAMPROXY_RES_OK;
uint64_t body_size = machine_msg_size(
msg); // stores size of message (add one byte for 'c\0')
/* PREPARE HEADER BUFFER */
machine_msg_t *header =
machine_msg_create(MDB_IAMPROXY_DEFAULT_HEADER_SIZE);
if (header == NULL) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}
put_header((char *)machine_msg_data(header), body_size);
/*SEND HEADER TO SOCKET*/
if (machine_write(io, header, MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT) <
0) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}
/*SEND MSG TO SOCKET*/
if (machine_write(io, msg, MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT) < 0) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}
free_end:
return send_result;
}
int mdb_iamproxy_authenticate_user(const char *username, const char *token,
od_instance_t *instance, od_client_t *client)
{
int32_t authentication_result =
MDB_IAMPROXY_CONN_DENIED; // stores authenticate status for user (default value: CONN_DENIED)
int32_t correct_sending =
MDB_IAMPROXY_CONN_ACCEPTED; // stores stutus of sending data to iam-auth-proxy
char *auth_status_char;
machine_msg_t *msg_username = NULL, *msg_token = NULL,
*auth_status = NULL, *external_user = NULL;
/*SOCKET SETUP*/
struct sockaddr *saddr;
struct sockaddr_un
exchange_socket; // socket for interprocceses connection
memset(&exchange_socket, 0, sizeof(exchange_socket));
exchange_socket.sun_family = AF_UNIX;
saddr = (struct sockaddr *)&exchange_socket;
od_snprintf(exchange_socket.sun_path, sizeof(exchange_socket.sun_path),
"%s", MDB_IAMPROXY_DEFAULT_SOCKET_FILE);
/*SETUP IO*/
machine_io_t *io;
io = machine_io_create();
if (io == NULL) {
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_end;
}
/*CONNECT TO SOCKET*/
int rc = machine_connect(io, saddr,
MDB_IAMPROXY_DEFAULT_CONNECTION_TIMEOUT);
if (rc == NOT_OK_RESPONSE) {
od_error(&instance->logger, "auth", client, NULL,
"failed to connect to %s", exchange_socket.sun_path);
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_end;
}
/*COMMUNICATE WITH SOCKET*/
msg_username = machine_msg_create(0);
if (msg_username == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to allocate msg_username");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
if (machine_msg_write(msg_username, username, strlen(username) + 1) <
0) {
od_error(&instance->logger, "auth", client, NULL,
"failed to send username to msg_username");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
msg_token = machine_msg_create(0);
if (msg_token == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to allocate msg_token");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
if (machine_msg_write(msg_token, token, strlen(token) + 1) < 0) {
od_error(&instance->logger, "auth", client, NULL,
"failed to write token to msg_token");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
correct_sending = mdb_iamproxy_io_write(
io, msg_username); // send USERNAME to socket
if (correct_sending !=
MDB_IAMPROXY_RES_OK) { // error during sending data to socket
od_error(&instance->logger, "auth", client, NULL,
"failed to send username to iam-auth-proxy");
authentication_result = correct_sending;
goto free_io;
}
correct_sending =
mdb_iamproxy_io_write(io, msg_token); // send TOKEN to socket
if (correct_sending !=
MDB_IAMPROXY_RES_OK) { // error during sending data to socket
od_error(&instance->logger, "auth", client, NULL,
"failed to send token to iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
/*COMMUNUCATE WITH SOCKET*/
auth_status =
mdb_iamproxy_io_read(io); // recieve auth_status from socket
if (auth_status == NULL) { // recieving is not completed successfully
od_error(&instance->logger, "auth", client, NULL,
"failed to receive auth_status from iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
auth_status_char = (char *)machine_msg_data(auth_status);
if ((unsigned)auth_status_char[0]) {
authentication_result = MDB_IAMPROXY_CONN_ACCEPTED;
} else {
authentication_result = MDB_IAMPROXY_CONN_DENIED;
}
external_user =
mdb_iamproxy_io_read(io); // recieve subject_id from socket
if (external_user == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to receive external_user from iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_auth_status;
}
client->external_id = malloc(machine_msg_size(external_user));
memcpy(client->external_id, (char *)machine_msg_data(external_user),
machine_msg_size(external_user));
od_log(&instance->logger, "auth", client, NULL,
"user '%s.%s', with client_id: %s was authenticated by iam with subject_id: %s",
client->startup.database.value, client->startup.user.value,
client->id.id, client->external_id);
/*FREE RESOURCES*/
free_external_user:
machine_msg_free(external_user);
free_auth_status:
machine_msg_free(auth_status);
free_io:
machine_io_free(io);
free_end:
/*RETURN RESULT*/
return authentication_result;
}

14
sources/mdb_iamproxy.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef ODYSSEY_IAMPROXY_H
#define ODYSSEY_IAMPROXY_H
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
int mdb_iamproxy_authenticate_user(const char *username, const char *token,
od_instance_t *instance,
od_client_t *client);
#endif /* ODYSSEY_IAMPROXy_H */

View File

@ -200,6 +200,8 @@ void od_rules_rule_free(od_rule_t *rule)
free(rule->storage_password);
if (rule->pool)
od_rule_pool_free(rule->pool);
if (rule->mdb_iamproxy_socket_path)
free(rule->mdb_iamproxy_socket_path);
od_list_t *i, *n;
od_list_foreach_safe(&rule->auth_common_names, i, n)

View File

@ -79,6 +79,9 @@ struct od_rule {
od_list_t auth_common_names;
int auth_common_names_count;
int enable_mdb_iamproxy_auth;
char *mdb_iamproxy_socket_path;
#ifdef PAM_FOUND
/* PAM parametrs */
char *auth_pam_service;