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

X509 Auth issue for MongoDB Atlas with OTP 26 #226

Closed
suchasurge opened this issue Jan 9, 2024 · 15 comments
Closed

X509 Auth issue for MongoDB Atlas with OTP 26 #226

suchasurge opened this issue Jan 9, 2024 · 15 comments
Assignees

Comments

@suchasurge
Copy link

I just wanted to quickly update to elixir 1.16 and OTP 26 but discovered some Auth issues I haven't seen before.

I use MongoDB Atlas with an X509 certificate which was generated by MongoDB itself.

And I use the currently latest version 1.2.1 of this library.

My config looks like this and is currently working without any problems in elixir 15 / OTP 25:

  config :my_app, :mongo_config,
    name: :my_app,
    appname: "myapp",
    url: "mongodb+srv://default.3kjdjd.mongodb.net",
    username: "CN=my_username",
    password: "",
    database: "my_database",
    timeout: 60_000,
    idle_interval: 10_000,
    queue_target: 5000,
    pool_size: 100,
    auth_mechanism: :x509,
    ssl_opts: [
      certfile: "/path/to/my_cert.pem",
      verify: :verify_none
    ]

I tried the following elixir/erlang combinations:

  • elixir 15 / OTP 25 <- is running in production
  • elixir 15 / OTP 26
  • elixir 16 / OTP 25
  • elixir 16 / OTP 26

The result is that only the combinations with OTP 26 don't work.

With OPT 26, regardless which query I try, I always get:

 iex(1)> Mongo.find_one(:my_app, :my_collection, %{})
 {:error,
  %Mongo.Error{
    message: "command find requires authentication",
    code: 13,
    host: nil,
    fail_command: false,
    error_labels: [],
    resumable: false,
    retryable_reads: false,
    retryable_writes: false,
    not_writable_primary_or_recovering: false,
    error_info: nil
  }}

With OTP 25 and either elixir 15 or 16 I get the data results I expect.

To be sure I also tried the proposed config from the readme and changed the ssl config part to:

ssl: true,
ssl_opts: [
  certfile: "/path/to/my_cert.pem",
  verify: :verify_peer,
  cacertfile: to_charlist(CAStore.file_path()),
  customize_hostname_check: [
    match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
  ]
]

with the same results as mentioned above. So this config didn't fix it.

I saw the OTP 26 adjusted some SSL related things but I cannot spot how and where this breaks stuff in the x509 authentication with MongoDB Atlas.

Did anyone of you have similar problems and/or ideas how to fix it?

Cheers
Frank

@zookzook zookzook self-assigned this Jan 10, 2024
@zookzook
Copy link
Owner

I will take a look at it on the next weekend.

@zookzook
Copy link
Owner

If I use the example from the documentation then everything works as expected:

iex [18:55 :: 1] > {:ok, top} = HelloWorld.connect()
{:ok, #PID<0.234.0>}
iex [18:55 :: 2] > Mongo.show_collections(top) |> Enum.to_list()
["dogs"]
iex [18:55 :: 3] > Mongo.find(top, "dogs", %{}) |> Enum.to_list()
[
  %{"_id" => #BSON.ObjectId<63135a9a4ae06e5cca171679>, "name" => "Tom"},
  %{"_id" => #BSON.ObjectId<63135a954ae06e5ccaa3e990>, "name" => "Greta"}
]

My config is:

def connect() do
    opts = [
      url: "mongodb+srv://cluster0.xxxx.mongodb.net/myFirstDatabase?authSource=%24external&retryWrites=true&w=majority",
      ssl: true,
      username: "CN=cert_user",
      auth_mechanism: :x509,
      ssl_opts: [
        verify: :verify_peer,
        cacerts: :public_key.cacerts_get(),
        certfile: './X509-cert-1577233547801905820.pem',
        customize_hostname_check: [
          match_fun:
            :public_key.pkix_verify_hostname_match_fun(:https)
        ]
      ]
    ]
    Mongo.start_link(opts)
  end

@suchasurge
Copy link
Author

Thanks for trying out.

It's still not working for me with OTP-26.

Even if I use your code snipped with my Atlas credentials. Same error like I described above.

I notice that you are probably using a shared atlas cluster?
Because my url for my dedicated cluster looks like this mongodb+srv://default.XXXX.mongodb.net vs your url mongodb+srv://cluster0.xxxx.mongodb.net.

But not sure if it makes any difference if using a shared vs a dedicated cluster.

Oh, I didn't say that before. I'm using MongoDB v6.

Cheers
Frank

@zookzook
Copy link
Owner

Did you check the firewall? Maybe you can give temporary access to a demo db and I can try it out.

@suchasurge
Copy link
Author

Yes, firewall is fine.
I test this by switching from OTP-26 to OTP-25 (I’m using asdf for this) without changing any code.

With OTP-25 everything works.

I currently don’t have a test db I can give you access to but will look at it when I‘m back at work.

@suchasurge
Copy link
Author

Besides that the ssl verification is somehow broken for me, I'm wondering why

ssl_opts: [ verify: :verify_none ]

doesn`t bring the previous behavior back.

@zookzook
Copy link
Owner

I guess, because you use the X509 auth mechanism which relies on verifying.

@suchasurge
Copy link
Author

I guess, because you use the X509 auth mechanism which relies on verifying.

Using the x509 auth mechanism using ssl_opts: [ verify: :verify_none ] works fine until OTP-26.

With OTP-26 it looks like these verify option does nothing or at least not the same like with OTP-25

@zookzook
Copy link
Owner

Ok...I think, to get some progress it would be to get access to your database or cluster because my example is working.

@suchasurge
Copy link
Author

So I just got a log entry from MongoDB which may give some more insights...

{
  "t":{"$date":"2024-01-15T12:28:57.012+00:00"},
  "s":"I",
  "c":"ACCESS",
  "id":20428,
  "ctx":"conn173745",
  "msg":"Failed to authenticate",
  "attr":{
    "client":"XX.XX.XXX.XXX:36734",
    "mechanism":"MONGODB-X509",
    "user":"CN=myuser",
    "db":"$external",
    "error":{
      "code":18,
      "codeName":"AuthenticationFailed",
      "errmsg":"No verified subject name available from client"
    }
  }
}

Also tried it directly via mongosh whitout problems:

mongosh "mongodb+srv://default.XXXX.mongodb.net/products?authSource=%24external&authMechanism=MONGODB-X509" --apiVersion 1 --tls --tlsCertificateKeyFile "/path/to/my/cert.pem" --eval 'db.runCommand({ping:1})'

{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1705323102, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('AhIUib/WN6jbpdseoeFuRVSxtYbY=', 0),
      keyId: Long('72868480552342391809')
    }
  },
  operationTime: Timestamp({ t: 1705323102, i: 1 })
}

@zookzook
Copy link
Owner

Maybe the subject name is not the right one.

@zookzook
Copy link
Owner

Is CN=myuser correct?

@suchasurge
Copy link
Author

Maybe the subject name is not the right one.

> openssl x509 -in my_cert.pem -inform PEM -subject -nameopt RFC2253

subject=CN=myuser

Ok...I think, to get some progress it would be to get access to your database or cluster because my example is working.

Ok, thx. I need your IP to give you access.

To which e-mail I can send you the pem certificate?

@zookzook
Copy link
Owner

I sent you a message in the elixir forum.

@suchasurge
Copy link
Author

So, to fix my connection issue I needed to add versions: [:"tlsv1.2"] to ssl_opts.

It looks like that mongoDB atlas (on a dedicated cluster) currently doesn't support TLS 1.3.

Thx @zookzook for your help with debugging and pointing me to the solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants