Skip to content

CDRIVER-4439 add AWS credential cache #1207

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

Merged
merged 24 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
065a1b0
add test-awsauth
kevinAlbs Feb 6, 2023
c22bdf6
unconditionally define _mongoc_aws_credentials_cleanup
kevinAlbs Feb 8, 2023
90524db
add AWS credential cache
kevinAlbs Feb 8, 2023
3f2cdc9
use AWS credential cache
kevinAlbs Feb 10, 2023
2a185e2
use test-awsauth in Evergreen
kevinAlbs Feb 14, 2023
6776f34
remove outdated docs of optional variables
kevinAlbs Feb 15, 2023
6ceae5c
fix docs to note TESTCASE is an env var
kevinAlbs Feb 15, 2023
d1624d5
remove unnecessary additions runtime paths
kevinAlbs Feb 15, 2023
1b93a95
use `mcd_timer` for expiration
kevinAlbs Feb 16, 2023
d9b8d8e
remove unused vars
kevinAlbs Feb 16, 2023
21d8491
simplify bash scripts
kevinAlbs Feb 19, 2023
c5a9dea
fix comment for `expiration`
kevinAlbs Feb 19, 2023
6c8f40f
be more explicit about _mongoc_aws_credentials_cache_get behavior
kevinAlbs Feb 19, 2023
dad4cf5
rename helper to expiration_to_mcd_timer
kevinAlbs Feb 19, 2023
922e2c3
compute in int64_t domain
kevinAlbs Feb 19, 2023
e2fa0ac
remove unnecessary expiration vars
kevinAlbs Feb 19, 2023
1c6c266
add MONGOC_AWS_CREDENTIALS_INIT macro
kevinAlbs Feb 19, 2023
0c9b872
only initialize and cleanup AWS cache if AWS is enabled
kevinAlbs Feb 19, 2023
34a024d
remove unnecessary can_setenv
kevinAlbs Feb 19, 2023
9664419
fix -Wmissing-braces warning
kevinAlbs Feb 19, 2023
59fa557
fix signature of test_aws_cache
kevinAlbs Feb 19, 2023
bc2f59b
do not support uninitialized creds in _mongoc_aws_credentials_cache_get
kevinAlbs Feb 22, 2023
154d6c7
do not reuse creds after cleanup
kevinAlbs Feb 22, 2023
a6a75c1
fix -Wmissing-field-initializers warning
kevinAlbs Feb 22, 2023
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
4 changes: 2 additions & 2 deletions .evergreen/generated_configs/legacy-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1817,11 +1817,11 @@ tasks:
shell: bash
script: |-
set -o errexit
# Compile mongoc-ping. Disable unnecessary dependencies since mongoc-ping is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
# Compile test-awsauth. Disable unnecessary dependencies since test-awsauth is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
. .evergreen/scripts/find-cmake.sh
export CC='${CC}'
$CMAKE -DENABLE_SASL=OFF -DENABLE_SNAPPY=OFF -DENABLE_ZSTD=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=OFF .
$CMAKE --build . --target mongoc-ping
$CMAKE --build . --target test-awsauth
- func: upload-build
- name: test-aws-openssl-regular-latest
depends_on:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,11 +826,11 @@ def _check_allowed(self):
all_tasks = chain(all_tasks, IPTask.matrix())

aws_compile_task = NamedTask('debug-compile-aws', commands=[shell_mongoc('''
# Compile mongoc-ping. Disable unnecessary dependencies since mongoc-ping is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
# Compile test-awsauth. Disable unnecessary dependencies since test-awsauth is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
. .evergreen/scripts/find-cmake.sh
export CC='${CC}'
$CMAKE -DENABLE_SASL=OFF -DENABLE_SNAPPY=OFF -DENABLE_ZSTD=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=OFF .
$CMAKE --build . --target mongoc-ping
$CMAKE --build . --target test-awsauth
'''), func('upload-build')])

all_tasks = chain(all_tasks, [aws_compile_task])
Expand Down
54 changes: 6 additions & 48 deletions .evergreen/scripts/run-aws-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@
# Test runner for AWS authentication.
#
# This script is meant to be run in parts (so to isolate the AWS tests).
# Pass the desired test first argument (REGULAR, EC2, ECS, ASSUME_ROLE, LAMBDA)
# Pass the desired test as the environment variable TESTCASE: (REGULAR, EC2, ECS, ASSUME_ROLE, LAMBDA)
#
# Example:
# run-aws-tests.sh EC2
# TESTCASE=EC2 run-aws-tests.sh
#
# Optional environment variables:
#
# drivers_tools_dir
# The path to clone of https://github.com/mongodb-labs/drivers-evergreen-tools.
# Defaults to $(pwd)../drivers-evergreen-tools
# mongoc_dir
# The path to the build of mongo-c-driver (e.g. mongo-c-driver/cmake-build).
# Defaults to $(pwd)
# mongoc_dir
# The path to mongo-c-driver source (may be same as mongoc_dir).
# Defaults to $(pwd)
# mongodb_bin_dir
# The path to mongodb binaries.
# Defaults to $(pwd)/mongodb/bin
# iam_auth_ecs_account and iam_auth_ecs_secret_access_key
# Set to access key id/secret access key. Required for some tests.

Expand All @@ -46,49 +33,20 @@ declare drivers_tools_dir
drivers_tools_dir="$(to_absolute "${mongoc_dir}/../drivers-evergreen-tools")"

declare mongodb_bin_dir="${mongoc_dir}/mongodb/bin"
declare mongoc_ping="${mongoc_dir}/src/libmongoc/mongoc-ping"
declare test_awsauth="${mongoc_dir}/src/libmongoc/test-awsauth"

# Add libmongoc-1.0 and libbson-1.0 to library path, so mongoc-ping can find them at runtime.
if [[ "${OSTYPE}" == "cygwin" ]]; then
export PATH
PATH+=":${mongoc_dir}/src/libmongoc/Debug"
PATH+=":${mongoc_dir}/src/libbson/Debug"

chmod -f +x src/libmongoc/Debug/* src/libbson/Debug/* || true

mongoc_ping="${mongoc_dir}/src/libmongoc/Debug/mongoc-ping.exe"
elif [[ "${OSTYPE}" == darwin* ]]; then
export DYLD_LIBRARY_PATH
DYLD_LIBRARY_PATH+=":${mongoc_dir}/src/libmongoc"
DYLD_LIBRARY_PATH+=":${mongoc_dir}/src/libbson"
else
export LD_LIBRARY_PATH
LD_LIBRARY_PATH+=":${mongoc_dir}/src/libmongoc"
LD_LIBRARY_PATH+=":$mongoc_dir/src/libbson"
test_awsauth="${mongoc_dir}/src/libmongoc/Debug/test-awsauth.exe"
fi

expect_success() {
echo "Should succeed:"
if ! "${mongoc_ping}" "${1:?}"; then
echo "Unexpected auth failure" 1>&2
exit 1
fi
"${test_awsauth}" "${1:?}" "EXPECT_SUCCESS" || exit
}

expect_failure() {
echo "Should fail:"
if "${mongoc_ping}" "${1:?}" >output.txt 2>&1; then
echo "Unexpected - authed but it should not have" 1>&2
exit 1
else
echo "auth failed as expected"
fi

if ! grep "Authentication failed" output.txt >/dev/null; then
echo "Unexpected, error was not an authentication failure:" 1>&2
cat output.txt 1>&2
exit 1
fi
"${test_awsauth}" "${1:?}" "EXPECT_FAILURE" || exit
}

url_encode() {
Expand Down
9 changes: 1 addition & 8 deletions .evergreen/scripts/run-mongodb-aws-ecs-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,10 @@

echo "run-mongodb-aws-ecs-test.sh"

# Set paths so mongoc-ping can find dependencies
export LD_LIBRARY_PATH
LD_LIBRARY_PATH+=":/root/mongoc/src/libmongoc"
LD_LIBRARY_PATH+=":/root/mongoc/src/libbson"

expect_success() {
echo "Should succeed:"
if ! /root/mongoc/src/libmongoc/mongoc-ping "${1:?}"; then
echo "Unexpected auth failure" 1>&2
exit 1
fi
/root/mongoc/src/libmongoc/test-awsauth "${1:?}" "EXPECT_SUCCESS"
}

expect_success "${1:?}"
1 change: 1 addition & 0 deletions src/libmongoc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,7 @@ mongoc_add_test (test-mongoc-gssapi FALSE ${PROJECT_SOURCE_DIR}/tests/test-mongo
mongoc_add_test (test-mongoc-cache FALSE ${PROJECT_SOURCE_DIR}/tests/test-mongoc-cache.c)
mongoc_add_test (test-azurekms FALSE ${PROJECT_SOURCE_DIR}/tests/test-azurekms.c)
mongoc_add_test (test-gcpkms FALSE ${PROJECT_SOURCE_DIR}/tests/test-gcpkms.c)
mongoc_add_test (test-awsauth FALSE ${PROJECT_SOURCE_DIR}/tests/test-awsauth.c)

if (ENABLE_TESTS)
# "make test" doesn't compile tests, so we create "make check" which compiles
Expand Down
90 changes: 89 additions & 1 deletion src/libmongoc/src/mongoc/mongoc-cluster-aws-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#define MONGOC_CLUSTER_AWS_PRIVATE_H

#include "bson/bson.h"
#include "mcd-time.h"
#include "mongoc/mongoc-cluster-private.h"
#include "common-thread-private.h" // bson_mutex_t

bool
_mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster,
Expand All @@ -29,18 +31,104 @@ _mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster,
bson_error_t *error);

/* The following are declared in the private header for testing. It is only used
* in test-mongoc-aws.c and mongoc-cluster.aws.c */
* in test-mongoc-aws.c, mongoc-cluster-aws.c, and test-awsauth.c */
typedef struct {
char *access_key_id;
char *secret_access_key;
char *session_token;
// expiration is the time when these credentials expire.
// If expiration.set is false, the credentials do not have a known
// expiration.
struct {
mcd_timer value;
bool set;
} expiration;
} _mongoc_aws_credentials_t;

#define MONGOC_AWS_CREDENTIALS_INIT \
(_mongoc_aws_credentials_t) \
{ \
.access_key_id = NULL, .secret_access_key = NULL, .session_token = NULL, \
.expiration = {.value = {.expire_at = {0}}, .set = false}, \
}

#define MONGOC_AWS_CREDENTIALS_EXPIRATION_WINDOW_MS 60 * 5 * 1000

// _mongoc_aws_credentials_cache_t is a thread-safe global cache of AWS
// credentials.
typedef struct {
struct {
_mongoc_aws_credentials_t value;
bool set;
} cached;
bson_mutex_t mutex; // guards cached.
} _mongoc_aws_credentials_cache_t;

extern _mongoc_aws_credentials_cache_t mongoc_aws_credentials_cache;

// _mongoc_aws_credentials_cache_init initializes the global
// `mongoc_aws_credentials_cache. It is expected to be called by mongoc_init.
void
_mongoc_aws_credentials_cache_init (void);

// _mongoc_aws_credentials_cache_lock exclusively locks the cache.
void
_mongoc_aws_credentials_cache_lock (void);

// _mongoc_aws_credentials_cache_unlock unlocks the cache.
void
_mongoc_aws_credentials_cache_unlock (void);

// _mongoc_aws_credentials_cache_put_nolock is a non-locking variant of
// _mongoc_aws_credentials_cache_put.
void
_mongoc_aws_credentials_cache_put_nolock (
const _mongoc_aws_credentials_t *creds);

// _mongoc_aws_credentials_cache_put adds credentials into the global cache.
void
_mongoc_aws_credentials_cache_put (const _mongoc_aws_credentials_t *creds);

// _mongoc_aws_credentials_cache_get_nolock is a non-locking variant of
// _mongoc_aws_credentials_cache_get.
bool
_mongoc_aws_credentials_cache_get_nolock (_mongoc_aws_credentials_t *creds);

// _mongoc_aws_credentials_cache_get returns true if cached credentials were
// retrieved.
// The passed `creds` is expected to be initialized with
// MONGOC_AWS_CREDENTIALS_INIT. Returns true if there are valid cached
// credentials. Retrieved credentials are copied to `creds`. Callers are
// expected to call
// `_mongoc_aws_credentials_cleanup` on `creds`.
// Returns false and zeroes `creds` if there are no valid cached credentials.
bool
_mongoc_aws_credentials_cache_get (_mongoc_aws_credentials_t *creds);

// _mongoc_aws_credentials_cache_clear_nolock is the non-locking variant of
// _mongoc_aws_credentials_cache_clear
void
_mongoc_aws_credentials_cache_clear_nolock (void);

// _mongoc_aws_credentials_cache_clear clears credentials in the global cache
void
_mongoc_aws_credentials_cache_clear (void);

// _mongoc_aws_credentials_cache_cleanup frees data for the global cache.
// It is expected to be called by mongoc_cleanup.
void
_mongoc_aws_credentials_cache_cleanup (void);


bool
_mongoc_aws_credentials_obtain (mongoc_uri_t *uri,
_mongoc_aws_credentials_t *creds,
bson_error_t *error);

void
_mongoc_aws_credentials_copy_to (const _mongoc_aws_credentials_t *src,
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe it is more conventional to have the dest parameter first.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I plan to keep as is. The src, dst order is consistent with all other C driver functions named *_copy_to.

_mongoc_aws_credentials_t *dst);

void
_mongoc_aws_credentials_cleanup (_mongoc_aws_credentials_t *creds);

Expand Down
Loading