avatarMeta Collective

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4331

Abstract

: Create an IAM role which will allow the RDS proxy to read this secret.</p><p id="f659">You can do that by creating a new IAM role and adding the following permissions</p><div id="72e2"><pre><span class="hljs-punctuation">{</span> <span class="hljs-attr">"Version"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"2012-10-17"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Statement"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"Sid"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"VisualEditor0"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Effect"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Allow"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Action"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"secretsmanager:GetResourcePolicy"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"secretsmanager:GetSecretValue"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"secretsmanager:DescribeSecret"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"secretsmanager:ListSecretVersionIds"</span> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Resource"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"ARN_OF_SECRET_FROM_STEP1"</span> <span class="hljs-punctuation">]</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"Sid"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"VisualEditor1"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Effect"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Allow"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Action"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"secretsmanager:GetRandomPassword"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"secretsmanager:ListSecrets"</span> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Resource"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"*"</span> <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">]</span> <span class="hljs-punctuation">}</span></pre></div><p id="8b0f">Then, add the following trust policy to the role so that the RDS is allowed to assume the role</p><div id="7800"><pre><span class="hljs-punctuation">{</span> <span class="hljs-attr">"Version"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"2012-10-17"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Statement"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"Sid"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">""</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Effect"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Allow"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Principal"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"Service"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"rds.amazonaws.com"</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"Action"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"sts:AssumeRole"</span> <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">]</span> <span class="hljs-punctuation">}</span></pre></div><p id="2b79">N

Options

ow, again take note of the ARN of the newly created role, we will need it when we attach this role to our lambda proxy.</p><p id="5995"><b>Step 3</b>: Add RDS proxy to lambda function</p><p id="065d">head over to Lambda in the AWS console and open the function you wish to attach the lambda with. Then, click on the configuration tab and find database proxies. Click on add database proxy</p><figure id="8350"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*7CmcPAyxcCzuSLaunuXpdQ.png"><figcaption></figcaption></figure><p id="0ca0">here, enter the relevant details from steps 1 and 2 and click add.</p><figure id="c59b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*UkTXPyqyzDv-c7va8ybjFQ.png"><figcaption>add new database proxy</figcaption></figure><p id="155f">Make a note of the proxy endpoint, we will use it to make the connection from our lambda function</p><p id="36f4"><b>Step 4</b>: Adapt your code to use a proxy endpoint to make the connection. the following is a nodeJS example using Sequelize ORM —</p><div id="8edd"><pre><span class="hljs-keyword">import</span> { <span class="hljs-title class_">APIGatewayProxyEvent</span>, <span class="hljs-title class_">APIGatewayProxyResult</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">"aws-lambda"</span>; <span class="hljs-keyword">import</span> { <span class="hljs-title class_">Signer</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/rds-signer"</span>; <span class="hljs-keyword">import</span> { <span class="hljs-title class_">Sequelize</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">"sequelize"</span>;

<span class="hljs-keyword">const</span> signer = <span class="hljs-keyword">new</span> <span class="hljs-variable constant_">RDS</span>.<span class="hljs-title class_">Signer</span>({ <span class="hljs-attr">region</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">REGION</span>, <span class="hljs-attr">hostname</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_PROXY_ENDPOINT</span>, <span class="hljs-attr">port</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_PROXY_PORT</span>, <span class="hljs-attr">username</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_USERNAME</span>, });

<span class="hljs-comment">//Use this sequelize object to perform DB queries</span> <span class="hljs-keyword">const</span> sequelize = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Sequelize</span>({ process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_USERNAME</span>, process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_PROXY_ENDPOINT</span>, process.<span class="hljs-property">env</span>.<span class="hljs-property">DB_PROXY_PORT</span>, <span class="hljs-attr">dialect</span>: <span class="hljs-string">"mysql"</span>, <span class="hljs-attr">dialectOptions</span>: { <span class="hljs-attr">ssl</span>: <span class="hljs-string">"Amazon RDS"</span>, <span class="hljs-attr">authPlugins</span>: { <span class="hljs-attr">mysql_clear_password</span>: <span class="hljs-function">() =></span> <span class="hljs-function">() =></span> signer.<span class="hljs-title function_">getAuthToken</span>(), }, }, });</pre></div><p id="7e16">Thanks for reading and if you like my content and want to support me, then please follow me and help all of us on this platform grow and produce useful content by becoming a member.</p><div id="deea" class="link-block"> <a href="https://medium.com/@metacollective/membership"> <div> <div> <h2>Join Medium with my referral link — Meta Collective</h2> <div><h3>As a Medium member, a portion of your membership fee goes to writers you read, and you get full access to every story…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*ieVyyKI4MJrdkCFG)"></div> </div> </div> </a> </div></article></body>

How to use an RDS proxy to manage connection pools?

Image by Michal Jarmoluk from Pixabay

What is RDS Proxy?

RDS Proxy is a service from AWS which will act as a proxy for RDS services. This managed service from AWS is highly available and helps with increasing the scalability, resilience & security of your applications.

At the time of writing this article, Amazon RDS Proxy is available for Amazon Aurora with MySQL compatibility, Amazon Aurora with PostgreSQL compatibility, Amazon RDS for MariaDB, Amazon RDS for MySQL, Amazon RDS for PostgreSQL, and Amazon RDS for SQL Server.

Why Do I need RDS Proxy?

Consider this simple API design using API Gateway, Lambda & RDS —

Simple API design on AWS

As you can see, the API gateway is passing on requests to Lambda which in turn makes a connection to the RDS, but since this is a serverless architecture, lambda has no way of guaranteeing that it will be able to reuse connections. Hence, each individual request will end up making a new connection. This is inefficient and we will end up hitting the maximum number of connections allowed.

How to determine the maximum number of connections allowed?

This can vary by the type of DB Engine you are using and you can find them here on AWS’s documentation page — https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections

At the moment, this is how the limits on connection look like

RDS Connection limits

So, for example, if you are running a MySql instance on a t2 micro with 1GB RAM the max_connections could be (1024*1024*1024)/12582880 ~= 85. This is not a very scalable setup and will cause performance issues for the end user once it reaches its limit.

How does the RDS proxy solve this problem?

RDS proxy is an AWS service, which will sit in front of the RDS service and manage a connection pool. Our applications (like the Lambda function) will connect to the RDS Proxy service instead of the actual RDS itself, and from there onwards, this Proxy service will manage the connections via the connection pool.

Some of the core benefits of using proxy service are —

  • Connection shares between various request calls will reduce stresses on the CPU & Memory
  • Higher availability of services
  • Increase in efficiency
  • Better control of authentication by managing DB credentials via AWS’s secret manager

How to implement RDS Proxy?

Step 1: Create a new secret to store credentials for your RDS database

Log into AWS, and create a new secret for your RDS database

create a new secret

Make sure that you select the correct database from the list

Make a note of the Secret ARN, we will need it in our next step

Step 2: Create an IAM role which will allow the RDS proxy to read this secret.

You can do that by creating a new IAM role and adding the following permissions

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": [
        "ARN_OF_SECRET_FROM_STEP1"
      ]
    },
    {
      "Sid": "VisualEditor1",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetRandomPassword",
        "secretsmanager:ListSecrets"
      ],
      "Resource": "*"
    }
  ]
}

Then, add the following trust policy to the role so that the RDS is allowed to assume the role

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "",
   "Effect": "Allow",
   "Principal": {
    "Service": "rds.amazonaws.com"
   },
   "Action": "sts:AssumeRole"
  }
 ]
}

Now, again take note of the ARN of the newly created role, we will need it when we attach this role to our lambda proxy.

Step 3: Add RDS proxy to lambda function

head over to Lambda in the AWS console and open the function you wish to attach the lambda with. Then, click on the configuration tab and find database proxies. Click on add database proxy

here, enter the relevant details from steps 1 and 2 and click add.

add new database proxy

Make a note of the proxy endpoint, we will use it to make the connection from our lambda function

Step 4: Adapt your code to use a proxy endpoint to make the connection. the following is a nodeJS example using Sequelize ORM —

import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { Signer } from "@aws-sdk/rds-signer";
import { Sequelize } from "sequelize";

const signer = new RDS.Signer({
  region: process.env.REGION,
  hostname: process.env.DB_PROXY_ENDPOINT,
  port: process.env.DB_PROXY_PORT,
  username: process.env.DB_USERNAME,
});

//Use this sequelize object to perform DB queries
const sequelize = new Sequelize({
  process.env.DB_USERNAME,
  process.env.DB_PROXY_ENDPOINT,
  process.env.DB_PROXY_PORT,
  dialect: "mysql",
  dialectOptions: {
    ssl: "Amazon RDS",
    authPlugins: {
      mysql_clear_password: () => () => signer.getAuthToken(),
    },
  },
});

Thanks for reading and if you like my content and want to support me, then please follow me and help all of us on this platform grow and produce useful content by becoming a member.

AWS
Rds Proxy
Cloud Computing
Serverless
Lambda
Recommended from ReadMedium