Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
39cfd11
Clean up AWS and add output file
blink1073 Feb 15, 2025
c94b0bd
fix typo
blink1073 Feb 15, 2025
07078cc
fix path
blink1073 Feb 15, 2025
b6437d3
use export
blink1073 Feb 15, 2025
4851288
fix newline on windows
blink1073 Feb 16, 2025
a81621b
add mongodb uri
blink1073 Feb 17, 2025
3c18960
try with new secret
blink1073 Feb 17, 2025
024b746
Use standard admin
blink1073 Feb 18, 2025
5e44b66
popd
blink1073 Feb 18, 2025
02b5ecf
debug
blink1073 Feb 18, 2025
439940c
fix handling of mongodb_uri
blink1073 Feb 18, 2025
652fc2c
remove debug
blink1073 Feb 18, 2025
b2a1d84
handle quoting
blink1073 Feb 18, 2025
348ddab
fix missing char
blink1073 Feb 18, 2025
0a47818
use new user
blink1073 Feb 18, 2025
45b2b77
add debug
blink1073 Feb 18, 2025
daac114
Merge branch 'master' of github.com:mongodb-labs/drivers-evergreen-to…
blink1073 Feb 18, 2025
b142f39
revert change
blink1073 Feb 18, 2025
9ace3bd
add both users
blink1073 Feb 18, 2025
7e6a996
do not add bob user
blink1073 Feb 18, 2025
2b4df1a
cleanup
blink1073 Feb 19, 2025
a26fb94
fix usage
blink1073 Feb 19, 2025
3fc0801
revert change
blink1073 Feb 19, 2025
f19589a
do not load second user
blink1073 Feb 19, 2025
01f24d4
debug
blink1073 Feb 19, 2025
635489c
debug
blink1073 Feb 19, 2025
396e976
debug
blink1073 Feb 19, 2025
8f4a7e3
debug
blink1073 Feb 19, 2025
f2eaf2d
debug
blink1073 Feb 19, 2025
cbb86b1
debug
blink1073 Feb 19, 2025
d4a0618
debug
blink1073 Feb 19, 2025
5c74dc9
debug
blink1073 Feb 19, 2025
0c41af1
debug
blink1073 Feb 20, 2025
77a245b
undo debug
blink1073 Feb 20, 2025
f3d7ee3
undo unrelated changes
blink1073 Feb 20, 2025
72316b7
Merge branch 'master' of github.com:mongodb-labs/drivers-evergreen-to…
blink1073 Feb 26, 2025
b33d28c
remove test.env
blink1073 Feb 26, 2025
c9049e3
clean up env vars
blink1073 Feb 26, 2025
d9bda56
Merge branch 'master' of github.com:mongodb-labs/drivers-evergreen-to…
blink1073 Feb 26, 2025
4291bd5
undo env removal
blink1073 Feb 27, 2025
47233a0
avoid double quoting
blink1073 Feb 27, 2025
4bb2f40
remove creds
blink1073 Feb 27, 2025
75c9e07
fix aws teardown
blink1073 Feb 27, 2025
927b95b
debug
blink1073 Feb 27, 2025
ca42379
debug
blink1073 Feb 27, 2025
0209b78
debug
blink1073 Feb 27, 2025
b82546c
debug
blink1073 Feb 27, 2025
f47012d
debug
blink1073 Feb 27, 2025
f2378c0
add auth_aws option
blink1073 Mar 2, 2025
ce94638
clean up help
blink1073 Mar 2, 2025
97cfbbb
Merge branch 'master' of github.com:mongodb-labs/drivers-evergreen-to…
blink1073 Mar 4, 2025
852bfcf
address review
blink1073 Mar 4, 2025
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
101 changes: 13 additions & 88 deletions .evergreen/auth_aws/aws_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,108 +6,33 @@
# . ./aws_setup.sh <test-name>
#
# Handles AWS credential setup and exports relevant environment variables.
# Assumes you have already set up secrets.
# Sets up secrets if they have not already been set up.
set -eu

SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})
. $SCRIPT_DIR/../handle-paths.sh
pushd $SCRIPT_DIR

# Ensure that secrets have already been set up.
if [ ! -f "secrets-export.sh" ]; then
echo "ERROR: please run './setup-secrets.sh' in this folder"
fi

# Activate the venv and source the secrets file.
. ./activate-authawsvenv.sh
source secrets-export.sh

if [ "$1" == "web-identity" ]; then
export AWS_WEB_IDENTITY_TOKEN_FILE="./token_file.txt"
fi

# Handle the test setup if not using env variables.
case $1 in
session-creds)
echo "Running aws_tester.py with assume-role"
# Set up credentials with assume-role to create user in MongoDB and write AWS credentials.
python aws_tester.py "assume-role"
;;
env-creds)
echo "Running aws_tester.py with regular"
# Set up credentials with regular to create user in MongoDB and write AWS credentials.
python aws_tester.py "regular"
;;
*)
python aws_tester.py "$1"
;;
esac

# If this is ecs, exit now.
if [ "$1" == "ecs" ]; then
exit 0
# Ensure that secrets have already been set up.
if [ ! -f "./secrets-export.sh" ]; then
bash ./setup-secrets.sh
fi

# Convenience functions.
urlencode () {
python -c "import sys, urllib.parse as ulp; sys.stdout.write(ulp.quote_plus(sys.argv[1]))" "$1"
}
# Remove any AWS creds that might be set in the parent env.
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

jsonkey () {
python -c "import json,sys;sys.stdout.write(json.load(sys.stdin)[sys.argv[1]])" "$1" < ./creds.json
}
source ./secrets-export.sh

# Handle extra vars based on auth type.
USER=""
case $1 in
assume-role)
USER=$(jsonkey AccessKeyId)
USER=$(urlencode "$USER")
PASS=$(jsonkey SecretAccessKey)
PASS=$(urlencode "$PASS")
SESSION_TOKEN=$(jsonkey SessionToken)
SESSION_TOKEN=$(urlencode "$SESSION_TOKEN")
;;

session-creds)
AWS_ACCESS_KEY_ID=$(jsonkey AccessKeyId)
AWS_SECRET_ACCESS_KEY=$(jsonkey SecretAccessKey)
AWS_SESSION_TOKEN=$(jsonkey SessionToken)

export AWS_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY
export AWS_SESSION_TOKEN
;;

web-identity)
export AWS_ROLE_ARN=$IAM_AUTH_ASSUME_WEB_ROLE_NAME
export AWS_WEB_IDENTITY_TOKEN_FILE="$SCRIPT_DIR/$AWS_WEB_IDENTITY_TOKEN_FILE"
;;

regular)
USER=$(urlencode "${IAM_AUTH_ECS_ACCOUNT}")
PASS=$(urlencode "${IAM_AUTH_ECS_SECRET_ACCESS_KEY}")
;;

env-creds)
export AWS_ACCESS_KEY_ID=$IAM_AUTH_ECS_ACCOUNT
export AWS_SECRET_ACCESS_KEY=$IAM_AUTH_ECS_SECRET_ACCESS_KEY
;;
esac

# Handle the URI.
if [ -n "$USER" ]; then
MONGODB_URI="mongodb://$USER:$PASS@localhost"
export USER
export PASS
else
MONGODB_URI="mongodb://localhost"
fi
MONGODB_URI="${MONGODB_URI}/aws?authMechanism=MONGODB-AWS"
if [[ -n ${SESSION_TOKEN:-} ]]; then
MONGODB_URI="${MONGODB_URI}&authMechanismProperties=AWS_SESSION_TOKEN:${SESSION_TOKEN}"
if [ -f $SCRIPT_DIR/test-env.sh ]; then
rm $SCRIPT_DIR/test-env.sh
fi

export MONGODB_URI="$MONGODB_URI"
python aws_tester.py "$1"
source $SCRIPT_DIR/test-env.sh

popd
68 changes: 57 additions & 11 deletions .evergreen/auth_aws/aws_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@

import argparse
import json
import logging
import os
import subprocess
import sys
from functools import partial
from pathlib import Path
from urllib.parse import quote_plus

from pymongo import MongoClient
from pymongo.errors import OperationFailure

HERE = os.path.abspath(os.path.dirname(__file__))
HERE = Path(__file__).absolute().parent
LOGGER = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")


def join(*parts):
return os.path.join(*parts).replace(os.sep, "/")


sys.path.insert(0, join(HERE, "lib"))
sys.path.insert(0, str(HERE / "lib"))
from aws_assign_instance_profile import _assign_instance_policy
from aws_assume_role import _assume_role
from aws_assume_web_role import _assume_role_with_web_identity
Expand All @@ -35,7 +39,7 @@ def join(*parts):
_USE_AWS_SECRETS = False

try:
with open(join(HERE, "aws_e2e_setup.json")) as fid:
with (HERE / "aws_e2e_setup.json").open() as fid:
CONFIG = json.load(fid)
get_key = partial(_get_key, uppercase=False)
except FileNotFoundError:
Expand All @@ -51,7 +55,7 @@ def run(args, env):

def create_user(user, kwargs):
"""Create a user and verify access."""
print("Creating user", user)
LOGGER.info("Creating user %s", user)
client = MongoClient(username="bob", password="pwd123")
db = client["$external"]
try:
Expand All @@ -76,7 +80,7 @@ def setup_assume_role():

role_name = CONFIG[get_key("iam_auth_assume_role_name")]
creds = _assume_role(role_name, quiet=True)
with open(join(HERE, "creds.json"), "w") as fid:
with (HERE / "creds.json").open("w") as fid:
json.dump(creds, fid)

# Create the user.
Expand All @@ -87,6 +91,11 @@ def setup_assume_role():
authmechanismproperties=f"AWS_SESSION_TOKEN:{token}",
)
create_user(ASSUMED_ROLE, kwargs)
return dict(
USER=kwargs["username"],
PASS=kwargs["password"],
SESSION_TOKEN=creds["SessionToken"],
)


def setup_ec2():
Expand All @@ -95,6 +104,7 @@ def setup_ec2():
os.environ.pop("AWS_ACCESS_KEY_ID", None)
os.environ.pop("AWS_SECRET_ACCESS_KEY", None)
create_user(AWS_ACCOUNT_ARN, dict())
return dict()


def setup_ecs():
Expand Down Expand Up @@ -138,6 +148,8 @@ def setup_ecs():
# Run the test in a container
subprocess.check_call(["/bin/sh", "-c", run_test_command], env=env)

return dict()


def setup_regular():
# Create the user.
Expand All @@ -147,6 +159,8 @@ def setup_regular():
)
create_user(CONFIG[get_key("iam_auth_ecs_account_arn")], kwargs)

return dict(USER=kwargs["username"], PASS=kwargs["password"])


def setup_web_identity():
# Unassign the instance profile.
Expand All @@ -161,7 +175,7 @@ def setup_web_identity():
raise RuntimeError("Request limit exceeded for AWS API")

if ret != 0:
print("ret was", ret)
LOGGER.debug("return code was %s", ret)
raise RuntimeError(
"Failed to unassign an instance profile from the current machine"
)
Expand All @@ -186,10 +200,11 @@ def setup_web_identity():

# Assume the web role to get temp credentials.
os.environ["AWS_WEB_IDENTITY_TOKEN_FILE"] = token_file
os.environ["AWS_ROLE_ARN"] = CONFIG[get_key("iam_auth_assume_web_role_name")]
role_arn = CONFIG[get_key("iam_auth_assume_web_role_name")]
os.environ["AWS_ROLE_ARN"] = role_arn

creds = _assume_role_with_web_identity(True)
with open(join(HERE, "creds.json"), "w") as fid:
with (HERE / "creds.json").open("w") as fid:
json.dump(creds, fid)

# Create the user.
Expand All @@ -201,12 +216,37 @@ def setup_web_identity():
)
create_user(ASSUMED_WEB_ROLE, kwargs)

return dict(AWS_WEB_IDENTITY_TOKEN_FILE=token_file, AWS_ROLE_ARN=role_arn)


def handle_creds(creds: dict):
if "USER" in creds:
USER = quote_plus(creds.pop("USER"))
PASS = quote_plus(creds.pop("PASS"))
MONGODB_URI = f"mongodb://{USER}:{PASS}@localhost"
else:
MONGODB_URI = "mongodb://localhost"
MONGODB_URI = f"{MONGODB_URI}/aws?authMechanism=MONGODB-AWS"
if "SESSION_TOKEN" in creds:
SESSION_TOKEN = quote_plus(creds.pop("SESSION_TOKEN"))
MONGODB_URI = (
f"{MONGODB_URI}&authMechanismProperties=AWS_SESSION_TOKEN:{SESSION_TOKEN}"
)
with (HERE / "test-env.sh").open("w", newline="\n") as fid:
fid.write("#!/usr/bin/env bash\n\n")
fid.write("set +x\n")
for key, value in creds.items():
fid.write(f"export {key}={value}\n")
fid.write(f"export MONGODB_URI={MONGODB_URI}\n")


def main():
parser = argparse.ArgumentParser(description="MONGODB-AWS tester.")
sub = parser.add_subparsers(title="Tester subcommands", help="sub-command help")

run_assume_role_cmd = sub.add_parser("assume-role", help="Assume role test")
run_assume_role_cmd = sub.add_parser(
"assume-role", aliases=["session-creds"], help="Assume role test"
)
run_assume_role_cmd.set_defaults(func=setup_assume_role)

run_ec2_cmd = sub.add_parser("ec2", help="EC2 test")
Expand All @@ -215,14 +255,20 @@ def main():
run_ecs_cmd = sub.add_parser("ecs", help="ECS test")
run_ecs_cmd.set_defaults(func=setup_ecs)

run_regular_cmd = sub.add_parser("regular", help="Regular credentials test")
run_regular_cmd = sub.add_parser(
"regular", aliases=["env-creds"], help="Regular credentials test"
)
run_regular_cmd.set_defaults(func=setup_regular)

run_web_identity_cmd = sub.add_parser("web-identity", help="Web identity test")
run_web_identity_cmd.set_defaults(func=setup_web_identity)

args = parser.parse_args()
args.func()
func_name = args.func.__name__.replace("setup_", "")
LOGGER.info("Running aws_tester.py with %s...", func_name)
creds = args.func()
handle_creds(creds)
LOGGER.info("Running aws_tester.py with %s... done.", func_name)


if __name__ == "__main__":
Expand Down
18 changes: 9 additions & 9 deletions .evergreen/auth_aws/lib/aws_assign_instance_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,23 @@ def _get_local_instance_id():
def _has_instance_profile():
base_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
try:
print("Reading: " + base_url)
LOGGER.info("Reading: " + base_url)
iam_role = urllib.request.urlopen(base_url).read().decode()
except urllib.error.HTTPError as e:
print(e)
if e.code == 404:
return False
LOGGER.error(e)
raise e

try:
url = base_url + iam_role
print("Reading: " + url)
LOGGER.info("Reading: " + url)
_ = urllib.request.urlopen(url)
print("Assigned " + iam_role)
LOGGER.info("Assigned " + iam_role)
except urllib.error.HTTPError as e:
print(e)
if e.code == 404:
return False
LOGGER.error(e)
raise e

return True
Expand Down Expand Up @@ -85,7 +85,7 @@ def _handle_config():
)
return CONFIG[get_key("iam_auth_ec2_instance_profile")]
except Exception as e:
print(e)
LOGGER.error(e)
return ""


Expand All @@ -94,7 +94,7 @@ def _handle_config():

def _assign_instance_policy(iam_instance_arn=DEFAULT_ARN):
if _has_instance_profile():
print(
LOGGER.warning(
"IMPORTANT: Found machine already has instance profile, skipping the assignment"
)
return
Expand All @@ -112,14 +112,14 @@ def _assign_instance_policy(iam_instance_arn=DEFAULT_ARN):
InstanceId=instance_id,
)

print(response)
LOGGER.debug(response)

# Wait for the instance profile to be assigned by polling the local instance metadata service
_wait_instance_profile()

except botocore.exceptions.ClientError as ce:
if ce.response["Error"]["Code"] == "RequestLimitExceeded":
print("WARNING: RequestLimitExceeded, exiting with error code 2")
LOGGER.warning("WARNING: RequestLimitExceeded, exiting with error code 2")
sys.exit(2)
raise

Expand Down
Loading
Loading