<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="">
  <title></title>
  <subtitle></subtitle>
  <link href="/feed.xml" rel="self"/>
  <link href="/"/>
  <updated>2023-11-25T00:00:00Z</updated>
  <id>/</id>
  <author>
    <name></name>
    <email></email>
  </author>
  <entry>
    <title>IAM Role Authentication for Postgres RDS using Python and Go</title>
    <link href="/blog/iam-role-authentication-postgres-rds/"/>
    <updated>2021-12-28T00:00:00Z</updated>
    <id>/blog/iam-role-authentication-postgres-rds/</id>
    <content type="html"><![CDATA[<p>In this article I will be discussing how to connect to Postgres RDS from <a href="https://www.python.org/">Python</a> using <a href="https://www.djangoproject.com/">Django</a> and also using <a href="https://go.dev/">Go</a> when using IAM authentication.</p>
<p>AWS supports IAM Roles to authenticate with RDS instead of conventional username password. We can create IAM policies for RDS and attach it to an EC2 instance and the EC2 will be able to connect with RDS using an IAM token instead of the password. In this article we will talk about how to periodically refresh the token when using <code>pgx</code> as the <code>postgres</code> driver in <code>go</code>. Or how to use/refresh IAM tokens when using <code>django</code> and <code>python</code>.</p>
<p>In this blog I will not go into the details of creating and attaching an IAM role/policy, there are a lot of <a href="https://aws.amazon.com/premiumsupport/knowledge-center/users-connect-rds-iam/">resources</a> available for this.</p>
<h2 id="what-is-iam-role-and-iam-token" tabindex="-1"><a class="header-anchor" href="#what-is-iam-role-and-iam-token">What is IAM role and IAM token</a></h2>
<p>With IAM database authentication, you use an authentication token when you connect to your DB instance. An authentication token is a string of characters that you use instead of a password. After you generate an authentication token, it's valid for 15 minutes before it expires. If you try to connect using an expired token, the connection request is denied.</p>
<p>Network traffic to and from the database is encrypted using Transport Layer Security (TLS).</p>
<p>Using this authentication we can avoid keeping the password in the code/config. The AWS SDK will programmatically create and sign an authentication token.</p>
<h2 id="how-does-the-iam-token-work" tabindex="-1"><a class="header-anchor" href="#how-does-the-iam-token-work">How does the IAM token work</a></h2>
<p>The AWS SDK for <code>go</code> in case of <code>Golang</code> or <code>boto3</code> in case of <code>Python</code> is used to generate a new token every time a db connection needs to be made. Important thing to note is that the <strong>token is generated on the client side</strong>. No network call is made to <em>fetch</em> the token from AWS. So it is completely okay to generate a new token every time a new connection is made.</p>
<p>How this is achieved is using AWS's <a href="https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html">Signature v4 signing process</a>. AWS SDK signs the token with the access key ID and the secret access key.</p>
<p>We use this token to connect to Postgres instead of the password.</p>
<h2 id="how-can-this-be-used-to-connect-to-postgres-in-go-python" tabindex="-1"><a class="header-anchor" href="#how-can-this-be-used-to-connect-to-postgres-in-go-python">How can this be used to connect to Postgres in go/python</a></h2>
<p>AWS has quite good <a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.Go.html">documentation</a> for connecting with Postgres/RDS using IAM tokens instead of passwords in <code>go</code> as well as in <code>python</code>. But when I was trying to implement this, the problem I faced was that we used client side <a href="https://github.com/jackc/pgx">database pools</a>. It would be fair to assume that most real-world production systems leverage pooling.</p>
<h3 id="database-pooling" tabindex="-1"><a class="header-anchor" href="#database-pooling">Database Pooling</a></h3>
<p><a href="https://en.wikipedia.org/wiki/Connection_pool">Database connection pooling</a> is a method used to keep database connections open so they can be reused by others.</p>
<p>Typically, opening a database connection is an expensive operation. You have to open up network sessions, authenticate and so on. Pooling keeps the connections active so that, when a connection is later requested, one of the active ones is used in preference to having to create another one.</p>
<p>Now this adds an additional layer of complexity. The pools are created lazily. That means if a pool has 50 connections, all the connections are not stood up when the app starts, the connections are added to the pool as and when queries/transactions arrive. Now if we were to reuse the IAM token, we would have to keep track of them. So we would need a timer to refresh the token every 15 mins. But we cannot really close the connections within a pool as these are self-managing pools. So we would have to close the pools and re-initialize everything again. You can see where I am going with this. This approach seems very hacky and is not elegant.</p>
<h3 id="go-implementation" tabindex="-1"><a class="header-anchor" href="#go-implementation"><code>Go</code> implementation</a></h3>
<p>Fortunately <a href="https://github.com/jackc/pgx/issues/676"><code>pgx</code> has recently added</a> a <code>BeforeConnect</code> hook to its API. We can use this hook to modify the db credentials before any connection is made. This way every connection in the pool will have its own IAM token and as established earlier, tokens are created on the client side so there is no network call to &quot;fetch&quot; the token.</p>
<p>But how do we refresh the token after 15 mins? We don't! We can set the connection lifetime to 14 mins, so the connection is closed after 14 mins and the new connection that comes up, is created using a new token. This way we can inject our token for every connection. This approach also works because we are not closing the complete pool, we only close one connection at a time (because the connection lifetime is per connection). And because each connection is established lazily and has its own token, the connections are created and closed at different times, so the pool should always have some connections for use.</p>
<pre class="language-go"><code class="language-go"><span class="token comment">// peer contains the connection pool</span>
<span class="token comment">// IAMRoleAuth is the flag to toggle IAM role based authentication</span>
<span class="token keyword">type</span> peer <span class="token keyword">struct</span> <span class="token punctuation">{</span>
	name        <span class="token builtin">string</span>
	dbPool      <span class="token operator">*</span>pgxpool<span class="token punctuation">.</span>Pool
	weight      <span class="token builtin">int</span>
	logger      log<span class="token punctuation">.</span>Logger
	mu          sync<span class="token punctuation">.</span>Mutex
	IAMRoleAuth <span class="token builtin">bool</span>
<span class="token punctuation">}</span>

<span class="token keyword">type</span> DBConfig <span class="token keyword">struct</span> <span class="token punctuation">{</span>
	Host        <span class="token builtin">string</span>
	Port        <span class="token builtin">int</span>
	User        <span class="token builtin">string</span>
	Password    <span class="token builtin">string</span>
	SSLMode     <span class="token builtin">string</span>
	Name        <span class="token builtin">string</span>
	MinConn     <span class="token builtin">int</span>
	MaxConn     <span class="token builtin">int</span>
	LifeTime    <span class="token builtin">string</span>
	IdleTime    <span class="token builtin">string</span>
	LogLevel    <span class="token builtin">string</span>
	Region      <span class="token builtin">string</span>
	IAMRoleAuth <span class="token builtin">bool</span>
<span class="token punctuation">}</span></code></pre>
<p>We create a <code>session</code> struct, and pass this on to create a new IAM token.</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">import</span> <span class="token string">"github.com/aws/aws-sdk-go/aws/session"</span>

opts <span class="token operator">:=</span> session<span class="token punctuation">.</span>Options<span class="token punctuation">{</span>Config<span class="token punctuation">:</span> aws<span class="token punctuation">.</span>Config<span class="token punctuation">{</span>
		CredentialsChainVerboseErrors<span class="token punctuation">:</span> aws<span class="token punctuation">.</span><span class="token function">Bool</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
		Region<span class="token punctuation">:</span>                        aws<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token string">"us-east-1"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
		MaxRetries<span class="token punctuation">:</span>                    aws<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">}</span>
sess <span class="token operator">:=</span> session<span class="token punctuation">.</span><span class="token function">Must</span><span class="token punctuation">(</span>session<span class="token punctuation">.</span><span class="token function">NewSessionWithOptions</span><span class="token punctuation">(</span>opts<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<pre class="language-go"><code class="language-go"><span class="token comment">// getDBPool returns a new pgxpool.Pool instance.</span>
<span class="token comment">// If peer IAMRoleAuth is true then BeforeConnect method is implemented</span>
<span class="token comment">// BeforeConnect() is used to inject the authToken before a connection is made.</span>
<span class="token comment">// Connection `LifeTime` is set to 14 mins, hence the connection will expire </span>
<span class="token comment">// automatically and no intervention is needed to close the connection.</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>p <span class="token operator">*</span>peer<span class="token punctuation">)</span> <span class="token function">getDBPool</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> cfg DBConfig<span class="token punctuation">,</span> sess <span class="token operator">*</span>session<span class="token punctuation">.</span>Session<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>pgxpool<span class="token punctuation">.</span>Pool<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

	poolCfg<span class="token punctuation">,</span> err <span class="token operator">:=</span> pgxpool<span class="token punctuation">.</span><span class="token function">ParseConfig</span><span class="token punctuation">(</span><span class="token function">getDBURL</span><span class="token punctuation">(</span>cfg<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		p<span class="token punctuation">.</span>logger<span class="token punctuation">.</span><span class="token function">Err</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Msgf</span><span class="token punctuation">(</span><span class="token string">"unable to parse config for peer: %v cfg: %v"</span><span class="token punctuation">,</span> cfg<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> cfg<span class="token punctuation">)</span>
		<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	<span class="token keyword">if</span> p<span class="token punctuation">.</span>IAMRoleAuth <span class="token punctuation">{</span>
		poolCfg<span class="token punctuation">.</span>BeforeConnect <span class="token operator">=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> config <span class="token operator">*</span>pgx<span class="token punctuation">.</span>ConnConfig<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
			p<span class="token punctuation">.</span>logger<span class="token punctuation">.</span><span class="token function">Info</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Msg</span><span class="token punctuation">(</span><span class="token string">"RDS Credential beforeConnect(), creating new credential"</span><span class="token punctuation">)</span>
			newPassword<span class="token punctuation">,</span> err <span class="token operator">:=</span> p<span class="token punctuation">.</span><span class="token function">getCredential</span><span class="token punctuation">(</span>poolCfg<span class="token punctuation">,</span> cfg<span class="token punctuation">,</span> sess<span class="token punctuation">)</span>
			<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
				<span class="token keyword">return</span> err
			<span class="token punctuation">}</span>
			p<span class="token punctuation">.</span>mu<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
			config<span class="token punctuation">.</span>Password <span class="token operator">=</span> newPassword
			p<span class="token punctuation">.</span>mu<span class="token punctuation">.</span><span class="token function">Unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
			<span class="token keyword">return</span> <span class="token boolean">nil</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>

	pool<span class="token punctuation">,</span> err <span class="token operator">:=</span> pgxpool<span class="token punctuation">.</span><span class="token function">ConnectConfig</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> poolCfg<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		p<span class="token punctuation">.</span>logger<span class="token punctuation">.</span><span class="token function">Err</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Msg</span><span class="token punctuation">(</span><span class="token string">"unable to connect to db"</span><span class="token punctuation">)</span>
		<span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>

	<span class="token keyword">return</span> pool<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token comment">// getCredential returns the new password to connect to RDS</span>
<span class="token keyword">func</span> <span class="token punctuation">(</span>p <span class="token operator">*</span>peer<span class="token punctuation">)</span> <span class="token function">getCredential</span><span class="token punctuation">(</span>poolCfg <span class="token operator">*</span>pgxpool<span class="token punctuation">.</span>Config<span class="token punctuation">,</span> cfg DBConfig<span class="token punctuation">,</span> sess <span class="token operator">*</span>session<span class="token punctuation">.</span>Session<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	dbEndpoint <span class="token operator">:=</span> fmt<span class="token punctuation">.</span><span class="token function">Sprintf</span><span class="token punctuation">(</span><span class="token string">"%s:%d"</span><span class="token punctuation">,</span> poolCfg<span class="token punctuation">.</span>ConnConfig<span class="token punctuation">.</span>Host<span class="token punctuation">,</span> poolCfg<span class="token punctuation">.</span>ConnConfig<span class="token punctuation">.</span>Port<span class="token punctuation">)</span>
	awsRegion <span class="token operator">:=</span> cfg<span class="token punctuation">.</span>Region
	dbUser <span class="token operator">:=</span> poolCfg<span class="token punctuation">.</span>ConnConfig<span class="token punctuation">.</span>User
	authToken<span class="token punctuation">,</span> err <span class="token operator">:=</span> rdsutils<span class="token punctuation">.</span><span class="token function">BuildAuthToken</span><span class="token punctuation">(</span>dbEndpoint<span class="token punctuation">,</span> awsRegion<span class="token punctuation">,</span> dbUser<span class="token punctuation">,</span> sess<span class="token punctuation">.</span>Config<span class="token punctuation">.</span>Credentials<span class="token punctuation">)</span>
	<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
		p<span class="token punctuation">.</span>logger<span class="token punctuation">.</span><span class="token function">Panic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Err</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Msg</span><span class="token punctuation">(</span><span class="token string">"Error in building auth token to connect with RDS"</span><span class="token punctuation">)</span>
		<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">,</span> err
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> authToken<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span></code></pre>
<p>If you are using <a href="https://github.com/jmoiron/sqlx"><code>sqlx</code></a> as the DB driver, then things get trickier. As <code>sqlx</code> does not provide the <code>BeforeConnect()</code> hook to inject the token. I have not found any elegant way to do this with <code>sqlx</code> yet.</p>
<h3 id="django-implementation" tabindex="-1"><a class="header-anchor" href="#django-implementation"><code>Django</code> implementation</a></h3>
<p><a href="https://www.djangoproject.com/">Django</a> is a very popular web framework in python.</p>
<p>Unlike the <code>go</code> implementation, <code>django</code> does not use database pools, instead <code>django</code> uses <a href="https://docs.djangoproject.com/en/4.0/ref/databases/#persistent-connections">persistent connections</a>. This is different from pooling because <code>django</code> maintains one persistent connection per thread. In pooling, the pool takes care of opening and closing connections and every thread that needs a connection requests one from the pool.</p>
<p><code>django</code> uses <code>postgres</code> database backend which internally uses <a href="https://www.psycopg.org/"><code>Psycopg</code></a> as the database adapter. We can create our custom database backend by extending the <code>postgres</code> backend.</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">def</span> <span class="token function">get_aws_connection_params</span><span class="token punctuation">(</span>params<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token triple-quoted-string string">"""
    "rds_iam_auth" : If set to `True` IAM authentication is used, 
                     else password based authentication is used
    "region_name" : Contains the name of the aws region where DB is present.

    Parameters
    ----------
        params : dict
            The DATABASES dict that is passed from the settings.py
    """</span>
    enabled <span class="token operator">=</span> params<span class="token punctuation">.</span>pop<span class="token punctuation">(</span><span class="token string">"rds_iam_auth"</span><span class="token punctuation">,</span> <span class="token boolean">False</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> enabled<span class="token punctuation">:</span>
        region_name <span class="token operator">=</span> params<span class="token punctuation">.</span>pop<span class="token punctuation">(</span><span class="token string">"region_name"</span><span class="token punctuation">,</span> <span class="token boolean">None</span><span class="token punctuation">)</span>
        rds_client <span class="token operator">=</span> boto3<span class="token punctuation">.</span>client<span class="token punctuation">(</span>service_name<span class="token operator">=</span><span class="token string">"rds"</span><span class="token punctuation">,</span> region_name<span class="token operator">=</span>region_name<span class="token punctuation">)</span>

        hostname <span class="token operator">=</span> params<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"host"</span><span class="token punctuation">)</span>
        hostname <span class="token operator">=</span> hostname <span class="token keyword">if</span> hostname <span class="token keyword">else</span> <span class="token string">"localhost"</span>

        params<span class="token punctuation">[</span><span class="token string">"password"</span><span class="token punctuation">]</span> <span class="token operator">=</span> rds_client<span class="token punctuation">.</span>generate_db_auth_token<span class="token punctuation">(</span>
            DBHostname<span class="token operator">=</span>hostname<span class="token punctuation">,</span>
            Port<span class="token operator">=</span>params<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"port"</span><span class="token punctuation">,</span> <span class="token number">5432</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            DBUsername<span class="token operator">=</span>params<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> getpass<span class="token punctuation">.</span>getuser<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">)</span>

    <span class="token keyword">return</span> params

<span class="token keyword">class</span> <span class="token class-name">DatabaseWrapper</span><span class="token punctuation">(</span>base<span class="token punctuation">.</span>DatabaseWrapper<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">get_connection_params</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
        params <span class="token operator">=</span> <span class="token builtin">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>get_connection_params<span class="token punctuation">(</span><span class="token punctuation">)</span>
        params<span class="token punctuation">.</span>setdefault<span class="token punctuation">(</span><span class="token string">"port"</span><span class="token punctuation">,</span> <span class="token number">5432</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> get_aws_connection_params<span class="token punctuation">(</span>params<span class="token punctuation">)</span></code></pre>
<p>In the <code>settings.py</code> we can use this backend as:</p>
<pre class="language-python"><code class="language-python">DATABASES <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token string">"default"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"ENGINE"</span><span class="token punctuation">:</span> <span class="token string">"path.to.backend.aws.postgres"</span><span class="token punctuation">,</span>
        <span class="token string">"NAME"</span><span class="token punctuation">:</span> <span class="token string">"postgres"</span><span class="token punctuation">,</span>
        <span class="token string">"USER"</span><span class="token punctuation">:</span> <span class="token string">"user"</span><span class="token punctuation">,</span>
        <span class="token string">"PASSWORD"</span><span class="token punctuation">:</span> <span class="token string">"welcome"</span><span class="token punctuation">,</span>
        <span class="token string">"HOST"</span><span class="token punctuation">:</span> <span class="token string">"localhost"</span><span class="token punctuation">,</span>
        <span class="token string">"PORT"</span><span class="token punctuation">:</span> <span class="token string">"5432"</span><span class="token punctuation">,</span>
        <span class="token string">"OPTIONS"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
            <span class="token string">"rds_iam_auth"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span>
            <span class="token string">"region_name"</span><span class="token punctuation">:</span> <span class="token string">"us-east-1"</span><span class="token punctuation">,</span>
            <span class="token string">"sslmode"</span><span class="token punctuation">:</span> <span class="token string">"verify-full"</span><span class="token punctuation">,</span>
            <span class="token string">"sslrootcert"</span><span class="token punctuation">:</span> <span class="token string">"/path/to/rds-ca-2019-root.pem"</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Another thing to note in both the above approaches, is that the hostname needs to be used to connect with the RDS PostgreSQL, if a <code>DNS</code> <code>CNAME</code> is used, the connection will fail with PEM authentication error.</strong> This happens because the IAM token is signed for the <code>CNAME</code>, but RDS expects the <code>hostname</code>. One work-around is to resolve the CNAME into the hostname in the custom backend, before making the connection. I would advise against this, because CNAMEs are cached at multiple places and have a certain TTL, the connection would fail if the CNAME has not propagated yet.</p>
<h2 id="references" tabindex="-1"><a class="header-anchor" href="#references">References</a></h2>
<ul>
<li><a href="https://stackoverflow.com/questions/4041114/what-is-database-pooling">What is database pooling</a></li>
<li><a href="https://github.com/labd/django-iam-dbauth">django-iam-dbauth</a></li>
<li>Included inline hyperlinks to most sources.</li>
</ul>
]]></content>
    <category term="technical"/>
  </entry>
  <entry>
    <title>My Experience Buying a Term Insurance</title>
    <link href="/blog/buying-term-insurance/"/>
    <updated>2022-01-20T00:00:00Z</updated>
    <id>/blog/buying-term-insurance/</id>
    <content type="html"><![CDATA[<p>So recently I set out to buy a new term insurance plan for myself. A term insurance is necessary to protect ones dependents in case of death. You do not want to transfer your financial burdens on your dependents.</p>
<p>A term insurance is a very simple insurance where a person is insured for a &quot;term&quot; (say 30 years). You are required to pay the premium for this duration. During the term if you pass away, then your nominee receives the covered sum. However if at the end of the term if you are still alive, you don't get back anything. The premiums of these insurance policies are lower if you purchase them at a relatively young age. The premiums are fixed throughout the term of the policy, so it makes sense to buy these when young.</p>
<p>There are some people with another school of thought who say that you should get a term insurance only after you have dependents. This is also okay, but I personally would recommend getting one as soon as possible.</p>
<p>Now why term insurance is the right insurance for most people and how keeping your investments and insurances separate is the right thing to do is a discussion for a separate article. If you proceed to read further I assume you know why a term insurance is better than a ULIP.</p>
<p>In this article I will talk about how I purchased my term insurance and what are the things one needs to look out for.</p>
<h2 id="step-1-plan" tabindex="-1"><a class="header-anchor" href="#step-1-plan">Step 1 - Plan</a></h2>
<p>It is usually recommended that the policy cover should be 10-20x your annual salary. I personally agree with this, the rationale behind this is that in the event of your death your family must be able to maintain their current lifestyle for the next 10-20 years. We also need to understand what &quot;term&quot; we want our insurance for. The idea is simple, we want the insurance till the time we are earning and we have dependents. So for most people I believe that would be the age of 58-60. By then most people would retire and their children would be self sufficient. There is no point of having an insurance if you aren't working and don't have any dependents.</p>
<p>Insurance plans also come with a load of riders like, Critical Illness Rider and Accidental Death Rider and a few others. In my opinion one should opt for a vanilla insurance as most of these riders are useless. Because we should have a separate health insurance for these things anyway.</p>
<h2 id="step-2-research" tabindex="-1"><a class="header-anchor" href="#step-2-research">Step 2 - Research</a></h2>
<p>For this, I just used <a href="http://policybazaar.com">policybazaar.com</a>. It gives an easy way to look at the estimated premiums and claim settlement ratios etc on a single page. You can filter and sort based on the parameters important to you. While buying my policy I observed that most of the companies have claim settlement ratios etc greater than 97-98%. But one thing to keep in mind is that these claim settlement ratios are for all their insurance policies, which include ULIPs etc which are usually for low amounts. An insurance company can very easily approve 99 ULIPs with a cover of 5 lakh and reject 1 term insurance with a cover of 20 crore. As of now there really is no published data to look into this.</p>
<p>But the bottom line is that you can go with any major insurance company as you don't want your nominee to go through trouble if they ever need to file for a claim. In my case I chose ICICI Prudential. I chose my term of 38 years and looked at the premium and other policy details. Policy bazaar said that there would be a &quot;Tele medical&quot; before this policy was issued.</p>
<p>I had seen many reviews of policy bazaar saying that it was taking longer time to issue a policy through policy bazaar than buying directly from the company. So I decided to purchase directly from ICICI Pru.</p>
<h2 id="step-3-buying-the-policy" tabindex="-1"><a class="header-anchor" href="#step-3-buying-the-policy">Step 3 - Buying the policy</a></h2>
<p>I created an account on the insurer's website, filled the required details. Needless to say, don't lie on your forms as your claim might get rejected. It is fine to pay some extra premium but don't hide any medical history. For the insurance I would recommend just paying the premiums annually, against opting for any kind of limited pay. I paid the premium online. Yes, I paid the premium before the medical was done. It is possible that if there are some issues in the medical report, you might have to pay the extra premium. At this stage I was told that tele medical is not available so there will be a physical medical and sample will be collected from home.</p>
<h2 id="step-4-medical-tests" tabindex="-1"><a class="header-anchor" href="#step-4-medical-tests">Step 4 - Medical Tests</a></h2>
<p>I received a message from the medical partners of ICICI where I was asked to choose a time slot for the medical test. Here when I input my address I was prompted that home collection is not available in this area. This was very weird because I live in a very well known locality in North Bangalore. Since I had already paid the premium, I decided to go ahead with the medical. The lab was just 5 minutes from my house.</p>
<p>I went in at the selected time, everything was very smooth. I gave all my samples.</p>
<p>Within 48 hours, ICICI sent me the reports which is a great thing, because I've heard that many insurers don't send the medical reports back to the customers.</p>
<h2 id="step-5-issuance-of-the-policy" tabindex="-1"><a class="header-anchor" href="#step-5-issuance-of-the-policy">Step 5 - Issuance of the policy</a></h2>
<p>Within 2 days after receiving my medical reports, I was issued the policy. I received the policy documents over email on the same day. And within 14 days I received the physical policy documents. I was able to login to their website using my email and could verify that all the details were correct.</p>
<h2 id="summary" tabindex="-1"><a class="header-anchor" href="#summary">Summary</a></h2>
<p>All in all the process was not very difficult, having said that, it wasn't the easiest. Tele medical or home sample collection would've been great. If you don't have a term insurance yet, I'd suggest you get one sooner rather than later.</p>
<p>Everything mentioned in this article is my opinion and is from personal experience, your mileage may vary.</p>
<p>If you'd like to know more, do check out:</p>
<ol>
<li><a href="https://www.indiainvestments.wiki/start-here/insurance-policies/life/term-insurance">What is Life Insurance</a></li>
<li><a href="https://www.youtube.com/watch?v=aTQUB_1jREg">How to choose a term insurance</a></li>
</ol>
]]></content>
    <category term="opinions"/>
  </entry>
  <entry>
    <title>How to Excel in your First Job as a Software Engineer</title>
    <link href="/blog/how-to-excel-first-job-software-engineer/"/>
    <updated>2022-02-15T00:00:00Z</updated>
    <id>/blog/how-to-excel-first-job-software-engineer/</id>
    <content type="html"><![CDATA[<p>Doing well in Software Development is not just about writing the most code in the least amount of time. Working in an engineering team is quite different from what most students are used to in their university maybe working alone, or working in small teams of 2-3. This post is aimed mostly at students who are in their final/pre-final year of university and will soon be entering their first job as a Software Engineer or an intern.</p>
<p>When I started working as an intern, I had the luxury of meeting people physically, going on team lunches etc. I could just walk over to someone if I had a question. These things really helped me build very good working relationship with my teammates, manager etc. However, with most offices still closed and most job opportunities becoming remote, it becomes all the more important to reach out and seek for help/feedback and make personal connections with your colleagues.</p>
<p>This article is based on my experience over the past 3 years, most things on here are just my opinion and its totally okay if you don't agree.</p>
<p>When transitioning away from academics one needs to understand the paradigm shift. Some things which were important in university are not very important anymore, while some other things like readability of code are the most important thing. Because of this, a lot of students struggle transitioning from academia to industry. In my experience the best students don't always make the best engineers. Students are typically used to working alone and are not used to taking feedback. In most universities the projects are delivered at once and students are not used to working on massive projects and making incremental progress.</p>
<h2 id="8-ways-to-become-a-better-engineer" tabindex="-1"><a class="header-anchor" href="#8-ways-to-become-a-better-engineer">8 ways to become a better engineer</a></h2>
<h3 id="take-initiative" tabindex="-1"><a class="header-anchor" href="#take-initiative">Take initiative</a></h3>
<p>Don't be afraid of taking initiative. Volunteer for new projects, volunteer if anyone needs some help. This will open up new opportunities for learning. It is okay if you don't know how to do something, you can always learn.</p>
<h3 id="participate-in-technical-discussions" tabindex="-1"><a class="header-anchor" href="#participate-in-technical-discussions">Participate in technical discussions</a></h3>
<p>I have seen most interns/junior engineers don't participate in technical discussions. I believe the reason for this is that they believe that they are not good enough and don't want to sound stupid. But you need to not worry about sounding stupid and if you have a question or a suggestion, you should almost always speak up.</p>
<p>NO ONE will judge you for not knowing something. However please don't ask something just for the sake of asking, that is just annoying.</p>
<h3 id="take-ownership" tabindex="-1"><a class="header-anchor" href="#take-ownership">Take ownership</a></h3>
<p>Taking ownership means that you will complete your assigned task from start to finish. You will ensure that you communicate with your team and the respective stakeholders in case there is any blocker or to keep everyone up to date on the status of the work, so that you reduce the risk of not getting your task done in time. This is something that junior engineers actively need to work on.</p>
<p>I have seen so many juniors who when given some task, just vanish and go into a cocoon for several weeks and come back after a few weeks having completed the work, or to tell that they are stuck with a problem. Taking ownership means that you need to show incremental progress and seek for feedback periodically. This will also help you develop trust with other team members as people will know what you are actively working on.</p>
<p>I cannot remember where I had read &quot;If your manager cannot trust you, it doesn't matter how smart you are&quot;. This makes complete sense, you need to build trust with your co-workers. You need to ensure that people don't have to follow up with you again and again.</p>
<h3 id="communicate-clearly" tabindex="-1"><a class="header-anchor" href="#communicate-clearly">Communicate clearly</a></h3>
<p>If you need something say it. If you need technical guidance, speak up. If there is something in your personal life that is taking up your time, it might make sense to share relevant information with your manager so that expectations can be set accordingly. If you have concerns regarding your promotion or your compensation, you should be able to talk to your manager about these things. Clear communication is very important.</p>
<h3 id="growth-mindset" tabindex="-1"><a class="header-anchor" href="#growth-mindset">Growth mindset</a></h3>
<p>A lot of junior engineers that I talk to, say things like &quot;I'm not good at front-end&quot; or &quot;I don't know about XYZ&quot;. Well, that might be true for the moment, but you can always learn whatever you don't know. Most people don't know most things. It is more important to be open to learning. Learning new things itself is a skill. This brings me to my next point.</p>
<h3 id="learn-to-learn" tabindex="-1"><a class="header-anchor" href="#learn-to-learn">Learn to learn</a></h3>
<p>The best engineers I know are open to learning. They are often faster at learning than &quot;others&quot;. This is not because they are smarter, but this is because they have developed this skill of learning new things over the years. Everyone has a different way of learning, figure out what works for you.</p>
<p>Usually you'll have to go outside your comfort zone for this. But the more new things you learn, the more you exercise your &quot;learning muscle&quot;. Be open to suggestions and new ideas. These can be in the form of code review or during stand up meetings. Just general discussions between other team members is a great learning opportunity. Listen carefully to what others are saying, if senior engineers are doing something a particular way there is almost always a reason they do it that way.</p>
<h3 id="ask" tabindex="-1"><a class="header-anchor" href="#ask">Ask</a></h3>
<p>If you don't know something, ask. No one will look down on you for not knowing something. And if they do, it is a reflection on them and not on you. It is better to ask a senior engineer who can explain something to you in 5 mins rather than spending 3 days trying to figure it out. However, please make a genuine effort to understand something before you go out and ask. You need to respect people's time. I see far too many junior developers who seek help at the first sight of inconvenience. This ties together with my previous point, if you don't struggle, you will not learn anything new.</p>
<h3 id="separate-work-from-personal-life" tabindex="-1"><a class="header-anchor" href="#separate-work-from-personal-life">Separate work from personal life</a></h3>
<p>Learn to switch off. This is something even I struggle with. You don't need to be online 24/7. If you receive an email at 11 PM you don't need to reply instantly. You don't need to work weekends. A lot of new engineers want to &quot;prove themselves&quot;, which is fine. But you need to create a sustainable work-life balance for yourself, it is not fun to feel burnt out in a couple of years.</p>
<p>Having said that the other extreme is bad too. I've seen people not joining important meetings which are beyond 5PM because they are &quot;off work&quot;, try to find the right balance that works for you.</p>
<h3 id="create-meaningful-relationships" tabindex="-1"><a class="header-anchor" href="#create-meaningful-relationships">Create meaningful relationships</a></h3>
<p>Human beings are social creatures. Good relationship with our co-workers will make our jobs enjoyable. Be empathetic towards your teammates, try to help wherever you can. Having a strong professional circle will also help you develop your career, opening up opportunities that otherwise might pass by you.</p>
<h2 id="conclusion" tabindex="-1"><a class="header-anchor" href="#conclusion">Conclusion</a></h2>
<p>Most of these things need to be done within reason, for example too much &quot;asking&quot; will come across as inability to learn or by taking up too many tasks you can stretch yourself too thin.</p>
<p>These were some of the things that I did as a junior engineer which helped me grow as an engineer. I still try to actively do these things. If you feel that I missed out on something or if there is something that you would do differently, please let me know.</p>
]]></content>
    <category term="technical"/>
  </entry>
  <entry>
    <title>IIT Bombay Half Marathon 2023</title>
    <link href="/blog/iit-bombay-half-marathon-2023/"/>
    <updated>2023-02-12T00:00:00Z</updated>
    <id>/blog/iit-bombay-half-marathon-2023/</id>
    <content type="html"><![CDATA[<div class="race-info">
<ul>
<li><strong>Event:</strong> IIT Bombay Half Marathon</li>
<li><strong>Date:</strong> February 12, 2023</li>
<li><strong>Distance:</strong> 21.1 km (Half Marathon)</li>
<li><strong>Location:</strong> IIT Bombay Campus, Mumbai</li>
<li><strong>Finish Time:</strong> <em>[Add your finish time]</em></li>
<li><strong>Pace:</strong> <em>[Add your pace]</em></li>
</ul>
</div>
<h2 id="pre-race" tabindex="-1"><a class="header-anchor" href="#pre-race">Pre-Race</a></h2>
<p><em>[Add your training leading up to the half marathon, travel to Mumbai, race day morning preparation]</em></p>
<h2 id="the-course" tabindex="-1"><a class="header-anchor" href="#the-course">The Course</a></h2>
<p><em>[Describe the IIT Bombay campus course - the scenic lake, hilly terrain, multiple loops, atmosphere]</em></p>
<h2 id="race-recap" tabindex="-1"><a class="header-anchor" href="#race-recap">Race Recap</a></h2>
<h3 id="kilometers-1-7" tabindex="-1"><a class="header-anchor" href="#kilometers-1-7">Kilometers 1-7</a></h3>
<p><em>[The first third - settling into pace, how did you feel starting out?]</em></p>
<h3 id="kilometers-8-14" tabindex="-1"><a class="header-anchor" href="#kilometers-8-14">Kilometers 8-14</a></h3>
<p><em>[The middle section - maintaining rhythm, any challenges?]</em></p>
<h3 id="kilometers-15-21-1" tabindex="-1"><a class="header-anchor" href="#kilometers-15-21-1">Kilometers 15-21.1</a></h3>
<p><em>[The final push - how did you handle the last kilometers? Mental game?]</em></p>
<h2 id="strava-activity" tabindex="-1"><a class="header-anchor" href="#strava-activity">Strava Activity</a></h2>
<p><em>Replace the activity ID below with your actual Strava activity ID:</em></p>
<div class="strava-embed-container">
      <iframe 
        height='405' 
        width='100%' 
        frameborder='0' 
        allowtransparency='true' 
        scrolling='no' 
        src='https://www.strava.com/activities/YOUR_STRAVA_ACTIVITY_ID/embed/YOUR_STRAVA_ACTIVITY_ID'
        loading="lazy">
      </iframe>
    </div>
<h2 id="post-race-thoughts" tabindex="-1"><a class="header-anchor" href="#post-race-thoughts">Post-Race Thoughts</a></h2>
<p><em>[Your reflections - achieving goals, what you learned, would you run it again?]</em></p>
<h2 id="tips-for-future-runners" tabindex="-1"><a class="header-anchor" href="#tips-for-future-runners">Tips for Future Runners</a></h2>
<p><em>[Any advice for people planning to run this event]</em></p>
<hr>
<p><em>Have questions about this race? Feel free to reach out on <a href="https://twitter.com/TheMayankThakur">Twitter</a>.</em></p>
]]></content>
    <category term="race-reports"/>
  </entry>
  <entry>
    <title>HRX Pinkathon 5K</title>
    <link href="/blog/hrx-pinkathon-5k/"/>
    <updated>2023-09-17T00:00:00Z</updated>
    <id>/blog/hrx-pinkathon-5k/</id>
    <content type="html"><![CDATA[<div class="race-info">
<ul>
<li><strong>Event:</strong> HRX Pinkathon 5K</li>
<li><strong>Date:</strong> <em>[Add date]</em></li>
<li><strong>Distance:</strong> 5 km</li>
<li><strong>Location:</strong> <em>[Add location]</em></li>
<li><strong>Finish Time:</strong> <em>[Add your finish time]</em></li>
<li><strong>Pace:</strong> <em>[Add your pace]</em></li>
</ul>
</div>
<h2 id="about-the-event" tabindex="-1"><a class="header-anchor" href="#about-the-event">About the Event</a></h2>
<p><em>[Describe what the Pinkathon is about - its cause, the atmosphere, the community]</em></p>
<h2 id="pre-race" tabindex="-1"><a class="header-anchor" href="#pre-race">Pre-Race</a></h2>
<p><em>[Add your pre-race preparation and expectations]</em></p>
<h2 id="race-recap" tabindex="-1"><a class="header-anchor" href="#race-recap">Race Recap</a></h2>
<p><em>[Describe your race experience - the start, middle, and finish]</em></p>
<h2 id="strava-activity" tabindex="-1"><a class="header-anchor" href="#strava-activity">Strava Activity</a></h2>
<p><em>Replace the activity ID below with your actual Strava activity ID:</em></p>
<div class="strava-embed-container">
      <iframe 
        height='405' 
        width='100%' 
        frameborder='0' 
        allowtransparency='true' 
        scrolling='no' 
        src='https://www.strava.com/activities/YOUR_STRAVA_ACTIVITY_ID/embed/YOUR_STRAVA_ACTIVITY_ID'
        loading="lazy">
      </iframe>
    </div>
<h2 id="post-race-thoughts" tabindex="-1"><a class="header-anchor" href="#post-race-thoughts">Post-Race Thoughts</a></h2>
<p><em>[Your reflections on the event and the experience]</em></p>
<hr>
<p><em>Have questions about this race? Feel free to reach out on <a href="https://twitter.com/TheMayankThakur">Twitter</a>.</em></p>
]]></content>
    <category term="race-reports"/>
  </entry>
  <entry>
    <title>Bengaluru Midnight Marathon 10K 2023</title>
    <link href="/blog/bengaluru-midnight-marathon-10k-2023/"/>
    <updated>2023-11-25T00:00:00Z</updated>
    <id>/blog/bengaluru-midnight-marathon-10k-2023/</id>
    <content type="html"><![CDATA[<div class="race-info">
<ul>
<li><strong>Event:</strong> Bengaluru Midnight Marathon 10K</li>
<li><strong>Date:</strong> November 25, 2023</li>
<li><strong>Distance:</strong> 10 km</li>
<li><strong>Location:</strong> Bangalore, India</li>
<li><strong>Finish Time:</strong> <em>[Add your finish time]</em></li>
<li><strong>Pace:</strong> <em>[Add your pace]</em></li>
</ul>
</div>
<h2 id="pre-race" tabindex="-1"><a class="header-anchor" href="#pre-race">Pre-Race</a></h2>
<p><em>[Add your pre-race preparation, training leading up to the event, and how you were feeling before the race]</em></p>
<h2 id="the-course" tabindex="-1"><a class="header-anchor" href="#the-course">The Course</a></h2>
<p><em>[Describe the course - the route through Bangalore, elevation, atmosphere of running at midnight, crowd support, aid stations]</em></p>
<h2 id="race-recap" tabindex="-1"><a class="header-anchor" href="#race-recap">Race Recap</a></h2>
<h3 id="kilometers-1-3" tabindex="-1"><a class="header-anchor" href="#kilometers-1-3">Kilometers 1-3</a></h3>
<p><em>[How did the race start? What was the atmosphere like at midnight?]</em></p>
<h3 id="kilometers-4-7" tabindex="-1"><a class="header-anchor" href="#kilometers-4-7">Kilometers 4-7</a></h3>
<p><em>[The middle section - how were you feeling? Did you stick to your pace?]</em></p>
<h3 id="kilometers-8-10" tabindex="-1"><a class="header-anchor" href="#kilometers-8-10">Kilometers 8-10</a></h3>
<p><em>[The final push - did you have a strong finish?]</em></p>
<h2 id="strava-activity" tabindex="-1"><a class="header-anchor" href="#strava-activity">Strava Activity</a></h2>
<p><em>Replace the activity ID below with your actual Strava activity ID:</em></p>
<div class="strava-embed-container">
      <iframe 
        height='405' 
        width='100%' 
        frameborder='0' 
        allowtransparency='true' 
        scrolling='no' 
        src='https://www.strava.com/activities/YOUR_STRAVA_ACTIVITY_ID/embed/YOUR_STRAVA_ACTIVITY_ID'
        loading="lazy">
      </iframe>
    </div>
<h2 id="post-race-thoughts" tabindex="-1"><a class="header-anchor" href="#post-race-thoughts">Post-Race Thoughts</a></h2>
<p><em>[Your reflections - what went well, what would you do differently, overall experience of the midnight run]</em></p>
<hr>
<p><em>Have questions about this race? Feel free to reach out on <a href="https://twitter.com/TheMayankThakur">Twitter</a>.</em></p>
]]></content>
    <category term="race-reports"/>
  </entry>
</feed>
