Ecto, AWS RDS and credentials from the IAM

Hey guys,

I’d like to use Ecto with AWS RDS for my postgresql db, and connect using the credentials I’d get from the IAM (as described here: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.html).

I see that in Ex_AWS.RDS, there’s even a function to get a fresh token (https://hexdocs.pm/ex_aws_rds/ExAws.RDS.html#generate_db_auth_token/4).

Given that a token like this is only valid for 15min, where should I put the code that fetches a new token? I thought about the init/2 callback of Ecto.Repo, but I fear that in case of disconnection/reconnection, the workers would try to use outdated tokens.

Is there a callback that’s run when a worker initiates a connection?

Is there a reason you would rather use the token then a security group?

My understanding is that security groups define which network access are allowed. To my knowledge it has nothing to do with connecting to the DB. Am I missing something?

Oh sorry, I read your OP too quickly. For my RDS DB credentials, I usually just make a new DB user for my elixir application, and do not use the token you referenced.

1 Like

Yeah that’s what I have at the moment. My goal is to avoid to deploy secret keys in EC2 instances

You could use parameter store. Chamber might help with usability.

2 Likes

Hmmmm, not really what I was hoping for, but for now that’ll do. Thanks!

did you found a solution?

The DbConnection.start_link/2 accepts the :configure option, which can be used to run a function before every connection attempt.

You can add the :configure option in your Repo configuration. E.g.

config :your_app, YourApp.Repo,
  username: "postgres",
  password: "postgres",
  database: "test",
  hostname: "localhost",
  configure: {YourApp.Repo, :configure, []}
defmodule YourApp.Repo do
  use Ecto.Repo,
    otp_app: :your_app,
    adapter: Ecto.Adapters.Postgres

  def configure(opts) do
    opts
  end
end

In the configure function you can add the logic to change connection options

3 Likes

You can also use the init method of the Repo. Ecto.Repo — Ecto v3.7.1

defmodule ProductReviewFeed.ProductReviewRepository do
  use Ecto.Repo,
      otp_app: :product_review_feed,
      adapter: Ecto.Adapters.Postgres,
      read_only: true

  def init(_type, config) do
    username = Keyword.fetch!(config, :username)
    hostname = Keyword.fetch!(config, :hostname)
    port = Keyword.fetch!(config, :port)
    region = Application.get_env(:ex_aws, :region)
    token = ExAws.RDS.generate_db_auth_token(
      hostname,
      username,
      port,
      %{:region => region}
    )
    {:ok, Keyword.put(config, :password, token)}
  end
end

There is big difference between configure option and init/2 callback. The difference is when the connection dies for whatever reason during the application runtime. The difference is that init is called once when repo supervisor starts, while configure callback is ran on each connection process restart. If you have short-lived credentials to the DB, then you want to use later, as it will not cause full restarts on random connection process issues.

Thanks for pointing out. Do you have a link to the documentation for this behavior?

Ecto.Repo.init/2

https://hexdocs.pm/ecto/Ecto.Repo.html#c:init/2

A callback executed when the repo starts or when configuration is read.

DBConnection.start_link/2

https://hexdocs.pm/db_connection/DBConnection.html#start_link/2

:configure - A function to run before every connect attempt to dynamically configure the options, either a 1-arity fun, {module, function, args} with options prepended to args or nil where only returned options are passed to connect callback