Re-establish AWS Assumerole connection

Hello,

I want to connect my application server to MongoDB Atlas using AWS STS. Currently, I can get it to connect just fine by doing this:

    let url = 'mongodb+srv://{AWS_ACCESS_KEY}:{AWS_SECRET_KEY}' +
                    '@cluster0.blahblah.mongodb.net/mydb?authSource=%24external&authMechanism=MONGODB-AWS' +
                    '&retryWrites=true&w=majority&authMechanismProperties=AWS_SESSION_TOKEN:{AWS_TOKEN}',;

    const ec2IMDCredsProvider = fromInstanceMetadata();
    const { accessKeyId, secretAccessKey, sessionToken } = await ec2IMDCredsProvider();

    url = url.replace('{AWS_ACCESS_KEY}', accessKeyId);
    url = url.replace('{AWS_SECRET_KEY}', encodeURIComponent(secretAccessKey));
    url = url.replace('{AWS_TOKEN}', encodeURIComponent(sessionToken || ''));

After the assumeRole session times out, my application disconnects and I don’t know what hook to use in order to re-invoke ec2 instance metadata service in order to get a new role id/secret/token. The mongodb driver sits there trying and retrying the stale invalid credentials.

My current workaround is to give my servers a short lifespan and have my ASG automatically replace them over and over. This is not a great solution. I’d prefer for my application code to handle reconnecting gracefully. Has anyone done this before?

1 Like

I am having same problem. I am confused how AWS Assumerole can work in current driver implementation (I am using .Net). Credentials provided in string to MongoDB will always expire. And if Mongo Clients try to restablish connection, it will never be possible to authenticate because STS authentication is not possible with expired ACCESS KEY and SECRET. There is no way to provide new key and secret.

Can someone in Mongo help please ?

I am getting below error after some time:

[13:48:21 ERR[] Connection id "0HMCSB6U64G5J", Request id "0HMCSB6U64G5J:00000003": An unhandled exception was thrown by the application.

MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism MONGODB-AWS.

 ---> MongoDB.Driver.MongoCommandException: Command saslContinue failed: Authentication failed..

   at MongoDB.Driver.Core.WireProtocol.CommandUsingQueryMessageWireProtocol`1.ProcessReply(ConnectionId connectionId, ReplyMessage`1 reply)

   at MongoDB.Driver.Core.WireProtocol.CommandUsingQueryMessageWireProtocol`1.ExecuteAsync(IConnection connection, CancellationToken cancellationToken)

   at MongoDB.Driver.Core.Authentication.SaslAuthenticator.AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)

   --- End of inner exception stack trace ---

   at MongoDB.Driver.Core.Connections.BinaryConnection.OpenHelperAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.PooledConnection.OpenAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.ConnectionCreator.CreateOpenedInternalAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.ConnectionCreator.CreateOpenedOrReuseAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.AcquireConnectionHelper.EnteredPoolAsync(Boolean enteredPool, CancellationToken cancellationToken)

   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.AcquireConnectionAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.Servers.Server.GetChannelAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.Operations.RetryableReadContext.InitializeAsync(CancellationToken cancellationToken)

   at MongoDB.Driver.Core.Operations.RetryableReadContext.CreateAsync(IReadBinding binding, Boolean retryRequested, CancellationToken cancellationToken)

   at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)

   at MongoDB.Driver.OperationExecutor.ExecuteReadOperationAsync[TResult[](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken)

   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperationAsync[TResult[](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken)

   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult[](Func`2 funcAsync, CancellationToken cancellationToken)

   at MongoDB.Driver.IAsyncCursorSourceExtensions.FirstOrDefaultAsync[TDocument[](IAsyncCursorSource`1 source, CancellationToken cancellationToken)

   at MongoDbGenericRepository.DataAccess.Read.MongoDbReader.GetOneAsync[TDocument,TKey[](Expression`1 filter, String partitionKey, CancellationToken cancellationToken)

   at MongoDbGenericRepository.ReadOnlyMongoRepository.GetOneAsync[TDocument,TKey[](Expression`1 filter, String partitionKey, CancellationToken cancellationToken)

   at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)

All MongoDB drivers do not implement calling AssumeRole, and therefore cannot “re-AssumeRole” by themselves. Instead, they expect us to provide the temporary credentials directly but do not support refreshing them.
I recommend adding the IAM role of your EC2 instance or ECS Task as a database user directly to the MongoDB Atlas cluster.

Hi Boris, how to reslove the session timeout issue after adding the role of EC2 instance as database user? could you introduce more detail? thanks

Hi!

I want to add a +1 to this thread.

Looks like someone else had the same problem and fixed it themselves for typescript: GitHub - scaleapi/mongodb-auth-aws-improved

And MongoDB fixed it in the java driver: https://jira.mongodb.org/browse/JAVA-4292

It would be great if the official MongoDB librairies all supported it.

1 Like