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

mdb iamproxy auth support #561

Merged
merged 30 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions sources/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions sources/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
24 changes: 24 additions & 0 deletions sources/config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion sources/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -2338,4 +2338,4 @@ void od_frontend(void *arg)
od_router_unroute(router, client);
/* close frontend connection */
od_frontend_close(client);
}
}
11 changes: 11 additions & 0 deletions sources/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
250 changes: 250 additions & 0 deletions sources/mdb_iamproxy.c
Original file line number Diff line number Diff line change
@@ -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
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved
#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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's mark these as static.
Generaly we do all the formatting stuff in KiWi... it's kind of byte-formatting lib.

{
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;
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved
}
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;
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved
}

/*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;
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved
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);
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved

/*SETUP IO*/
machine_io_t *io;
io = machine_io_create();
AndrewOvvv marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Loading
Loading