<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BlackMagiq</title>
    <description>The latest articles on DEV Community by BlackMagiq (@dangtony98).</description>
    <link>https://dev.to/dangtony98</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F912566%2F81ac87b5-75d4-4b7f-9417-d34fc0e23673.jpeg</url>
      <title>DEV Community: BlackMagiq</title>
      <link>https://dev.to/dangtony98</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dangtony98"/>
    <language>en</language>
    <item>
      <title>Beware of Your Static Database Credentials</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Thu, 04 Apr 2024 15:15:08 +0000</pubDate>
      <link>https://dev.to/dangtony98/beware-of-your-static-database-credentials-129h</link>
      <guid>https://dev.to/dangtony98/beware-of-your-static-database-credentials-129h</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp019fe756hps97jh2l19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp019fe756hps97jh2l19.png" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like it or not, every static database credential, and more broadly authentication token,  is a secret waiting to be leaked and exploited by a bad actor. Be it one or ten years from now and as careful as you may be, the credential is bound to get leaked through one of many avenues and the proof is all over the news. From &lt;a href="https://www.securityweek.com/leaked-github-token-exposed-mercedes-source-code/"&gt;Mercedes-Benz&lt;/a&gt; to &lt;a href="https://techcrunch.com/2022/11/03/astrazeneca-passwords-exposed-patient-data/"&gt;AstraZeneca&lt;/a&gt;, it almost seems that no company is immune to credential leaking. That said, there may be a solution after all, one that is common enough to be named but clearly not widespread enough to be employed everywhere.&lt;/p&gt;

&lt;p&gt;In this article, we dive into everything wrong with static database credentials and discuss how we can improve to mitigate any risks associated with leaking them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s wrong with static database credentials?
&lt;/h3&gt;

&lt;p&gt;Most users and applications in the wild authenticate with databases using manually-provisioned, static database credentials. This approach is often problematic for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you happen to leak a static database credential, then you give an attacker an indefinite window of opportunity to exploit your database. Moreover since your applications may share database credentials, they may collectively increase the overall risk of leaking secrets throughout your development cycle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the lucky event that you discover the incident, then you may try to manually revoke the database credential as soon as possible. The revocation process, however, may take time and hence introduce yet another shorter window of opportunity for an attacker to exploit your database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In any case, you will want to audit the incident to check the details of how it transpired. Depending on whether or not parts of your infrastructure share database credentials, however, you may find it difficult to map a good audit trail.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a world where one database credential leak could mean an attacker gaining access to a treasure trove of data, it’s clear that we need better practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing the Moving Target Defense
&lt;/h3&gt;

&lt;p&gt;As the Department of Homeland Security states, many systems have been “built to operate in a relatively static configuration. For example, addresses, names, software stacks, networks, and various configuration parameters.” Seeing associated issues, the &lt;a href="https://www.dhs.gov/science-and-technology/csd-mtd"&gt;Moving Target Defense (MTD)&lt;/a&gt; was a concept introduced with the intent of “controlling change access multiple system dimensions to increase uncertainty and apparent complexity for attackers, reduce their window of opportunity and increase the costs of their probing and attack efforts.”&lt;/p&gt;

&lt;p&gt;While MTD covers a broad range of systems, for the sake of our discussion, it can be seen widely applied in the context of web applications. For example, one common moving target defense mechanism is the refresh token mechanism that is commonly used in web application authentication or protocols like OAuth 2.0.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft80umtx2e2c2vt790gdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft80umtx2e2c2vt790gdb.png" alt="Image description" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the refresh token mechanism, an application may redeem a long-lived token (the refresh token) for a short-lived access token and use that to authenticate with a target service. By doing so, it reduces any risk associated with leaked access token exploitation because an access token would likely be expired by the time it is found anywhere by a bad actor. Put differently, the risk of exploitation reduced with an access token developed into a moving target with short time-to-live (TTL).&lt;/p&gt;

&lt;h3&gt;
  
  
  How does Moving Target Defense relate to static database credentials?
&lt;/h3&gt;

&lt;p&gt;When dealing with static database credentials, we can use two moving target approaches to reduce the window of opportunity that an attacker may have of exploiting database credentials: &lt;strong&gt;secret rotation&lt;/strong&gt; and &lt;strong&gt;dynamic secrets&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Secret rotation at interval: Secret rotation is the practice of rotating database credentials at a specific interval where rotating implies invalidating a set of database credentials in favor of newly-issued ones. For example, you may have a script or application rotate a database credential every 30 days to completely remove the risk of an attacker being able to use a leaked, old database credential. Since database (and other types) credentials often get mishandled, forgotten about, and eventually leaked somewhere like in a public repository where it is swept up and exploited by a botnet; it’s surprisingly common to run into instances of leaked and exploited long-lived credentials, cases that would’ve easily been avoided with proper secret rotation practices in place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Secret rotation on-demand: In cases where a secret does get leaked and you need to revoke it immediately, secret rotation can be manually triggered to immediately invalidate and issue a new set of database credentials. Ultimately, both interval-based and on-demand secret rotation are useful to ensure that database credentials are switched out periodically and immediately in the event of an incident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dynamic secrets: Lastly, dynamic secrets is the practice of issuing each engineer or application that needs access to database credentials a unique, short-lived credential on-demand that is when requested. This removes the accumulated risk associated with shared database credentials, isolates each party’s access, and most importantly retains the moving target principle for database credentials. In a dynamic secrets scenario, an application requests access to a database from another application (we’ll get to this in a bit) after which it is granted a short-lived access token to do so; the scenario maintains that the application’s database access can be cut off independently and audited if needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How are secret rotation and dynamic secrets implemented in practice?
&lt;/h3&gt;

&lt;p&gt;As you may have guessed, implementing secret rotation and dynamic secrets is not trivial and requires introducing a third-party script or application to orchestrate the mechanisms. The third-party application would be responsible for updating the values of your database credentials as in the secret rotation case and/or issuing database credentials downstream to your applications that request them.&lt;/p&gt;

&lt;p&gt;While it’s possible to implement your own secret rotation and dynamic secrets functionality, it’s strongly encouraged to instead use a secrets manager. Using purpose-built tooling ensures that you reap all the benefits of good secrets hygiene including comprehensive visibility over secrets scattered throughout your infrastructure and moving targets applied to your database credentials.&lt;/p&gt;

&lt;p&gt;When using a tool like &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt;, for example, you set up dynamic secrets by delegating privileged access to the platform so it can issue temporary database credentials (i.e. dynamic secrets) bound under “leases” to applications that request them; upon lease expiration, Infisical automatically revokes the dynamic secrets, so applications must request a new dynamic secret to continue accessing the intended database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kcdhdeqpww5z9k5x767.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kcdhdeqpww5z9k5x767.png" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Many companies fall victim to using static database credentials only to find out, one or ten years from now, that they have accidentally leaked them somewhere across their sprawled infrastructure. From small to large companies and organizations, there’re countless stories to show that this is no rare occurrence. That said, by employing Moving Target Defense principles and specifically practices like secret rotation and dynamic secrets, you can improve your organization’s overall security posture and maximally reduce the window of opportunity that a bad actor may have of exploiting database credentials in the event of a leak.&lt;/p&gt;

&lt;p&gt;Onward and upward!&lt;/p&gt;

&lt;p&gt;— -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; — The open source secret management platform&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" alt="Image description" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; (11.8K+ ⭐️)helps thousands of teams and organizations store and sync secrets across their team and infrastructure.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/Infisical/infisical"&gt;https://github.com/Infisical/infisical&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>python</category>
    </item>
    <item>
      <title>The Great Migration from MongoDB to PostgreSQL</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Fri, 29 Mar 2024 12:23:11 +0000</pubDate>
      <link>https://dev.to/dangtony98/the-great-migration-from-mongodb-to-postgresql-eb0</link>
      <guid>https://dev.to/dangtony98/the-great-migration-from-mongodb-to-postgresql-eb0</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz13xodhnjxpel953bjc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz13xodhnjxpel953bjc6.png" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; has grown rapidly in the past year with the platform now processing north of 50 million secrets daily that is sending application configuration and secrets data to teams, CI/CD pipelines, and servers/applications that need them. &lt;/p&gt;

&lt;p&gt;With usage continuing to grow, we’ve had to continuously upgrade our stack. More recently, Infisical underwent a full database migration from &lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt; to &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;. This entailed deliberating the initiative, adopting new tech, creating new database schemas, rewiring logic, re-writing queries, to migrating millions (if not billions) of database records over to &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;. This was an elaborate process but one that was by all means necessary and for the betterment of the platform.&lt;/p&gt;

&lt;p&gt;This is the story of our decision-making behind why we moved from &lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt; to PostgreSQL and how we did it. Hopefully, this makes for an interesting read and is useful for others who may find themselves one day considering a similar database migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where we started
&lt;/h3&gt;

&lt;p&gt;When we first built Infisical, we built it with the stack that felt most familiar with the team. As part of that stack, we chose MongoDB + &lt;a href="https://mongoosejs.com/"&gt;Mongoose ORM&lt;/a&gt; because the combination presented least overhead and allowed us to ship quality features quickly. As Sir Tony Hoare states, “&lt;a href="https://stackify.com/premature-optimization-evil/"&gt;premature optimization is the root of all evil&lt;/a&gt;,” and there was certainly no need for further optimization at the time.&lt;/p&gt;

&lt;p&gt;At the time, we were also more focused on building &lt;a href="https://infisical.com/"&gt;Infisical Cloud&lt;/a&gt;, the managed SaSS offering, and given this focus, we didn’t anticipate as many users self-hosting the product and hence it wasn’t designed with that use-case in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not MongoDB?
&lt;/h3&gt;

&lt;p&gt;While MongoDB served Infisical well in the early days, it started showing signs of shortcoming when the use-case of our product evolved beyond the managed service. As time passed, we found that many organizations, especially ones operating at the intersection of compliance and security, preferred self-hosting Infisical as opposed to using Infisical Cloud; others had on-prem requirements that needed to be met.&lt;/p&gt;

&lt;p&gt;With demand growing for self-hosting Infisical, we found ourselves shipping many features catered to reducing the learning curve needed to self-host Infisical and, as part of that, we ended up leaving MongoDB in favor of PostgreSQL.&lt;/p&gt;

&lt;p&gt;In practice, we and our customers often ran into constraints around the capabilities and usability of MongoDB like the lack of support for &lt;a href="https://en.wikipedia.org/wiki/Database_transaction"&gt;transactions&lt;/a&gt;, clean-up, inconsistent versioning across managed offerings by cloud providers, not to mention issues associated with schema-less database design structure.&lt;/p&gt;

&lt;p&gt;I elaborate more on a few of these challenges below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Difficulty configuring database transactions: With MongoDB, setting up transactions was not trivial because it required running MongoDB in cluster mode with various configuration overhead; this made it extremely difficult, for instance, for customers to run a simple POC of Infisical because it required a production setup of MongoDB. For a product dealing with highly-sensitive data where data integrity is a must, this was a no-go.&lt;/li&gt;
&lt;li&gt;Missing out on relational features: With MongoDB, we lost out on many nice features from the relational world like &lt;code&gt;CASCADE&lt;/code&gt; which, when specified, deletes all referenced resources across other tables whenever a target resource is deleted; this hurt in particular because our data was very much relational. As a result, we employed hefty delete functions in our old codebase that never fully did the job and left dangling resources in the MongoDB databases.&lt;/li&gt;
&lt;li&gt;Lacking support across cloud providers: After MongoDB’s license change to SSPL, many cloud providers opted to offer older versions of MongoDB. As a result, we found it difficult to ensure the availability of features of Infisical for customers running on everything other than the latest stable version(s) of MongoDB.&lt;/li&gt;
&lt;li&gt;Lacking experience with MongoDB: Since more people were familiar with deploying SQL-based databases, they often struggled to scale and properly configure MongoDB; this led to a disproportionate uptick in the amount of support we needed to provide for customers specifically because they weren’t familiar with MongoDB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amongst a dozen more reasons, we came to the realization that a full database migration to something more universal was the ultimate feature needed to make Infisical more accessible to teams and organizations around the world.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why PostgreSQL?
&lt;/h3&gt;

&lt;p&gt;When searching for a new database, we began by listing out what aspects mattered most to us: ease of management (i.e. configuration, deployment, and scaling included), built-in support for transactions, and relational capabilities. As part of the deliberation, we also contemplated whether or not we should build our own integrated storage or pursue an external storage solution.&lt;/p&gt;

&lt;p&gt;Here’s what that meant for each option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrated storage: We could package in a database system like &lt;a href="https://www.sqlite.org/"&gt;SQLite&lt;/a&gt; directly into Infisical and pursue a horizontal replication strategy to reduce latency by avoiding extra network hops. In this model, scaling the system would mean deploying multiple instances of Infisical and have them communicate with each other via some &lt;a href="https://en.wikipedia.org/wiki/Consensus_%28computer_science%29"&gt;consensus algorithm&lt;/a&gt; like &lt;a href="https://en.wikipedia.org/wiki/Raft_%28algorithm%29"&gt;Raft&lt;/a&gt;. While this seemed like an excellent solution since customer’s wouldn’t need to connect any dependencies to run Infisical, the tooling ecosystem to execute this vision felt immature and the engineering effort required for it felt nothing short of overwhelming.&lt;/li&gt;
&lt;li&gt;External storage: We could simply replace MongoDB with another database(s) like PostgreSQL or MySQL and use its built-in scaling capabilities. Although this solution didn’t fully eliminate friction associated with needing external dependencies to use Infisical, we felt that it already delivered significant benefits by virtue of not being MongoDB. When it came to supporting one or multiple databases, we felt that supporting multiple would mean missing out on the unique advantages of each solution; it would also add to our engineering overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After careful consideration, we chose PostgreSQL. Beyond having a vibrant community, extensive documentation, and a myriad of solutions and extensions available, we appreciated most its open source nature and how the vast majority of cloud providers offered managed services of PostgreSQL.&lt;/p&gt;

&lt;p&gt;Above all, this meant that users of Infisical could more easily self-host our platform on any cloud provider and pair it with its corresponding managed PostgreSQL service. Moreover, given how widely-adopted the database has become, we were confident that users would have less trouble operating it when using Infisical.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about the ORM?
&lt;/h3&gt;

&lt;p&gt;After settling on PostgreSQL, we needed to figure out how our application would interact with the database. Right off the bat, we wanted something comparable to our experience with MongoDB where we used Mongoose ORM. So, we began evaluating candidates on the basis of maturity, visualization and migration support, and appropriate level of abstraction; we primarily considered &lt;a href="https://orm.drizzle.team/"&gt;Drizzle ORM&lt;/a&gt;, &lt;a href="https://www.prisma.io/"&gt;Prisma ORM&lt;/a&gt;, &lt;a href="https://typeorm.io/"&gt;TypeORM&lt;/a&gt;, and &lt;a href="https://knexjs.org/"&gt;Knex.js&lt;/a&gt;, a query builder.&lt;/p&gt;

&lt;p&gt;At the end, we decided to use Knex.js, a query builder, instead of a ORM to maintain better control over the database. While admittedly, going with raw SQL would be most versatile with least abstraction in place, we felt the approach would be far too error-prone and frankly cumbersome to maintain, especially without proper TypeScript support. Moreover, beyond being close to bare SQL, Knex.js came with its own toolkit for seeding and migration, had a mature ecosystem with excellent documentation and answers for almost any possible query. Coupled with some custom Zod integration work, we managed to get it to a satisfactory level for TypeScript support.&lt;/p&gt;

&lt;p&gt;Having decided on the database and ORM, we kicked off a process that would ultimately result in a re-write of dozens of data structures and hundreds of queries across the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  How did we plan the migration?
&lt;/h3&gt;

&lt;p&gt;Toward the end of the code-rewrite, we started to think about how we would conduct the migration operation to map our MongoDB data to PostgreSQL with minimal disruption to the Infisical Cloud platform.&lt;/p&gt;

&lt;p&gt;Given Infisical’s critical role in customers infrastructure, we immediately ruled out the possibility of having any absolute downtime. The part where we had to make a compromise was in disallowing write operations during the brief migration window (i.e. customers would not be able to create or update application configuration) in exchange for higher guarantee of data integrity. This tradeoff seemed acceptable given that customers primarily fetched back secrets from Infisical and, to a much lesser extent, updated their application configuration on a second-by-second basis.&lt;/p&gt;

&lt;p&gt;Next, regarding the actual migration operation, we needed to dump data from MongoDB, transform it carefully, and insert it back into PostgreSQL. As we audited the migration sequence, we grappled through challenges like making sure that various tree-like structures from NoSQL were correctly transformed to their relational counterparts; this was particularly sensitive for data structures like folders that had recursive considerations. We also found that we needed a persistent way to store and map identifiers in MongoDB to those in PostgreSQL; doing so in-memory would not work considering how much data we were dealing with. In the end, we settled for using the &lt;a href="https://leveljs.org/"&gt;LevelDB&lt;/a&gt; key-value store to assist with identifier storage and lookup operations. With it, we would move data table-by-table into PostgreSQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Great Migration
&lt;/h3&gt;

&lt;p&gt;Finally, we were ready to conduct the migration. At this point, folks not directly involved in the codebase re-write had spent a much-needed quarter improving other aspects of Infisical including making frontend changes, performing maintenance patches, extending client functionality, and writing up better documentation. We now all reconvened to prepare for the migration itself that is replacing the application codebase with the new one and transferring data over from MongoDB to PostgreSQL.&lt;/p&gt;

&lt;p&gt;As part of the preparation, we drafted a detailed migration checklist with an expected timeline.&lt;/p&gt;

&lt;p&gt;On a high-level, the plan looked something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the weeks building up to the migration, we would communicate in advance via both email and in-app banner to let users know about the impending database upgrade. We would conduct thorough testing of every feature flow on the platform and perform trial runs for the migration.&lt;/li&gt;
&lt;li&gt;The migration itself would occur within a six-hour window where only read operations would be allowed to the platform. During this window, we would run the migration script to move data from MongoDB to PostgreSQL, check that no data was lost, and if successful switch the DNS to the new instance. There were of course backup plans in place in case things went south.&lt;/li&gt;
&lt;li&gt;Finally, after the migration, we would iron out any residual issues and start rolling out new documentation for working with Infisical and PostgreSQL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the plan in hand, we proceeded to the execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;Fortunately, the migration execution turned out smooth with zero data loss and only a few non-essential incidents of feature malfunction; we ironed out these bugs out in the following 36 hours with minimal impact to customers.&lt;/p&gt;

&lt;p&gt;Following the migration, we observed many benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The platform experienced significant performance gains largely attributed to query optimizations with joins. With MongoDB, the platform often made inefficient aggregation queries and multiple network hops to achieve needed functionality. For instance, due to the relational characteristics of our core data, we often had to perform many &lt;code&gt;$lookup&lt;/code&gt; operations to simulate joins in SQL; such operations were inefficient and often required us to scale up both the database and application instances accordingly. Having moved to PostgreSQL, we avoided these inefficient operations which also resulted in a 50% cost reduction on our database bill.&lt;/li&gt;
&lt;li&gt;The platform now employed better data validation rooted at the database level rather than at the application layer. Since MongoDB was schemaless by design, it relied on Mongoose’s framework to define data types, required fields, and validation rules. With PostgreSQL in place, we no longer faced data inconsistencies that would otherwise previously occur if the database was ever accessed or modified outside of Mongoose’s purview.&lt;/li&gt;
&lt;li&gt;Lastly and most importantly, we believe that Infisical is much easier to self-host now with customers able to conduct POCs with no additional configuration overhead such as dealing with replica sets in MongoDB to enable transaction capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, we considered the initiative to be highly successful given the objective at hand, the scope of the task, and the resulting execution of it. We intend on publishing more concrete results in the future once we have more data on hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The decision to move from MongoDB to PostgreSQL was not an easy one from the get-go. All in all, the initiative took us 3–4 months to perform with careful planning and discussion around why we needed to perform it, how we were going to do it; and then to execute it all with care. For anyone reading this, I’d highly recommend thinking through the use-case and implementation deeply before attempting such a big endeavor. Overall, I’m extremely happy that everything went according to plan and we were able to deliver such a huge update that will make a large difference to users of Infisical moving forward.&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a href="https://www.linkedin.com/in/akhilmhdh/"&gt;Akhil Mohan&lt;/a&gt; for absolutely crushing the migration initiative and everyone else at Infisical for assisting with the process.&lt;/p&gt;

&lt;p&gt;— -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; — The open source secret management platform&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" alt="Image description" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; (11.8K+ ⭐️)helps thousands of teams and organizations store and sync secrets across their team and infrastructure.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/Infisical/infisical"&gt;https://github.com/Infisical/infisical&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mongodb</category>
      <category>postgres</category>
      <category>programming</category>
    </item>
    <item>
      <title>Guide to Building Great Audit Logs for Application Software</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Tue, 15 Aug 2023 18:15:46 +0000</pubDate>
      <link>https://dev.to/dangtony98/guide-to-building-audit-logs-for-application-software-49fh</link>
      <guid>https://dev.to/dangtony98/guide-to-building-audit-logs-for-application-software-49fh</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F165gvbi27yj29vy7hhsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F165gvbi27yj29vy7hhsc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s 2023 and audit logs are a core component of any enterprise product offering. As simple as they seem, audit logs can be tricky to implement.&lt;/p&gt;

&lt;p&gt;Having made this feature twice as part of my work at &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, I discuss everything about audit logging in this article and specifically how to ship them properly for yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are audit logs?
&lt;/h2&gt;

&lt;p&gt;To begin, audit logs are a centralized stream of user activity used by security and compliance teams at enterprises to monitor information access in the event of any suspicious activity or incident review. At first glance, they are entries consisting of events, time-stamps, and payloads. On a deeper level, however, they can be seen as summaries that, when taken in tandem, capture a frame-by-frame narrative of what happened at any given period of time in great detail (we call this a fine-grain audit trail).&lt;/p&gt;

&lt;h2&gt;
  
  
  Making great audit logs
&lt;/h2&gt;

&lt;p&gt;In this section, we outline the data structure we’d expect from an audit log and the principles we wish to uphold.&lt;/p&gt;

&lt;h3&gt;
  
  
  The general data structure
&lt;/h3&gt;

&lt;p&gt;As a reminder, audit logs are purpose-built for security and compliance teams to monitor and inspect the context of an incident at a given point in time. Given this, a good set of audit logs should, at the every least, contain fields that answer your basic interrogative pronouns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event&lt;/strong&gt;: What happened? — For &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, this was, for example, an action associated with a secret such as it being fetched or created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actor&lt;/strong&gt;: Who triggered the event? This may be the name, email, or identifier for the entity responsible for performing or causing the underlying event.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Timestamp&lt;/strong&gt;: When did the event occur? — Source (User agent + IP): Where did the event occur? If you’re building an API, both user information and IP address can typically be obtained from the request itself. Frameworks like Express, for instance, expose the request’s user agent under req.headers[“user-agent”] and req.ip .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metadata&lt;/strong&gt;: Additional data to provide context for each event. In our case, this could’ve been the path at which a secret was fetched from etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond these fields, it can be useful to store the following data (these may or may not be applicable):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source Type&lt;/strong&gt;: The source category of the event. In our case, requests could be made from a Web UI, CLI, Kubernetes Operator, or Other (i.e. anywhere else). We’ll discuss this more later but including such a field helps from a querying standpoint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: A human-readable description of the action taken. The defining characteristics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt;: Like HTTP requests, it’s possible for events to succeed or fail. If applicable and you have a way to detect this status information, you should include it in the entry. This would be helpful to identify, for instance, if someone attempted to access a forbidden resource.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good audit logging system should not only record event data but also consider various usability criteria for the teams inspecting the logs (i.e the end users) and engineers of the system itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Immutable&lt;/strong&gt;: Users of the system should only have the ability to read data from it and not write to it. Having write-ability would compromise the integrity of the audit logging system since it must reflect the exact state of events in the past.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Queryable&lt;/strong&gt;: Users of the system must be able to efficiently search through the audit logs by applying any one or more filters; filtering should be quick. In case of a security incident, an administrator should be able to filter out all events where actor A performed action B from source C between the dates D and E.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exportable&lt;/strong&gt;: Data must be exportable and/or streamable to a dedicated logging solution like Splunk, AWS, etc. This is useful for security teams to centralize their security logs to be analyzed externally. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, you may consider some additional nice-to-have qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lightweight&lt;/strong&gt;: Audit logs should capture brief summaries, snippets, and/or references to data rather than include all of it. So, if you find yourself copying an entire data structure over as if you’re capturing a database backup/snapshot, then you’re probably doing it wrong (e.g. you don’t need to attach every detail about the actor for an event; you may only need their identifier to link them to the event).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parsable&lt;/strong&gt;: A great audit log data structure should also be easy to parse and, more generally, work with. The shape and structure of your data can have implications on how easy it is to render it over in the platform UI as well as to manipulate for some future engineering endeavor.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How we did it at Infisical
&lt;/h2&gt;

&lt;p&gt;When we first built the audit logging functionality for &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, we didn’t fully consider the target user at hand.&lt;/p&gt;

&lt;p&gt;Instead, we viewed the objective in an overly-simplified way: create a chronologically-ordered ledger of events for teams to inspect the past. We also mistook audit logs for complete snapshots of data and state that, in retrospect, should be the responsibility of database backups/snapshots.&lt;/p&gt;

&lt;p&gt;As a result, we ended up with a impractical audit logging system that took us back to the drawing board.&lt;/p&gt;

&lt;h3&gt;
  
  
  The data structure we used
&lt;/h3&gt;

&lt;p&gt;After giving it a lot of thought, we opted for the following audit log schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IAuditLog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;userAgentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAgentType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auditLogSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAuditLog&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActorType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mixed&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mixed&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;userAgentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAgentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fundamentally, we split the necessary components into 3 parts adjusted to our needs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actor&lt;/strong&gt;: Since events in &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; could be triggered by human and non-human (i.e. services) actors, we added actor type to the schema. Moreover, since human and non-human actors had different identifier metadata like email, user ID, service ID, etc., we also created a well-typed, mixed type metadata field to store this information for each actor. The defining thought process here was query-ability.&lt;br&gt;
&lt;strong&gt;Event&lt;/strong&gt;: The name of the event and any associated metadata unique to each event.&lt;br&gt;
&lt;strong&gt;Other&lt;/strong&gt;: Request information such as the IP address and user agent of the inbound request as well as a timestamp of when it came in.&lt;br&gt;
Equipped with this data structure, creating and querying for audit logs became easy as cake.&lt;/p&gt;

&lt;h2&gt;
  
  
  The UI and UX
&lt;/h2&gt;

&lt;p&gt;As you’d expect, we organize audit logs into a paginated table view, equipped with filters that users can apply together to narrow their search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr471hdot24j8f2utwybr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr471hdot24j8f2utwybr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We made a ton of improvements since our first iteration of audit logs not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filter options&lt;/strong&gt;: You can filter audit logs by event, user, source, date, or any combination of these filters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metadata&lt;/strong&gt;: We display only relevant metadata and nothing excess. For instance, we don’t store and perform any crypto operations on audit logs when it comes to secrets; we just offload that to another part of the application that’s responsible for it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;: We format time-stamps in “YYYY-MM-DD hh:mm am/pm” format.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Audit logs are a high-demand feature when it comes to selling enterprise software and it’s important to get them right. By choosing a versatile data structure and considering how they are used in practice, you can design great audit logs for your software that help users gain insight for security reviews and incidents.&lt;/p&gt;

&lt;p&gt;— -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; — The open source secret management platform&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wswst18glpnl5eo2b6a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; (8.4K+ ⭐️)helps thousands of teams and organizations store and sync secrets across their team and infrastructure.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;https://github.com/Infisical/infisical&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>saas</category>
      <category>programming</category>
    </item>
    <item>
      <title>Guide to pentesting (what, why, and how)</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Wed, 21 Jun 2023 10:46:25 +0000</pubDate>
      <link>https://dev.to/dangtony98/guide-to-pentesting-what-why-and-how-it-works-2b92</link>
      <guid>https://dev.to/dangtony98/guide-to-pentesting-what-why-and-how-it-works-2b92</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kISTUHcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8o2bjon5xogtostzzt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kISTUHcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8o2bjon5xogtostzzt4.png" alt="Image description" width="768" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In May 2023, &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; commissioned cybersecurity firm &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; to perform a full-coverage, gray box penetration test (pentest) against the application's entire attack surface to identify vulnerabilities, according to industry standards (such as OWASP ASVS, WSTG, TOP-10). &lt;/p&gt;

&lt;p&gt;In this article, I share my experience spearheading the pentesting initiative for &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; that is our motivation and how the procedure went down for other companies that may be considering undergoing a pentest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is pentesting?
&lt;/h2&gt;

&lt;p&gt;Pentesting or ethical hacking is a simulated cyber attack against a computer system, network, or web application to identify vulnerabilities that could be exploited by malicious actors. The goal of pentesting is to identify weak spots in security posture which can be used to fine-tune security policies, patch vulnerabilities, and enhance overall security measures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you do a pentest?
&lt;/h2&gt;

&lt;p&gt;There are plenty of compelling reasons to do a pentest. Here are a few that stood out to us and that may be relevant to you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To proactively uncover and remediate security vulnerabilities before malicious actors discover them and, in doing so, strengthen your organization's security posture.&lt;/li&gt;
&lt;li&gt;To ensure compliance with standards like SOC 2 and ISO 27001 where policies may require your organization undergo pentests on a regular basis.&lt;/li&gt;
&lt;li&gt;To increase trust between you and existing/prospective customers, especially when your business handles sensitive data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an open source secret management solution with security at the heart of everything we do, &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; undergoes full-coverage pentests at least twice per year to ensure that the codebase is kept secure. That said, it may or may not make sense to do a pentest early on depending on the nature of your product/service, the sensitivity of data handled by it, the complexity of your systems, your organization's risk tolerance and compliance requirements, etc. The stage of your company may also matter since, for example, a pre-product market fit company may be concerned more with shipping product out the door quickly to ascertain demand rather than securing it. &lt;/p&gt;

&lt;p&gt;Ultimately, the decision is multifaceted and must be judged on a case-by-case basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What firm should you hire to conduct the pentest?
&lt;/h2&gt;

&lt;p&gt;You should hire a firm with a demonstrated history and track record of pentesting; ideally, it is also affordable for your company. With nearly a decade of experience performing pentests for 100+ companies and positive reviews/feedback from within the startup community, the team at &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; felt like a strong fit for &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; and we were quick to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the structure of a pentest?
&lt;/h2&gt;

&lt;p&gt;Depending on the scope of the engagement, you can expect a multi-step sequence spanning one or more months. In our case, we followed a four-phase roadmap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Information gathering: This step involved a call with &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; and assigned testers to determine the scope and timeline of the engagement, provide background information about the platform stack and infrastructure, and prepare for the test such as by providing the team access to a staging environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pentest start: The pentest itself involved two testers manually performing a large number of tests on the application with extra attention paid to vulnerabilities that could cause serious damage to &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reporting: After the pentest, &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; delivered a report consisting of an executive summary, a detailed finding section, and recommended remediations for the findings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remediation &amp;amp; retesting: Finally, the team at &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; remediated any findings within the following week. During this period, &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; maintained regular communication with &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; who were very responsive to inquiries. Following remediation, &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt; provided a remediation report and letter of attestation for the conducted pentest.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Do you recommend doing a pentest?
&lt;/h2&gt;

&lt;p&gt;Definitely — We had a pleasant experience working with &lt;a href="https://www.oneleet.com/"&gt;Oneleet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On a final note, we recommend doing a pentest at least once a year; we also recommend shaping a comprehensive security strategy early on and getting certified for compliance standards like SOC 2 and ISO 27001 early on. Prioritizing these initiatives early on help maintain your organization's security posture in the face of malicious actors and strengthen trust between you and your customers.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>startup</category>
      <category>testing</category>
    </item>
    <item>
      <title>Scan your codebase for leaked environment variables instantly</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Wed, 24 May 2023 13:13:09 +0000</pubDate>
      <link>https://dev.to/dangtony98/scan-your-codebase-for-leaked-environment-variables-instantly-829</link>
      <guid>https://dev.to/dangtony98/scan-your-codebase-for-leaked-environment-variables-instantly-829</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVTzDZ-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i988dk7x0lw3ub7ijlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVTzDZ-f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i988dk7x0lw3ub7ijlu.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All it takes is for one developer on your team to forget to &lt;code&gt;.gitignore&lt;/code&gt; their &lt;code&gt;.env&lt;/code&gt; file or remove a hardcoded environment variable they used in development for sensitive data to leak to source control. In the modern era where bad actors use bots to monitor repositories on GitHub, leaking environment variables can be a fatal mistake.&lt;/p&gt;

&lt;p&gt;In this article, I introduce a CLI tool that your team can use to scan your existing codebase for any leaked environment variables instantly. It can scan your existing commit, past commits, and be configured as a pre-commit hook to prevent developers from committing any unintended secrets to source control. By the end, you should be able to detect leaked environment variables in your codebase and set up a pre-commit hook to automatically scan for leaks and prevent committing them to source control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I care?
&lt;/h2&gt;

&lt;p&gt;It's important for developers to know the best practices for managing environment variables - to be more precise, managing secrets that is sensitive data like, for example, an API key that we wouldn't want bad actors to get ahold of.&lt;/p&gt;

&lt;p&gt;Perhaps the first step to better managing secrets is to adopt the tooling necessary to prevent leaking secrets to begin with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the tooling?
&lt;/h2&gt;

&lt;p&gt;While there are numerous CLI tools that you can use to detect secrets in your codebase, I'm going to be using the &lt;a href="https://infisical.com/docs/cli/overview"&gt;Infisical CLI&lt;/a&gt; in this article because it's simple and has synergies with &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt;, a popular open-source secret management stack that can also be used to store your environment variables.&lt;/p&gt;

&lt;p&gt;The CLI itself is free to use, and the &lt;a href="https://github.com/Infisical/infisical"&gt;Infisical&lt;/a&gt; platform itself can also be self-hosted on your own infrastructure as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To begin, you need to install the &lt;a href="https://infisical.com/docs/cli/overview"&gt;Infisical CLI &lt;/a&gt;onto your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MacOS (using brew):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;infisical/get-cli/infisical
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows (using scoop):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scoop bucket add org https://github.com/Infisical/scoop-infisical.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;infisical
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Arch Linux (using yay):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yay &lt;span class="nt"&gt;-S&lt;/span&gt; infisical-bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;a href="https://infisical.com/docs/cli/overview"&gt;documentation&lt;/a&gt; for more installation options like Redhat/CentOS/Amazon and Debian/Ubuntu if your system is missing above.&lt;/p&gt;

&lt;p&gt;Great! You're now ready to detect secrets in your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scanning a directory, file, or full Git history for secrets.
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;scan&lt;/code&gt; command can be run in a directory to detect any secrets within it; it looks out for 140+ secret types like potential API keys etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;scan your codebase &lt;span class="k"&gt;for &lt;/span&gt;secrets
&lt;span class="go"&gt;infisical scan

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;display the full secret findings
&lt;span class="go"&gt;infisical scan --verbose
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;infisical scan&lt;/code&gt; simply prints how many leaks were found across your commits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;11:13AM INF scanning for exposed secrets...
11:13AM INF 932 commits scanned.
11:13AM INF scan completed in 2.23s
11:13AM WRN leaks found: 32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile, &lt;code&gt;infisical scan --verbose&lt;/code&gt; prints fuller details for each secret such as what was leaked, who leaked it, and where it can be found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Finding:     JWT_SECRET=138817529bf4c73772243214896b168df91d3501d56757dbcbeda31d3da7acad
Secret:      138817529bf4c73772243214896b168df91d3501d56757dbcbeda31d3da7acad
RuleID:      generic-api-key
Entropy:     3.593139
File:        .env.example
Line:        7
Commit:      622ed0d1b294bd31bd771eb40115d337
Author:      John Doe
Email:       johndoe@gmail.com
Date:        2022-12-24T19:21:21Z
Fingerprint: 622ed0d1b294bd31bd771eb40115d337:.env.example:generic-api-key:7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scanning uncommitted files
&lt;/h2&gt;

&lt;p&gt;Scanning your entire git history is nice but what if you only wanted to scan your uncommitted files while developing?&lt;/p&gt;

&lt;p&gt;No worries, the &lt;code&gt;infisical scan git-changes&lt;/code&gt; subcommand has you covered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;scan your uncommitted files
&lt;span class="go"&gt;infisical scan git-changes

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;display the full secret findings &lt;span class="k"&gt;for &lt;/span&gt;the uncommitted files
&lt;span class="go"&gt;infisical git-changes --verbose
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up automatic scanning before each commit
&lt;/h2&gt;

&lt;p&gt;While scanning your codebase for leaked secrets manually works, the best teams have pre-commit hooks set up that automatically detect any leaked secrets before allowing you to commit any code. This one-time setup makes it impossible for developers to forget to manually run the scan command before each commit and, in doing so, enforces that committed code is clear of leaking any secrets.&lt;/p&gt;

&lt;p&gt;To install the git hook, run the following command in your local git repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;infisical scan install --pre-commit-hook
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You now know how to detect secrets in your codebase and prevent leaks from happening.&lt;/p&gt;

&lt;p&gt;That said, I'd encourage you to check out the &lt;a href="https://infisical.com/docs/cli/scanning-overview"&gt;full documentation&lt;/a&gt; for more information and advanced options on using the CLI for secret scanning. It includes how to configure the scan to ignore select secrets or even those matching a pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Leaking secrets can happen to the best of us, and this risk scales with the size of a team; the more engineers you have onboard, the higher the risk of one developer accidentally introducing a new secret and accidentally committing it to source control.&lt;/p&gt;

&lt;p&gt;However, there are practices that you and your team can enforce to prevent secrets leaks from happening and using a CLI to detect secrets in your codebase is one such practice. With minimal effort, you can set up a pre-commit hook that automatically scans for leaked secrets and prevents developers from committing code before removing that secret or acknowledging it as intentional.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>Magically use environment variables without a .env file</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Thu, 18 May 2023 13:51:26 +0000</pubDate>
      <link>https://dev.to/dangtony98/magically-use-environment-variables-without-a-env-file-43ch</link>
      <guid>https://dev.to/dangtony98/magically-use-environment-variables-without-a-env-file-43ch</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfxo86fjq18pfl230lqu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfxo86fjq18pfl230lqu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TLDR: You can build or use a pre-made CLI together with your application's start command to inject environment variables for local development and avoid using a &lt;code&gt;.env&lt;/code&gt; file altogether.&lt;/p&gt;

&lt;p&gt;Recently, I wrote about fetching environment variables for applications so teams always have access to the right variables. The method was simple: store environment variables in a secret management platform, then have the application fetch them back and cache them at runtime. This, however, came with a nuance of having to manage yet another token to fetch these variables.&lt;/p&gt;

&lt;p&gt;In this article, however, I discuss an enhanced approach specifically for local development to inject environment variables into an application without needing a &lt;code&gt;.env&lt;/code&gt; file at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  It sucks to fetch environment variables back for an application if the method still requires managing one environment variable
&lt;/h2&gt;

&lt;p&gt;This is a common complaint and debate amongst developers considering to use a secret management platform to store their environment variables only to find out that they still need to manage a token to gain access to the platform.&lt;/p&gt;

&lt;p&gt;While the approach of storing a token in a &lt;code&gt;.env&lt;/code&gt; file and using it to fetch back environment variables tamed secret sprawl, it did little to improve on the security front. After all, you could still leak the token to source control and, if not revoked, bad actors could use it to access your environment variables.&lt;/p&gt;

&lt;p&gt;I'm glad to say, however, that you can use a secret management platform and fetch environment variables back without needing to store another proxy token. Here's how:&lt;/p&gt;

&lt;h2&gt;
  
  
  You can inject environment variables into your application using a CLI
&lt;/h2&gt;

&lt;p&gt;Let me explain.&lt;/p&gt;

&lt;p&gt;It turns out that your application running in local development is just a process and it's possible to pass environment variables into that process as it starts up. This means that you can build a platform-agnostic CLI to fetch back environment variables from a centralized source and wrap it around your application's start command. Couple the CLI with authentication logic and proper credential storage on your system and you can have a secure workflow that pulls and injects environment variables into your local development process.&lt;/p&gt;

&lt;p&gt;Moving forward, members of your team only need to install the CLI onto their machine, authenticate with the secret management platform via the CLI, and start up their application via CLI with environment variables injected - Wizardry.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's enough, show me your recommendation, gimme the code
&lt;/h2&gt;

&lt;p&gt;While you can code the CLI yourself and connect it to an existing secret management platform, I wouldn't recommended it for most developers since this isn't a quick endeavor. Instead, I'm going to be using the &lt;a href="https://infisical.com/docs/cli/overview" rel="noopener noreferrer"&gt;Infisical CLI&lt;/a&gt; to pull and inject environment variables in local development from &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, a popular open-source, end-to-end encrypted secret management platform that you can store environment variables with.&lt;/p&gt;

&lt;p&gt;It's worth noting that &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; is self-hostable on your own infrastructure and &lt;a href="https://infisical.com/docs/documentation/getting-started/introduction" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm3j6zaldok3sszvqova.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm3j6zaldok3sszvqova.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Before we can fetch environment variables back into your application, you need to add them to a project in &lt;a href="https://app.infisical.com/" rel="noopener noreferrer"&gt;Infisical Cloud&lt;/a&gt; or in a &lt;a href="https://infisical.com/docs/self-hosting/overview" rel="noopener noreferrer"&gt;self-hosted instance of Infisical&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Okay, let's get started.&lt;/p&gt;

&lt;p&gt;First, install the CLI onto your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MacOS (using brew):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

brew &lt;span class="nb"&gt;install &lt;/span&gt;infisical/get-cli/infisical


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Windows (using scoop):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

scoop bucket add org https://github.com/Infisical/scoop-infisical.git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

scoop &lt;span class="nb"&gt;install &lt;/span&gt;infisical


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Arch Linux (using yay):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yay &lt;span class="nt"&gt;-S&lt;/span&gt; infisical-bin


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Check out the &lt;a href="https://infisical.com/docs/cli/overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for more installation options like Redhat/CentOS/Amazon and Debian/Ubuntu if your system is missing above.&lt;/p&gt;

&lt;p&gt;Next, authenticate with Infisical using the CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

infisical login


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command authenticates the CLI with Infisical Cloud or your self-hosted instance and stores credentials in your system keyring. &lt;/p&gt;

&lt;p&gt;Next, navigate to the root of your project and run the initialization command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

infisical init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command creates a &lt;code&gt;infisical.json&lt;/code&gt; file holding a reference to your project in Infisical Cloud or self-hosted instance; the file can be committed to source control.&lt;/p&gt;

&lt;p&gt;Finally, start your application in local development with the help of the CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

infisical run &lt;span class="nt"&gt;--&lt;/span&gt; &amp;lt;your application start &lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you're using a self-hosted instance of &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, you can run this command instead:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

infisical &lt;span class="nt"&gt;--domain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://your-self-hosted-infisical.com/api"&lt;/span&gt; run &lt;span class="nt"&gt;--&lt;/span&gt; &amp;lt;your application start &lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command fetches environment variables back from the development environment of your project in Infisical and starts up your application with the variables injected. The environment variables become available in the application environment. For example, they're accessible on &lt;code&gt;process.env&lt;/code&gt; in Node.js or on &lt;code&gt;os.environ&lt;/code&gt; in Python.&lt;/p&gt;

&lt;p&gt;While the CLI comes with a few helpful subcommands and flags that you can read more about in the documentation, in practice, the basic command above is all you need 99% of the time.&lt;/p&gt;

&lt;p&gt;Here're some examples for common frameworks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# example with node&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; node index.js

&lt;span class="c"&gt;# example with node (nodemon)&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; nodemon index.js

&lt;span class="c"&gt;# example with Next.js&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; npm run dev

&lt;span class="c"&gt;# example with flask&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; flask run

&lt;span class="c"&gt;# example with django&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; python manage.py runserver

&lt;span class="c"&gt;# example with laravel&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; php artisan serve

&lt;span class="c"&gt;# example with rails&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; bin/rails server

&lt;span class="c"&gt;# example with .NET&lt;/span&gt;
infisical run &lt;span class="nt"&gt;--&lt;/span&gt; dotnet run


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Now you can use environment variables in local development without a .env file and feel confident that your team will not leak anything to source control. You're now also able to view all the environment variables for your application from one central place and avoid any missing environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I trust a secret manager?
&lt;/h2&gt;

&lt;p&gt;I'm including this section because it has been helpful to developers in past articles.&lt;/p&gt;

&lt;p&gt;Adopting a secret manager can be daunting at first and rightfully so. You have to trust that the solution you're working with is secure, that the vendor won't view or tamper with your data, and that the underlying infrastructure will work and deliver environment variables reliably when needed. There is, however, a right tool for every task and using dedicated tooling to manage environment variables is surely better than any manual process that's either not efficient or prone to error.&lt;/p&gt;

&lt;p&gt;The analogy I like to use is password managers like 1Password and Bitwarden. Before using one, I was content with managing dozens of passwords manually and occasionally forgetting them. The minute I started to face &lt;strong&gt;password sprawl&lt;/strong&gt;, however, I was compelled to upgrade my workflow and sign up for a password manager. &lt;/p&gt;

&lt;p&gt;Similarly, in the realm of secret managers, when you're a solo developer, you can use manual approaches to store your environment variables. The minute, however, you start to scale to above five engineers, you start to face &lt;strong&gt;secret sprawl&lt;/strong&gt; and that's where a secret management solution can really help. My suggestions for selecting one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pick a solution that's either open source or made by the big cloud providers; it will be more resilient that way and you can inspect and, in the open source case, make changes to the code if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick something that provides a good developer experience for the size of your team. If you have site reliability engineers and teams for process, you can afford to go with more complex tools. Otherwise, if you're a smaller team, go frictionless and focus on building the rest of your application.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We developers often debate the practicality of using a secret management platform when faced with the need to yet manage another token to access environment variables or secrets. This unfortunately comes off as counterintuitive to many developers who then hesitate on adopting a secret management solution.&lt;/p&gt;

&lt;p&gt;In this article, however, I demonstrate a workflow using a CLI that fetches environment variables and injects them into any application upon starting up; the method avoids  storing any proxy token in a .env file. With this CLI approach, development teams stop risking leaking environment variables to source control by not storing any variables in plaintext in .env files on their machines.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Node.js: Replace your .env file with this awesome tool at scale</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Thu, 11 May 2023 14:41:46 +0000</pubDate>
      <link>https://dev.to/dangtony98/nodejs-replace-your-env-file-with-this-awesome-tool-at-scale-nic</link>
      <guid>https://dev.to/dangtony98/nodejs-replace-your-env-file-with-this-awesome-tool-at-scale-nic</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbctqtbeur3ou5sus1s8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbctqtbeur3ou5sus1s8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When developing applications, handling sensitive information like API keys, database credentials, and configuration settings is crucial. Ensuring these environment variables are managed securely, efficiently, and in sync across the development lifecycle is a common challenge and let’s face it, .env files don’t cut it anymore, well, &lt;a href="https://dev.to/dangtony98/doing-much-better-than-your-env-file-46bg"&gt;for many reasons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I discuss the optimal way to manage environment variables for your Node application with Infisical at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Infisical?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, an open-source, end-to-end encrypted secret management platform that you can store environment variables with. It’s fully self-hostable on your own infrastructure, &lt;a href="https://infisical.com/docs/documentation/getting-started/introduction" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt;, and insanely beautiful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3dcqnrb20ur4dfjua8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3dcqnrb20ur4dfjua8a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; lets you fetch back environment variables at runtime whether it be in local development or production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Before we can fetch environment variables back into your Node application, you need to add them to a project in &lt;a href="https://app.infisical.com/" rel="noopener noreferrer"&gt;Infisical Cloud&lt;/a&gt; or in a &lt;a href="https://infisical.com/docs/self-hosting/overview" rel="noopener noreferrer"&gt;self-hosted instance of Infisical&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Okay, let’s get started.&lt;/p&gt;

&lt;p&gt;First, install the &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;infisical-node&lt;/a&gt; package in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;infisical-node &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, import the SDK and create a client instance with your &lt;a href="https://infisical.com/docs/documentation/platform/token" rel="noopener noreferrer"&gt;Infisical Token&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfisicalClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;infisical-node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InfisicalClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_infisical_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To ensure optimal performance, I’d recommend creating a single instance of the Infisical client and exporting it to be used across your entire app. The reason is because the &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; caches every secret and updates it periodically, reducing excessive calls; this built-in caching makes syncing environment variables seamless at scale.&lt;/p&gt;

&lt;p&gt;I’d also recommend storing the Infisical Token in a &lt;code&gt;.env&lt;/code&gt; file in local development or as the only environment variable in production. This way, you don’t have to hardcode it into your application and can use it to fetch the rest of your environment variables.&lt;/p&gt;

&lt;p&gt;Now you can use the client to fetch secrets for your application on demand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello! My name is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;Now whenever your application needs an environment variable, it can request it from &lt;a href="https://app.infisical.com/" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; on demand. You’re now able to view all the environment variables for your Node application from one central place and avoid any missing environment variables.&lt;/p&gt;

&lt;p&gt;I’d recommend reading into the &lt;a href="https://infisical.com/docs/documentation/getting-started/introduction" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; more to learn more about how to manage environment variables effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, you’re still using a .env file…
&lt;/h2&gt;

&lt;p&gt;One question came up when I first posted this article being: “If the Infisical Token used to fetch other environment variables is stored in a .env file, then doesn’t that defeat the purpose of the tool?”&lt;/p&gt;

&lt;p&gt;The answer is no.&lt;/p&gt;

&lt;p&gt;As mentioned, a big point of using the recommended approach is to keep your environment variables in sync across your team. Oftentimes, new environment variables get introduced to a codebase and &lt;code&gt;.env&lt;/code&gt; files don’t get updated across the team; as a result, applications crash. The issue compounds when your infrastructure gets big and a problem known as “secret sprawl” emerges. As such, &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; provides you the ability to centralize your environment variables so you can update them in one place and have them delivered back to your team and infrastructure from development to production. This is different from what a lot of people do which is directly store dozens of environment variables in &lt;code&gt;.env&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Lastly, from a security perspective, leaking a revokable token is much better than leaking a dozen set of raw environment variables; you avoid leaving any direct traces in source control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Infisical is an awesome platform to streamline environment variables for you and your team. Its &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;open-source&lt;/a&gt; and has a handy &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; that can be used to fetch environment variables back to your Node applications on demand.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Doing much better than your .env file</title>
      <dc:creator>BlackMagiq</dc:creator>
      <pubDate>Wed, 10 May 2023 13:21:26 +0000</pubDate>
      <link>https://dev.to/dangtony98/doing-much-better-than-your-env-file-46bg</link>
      <guid>https://dev.to/dangtony98/doing-much-better-than-your-env-file-46bg</guid>
      <description>&lt;p&gt;Six months ago, I advocated for everyone to stop using &lt;code&gt;.env&lt;/code&gt; files in favor of approaches using secret management platforms. Since then, I've learned and experienced much more about how to manage environment variables effectively. In this article, I argue for why we should reduce the practice of storing all your application environment variables in a &lt;code&gt;.env&lt;/code&gt; file and move to a more sophisticated approach for managing them in local development.&lt;/p&gt;

&lt;p&gt;Before you roast me, I want to make clear that &lt;strong&gt;my position is not that you have to ditch the .env file entirely&lt;/strong&gt;. I'm asserting that &lt;strong&gt;your application's environment variables don't need to be stored directly in a .env file&lt;/strong&gt;. This doesn't mean, however, that you can't store a token in it that pulls in the rest of your environment variables at runtime.&lt;/p&gt;

&lt;p&gt;I also, by the way, want to make clear that &lt;strong&gt;this article is intended for software development teams&lt;/strong&gt; and not security and devops teams that already have this figured out; this article is also not intended for solo developers who can feel free to use .env files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't fix what's not broken
&lt;/h2&gt;

&lt;p&gt;In the beginning, developers hardcoded environment variables into their codebase. After realizing that hardcoding them into source control was suboptimal, we introduced &lt;code&gt;.env&lt;/code&gt; files for separation of concerns that is to split sensitive data from the rest of code.&lt;/p&gt;

&lt;p&gt;In practice, we'd create a &lt;code&gt;.env&lt;/code&gt; file, add environment variables to it, and &lt;code&gt;.gitignore&lt;/code&gt; the file. We'd start up our applications and read the environment variables into them in local development. Unfortunately, we still teach developers this as a staple of software development and proponents tend to say "don't fix what's not broken."&lt;/p&gt;

&lt;p&gt;If you're one of these stubborn proponents, then stop reading; if you're open to improvement and breaking tradition, go on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers have unmet needs
&lt;/h2&gt;

&lt;p&gt;At its core, &lt;code&gt;.env&lt;/code&gt; files are broken and we've all experienced it to some degree depending on the scale of our applications and infrastructure; folks deep in the security and devops department know it. In order to understand my argument for why the current usage of &lt;code&gt;.env&lt;/code&gt; files is broken, it's important to unlearn tradition and break the topic of managing environment variables locally down to first principles. Let's explore what developers need:&lt;/p&gt;

&lt;p&gt;Reliability: We want to make sure that developers have access to the right environment variables at all times. Oftentimes, developers introduce new environment variables and forget to update other developers on the team about the new values. As a result, developers start up their applications and … crash.&lt;/p&gt;

&lt;p&gt;Security: We want to keep our environment variables safe and out of source control. While we want to keep bad actors away from our environment variables, since this article focuses on &lt;code&gt;.env&lt;/code&gt; files that are typically used in development and contain less critical environment variables, I make this my second point.&lt;/p&gt;

&lt;p&gt;Note that my points above generalize across the entire development cycle from development to production and these needs grow with the scale and complexity of application infrastructure. In any case, we seek reliability and security when dealing with environment variables. We want the right environment variables in the right hands and places safely.&lt;/p&gt;

&lt;p&gt;Okay so what's wrong with &lt;code&gt;.env&lt;/code&gt; files?&lt;/p&gt;

&lt;h2&gt;
  
  
  While .env files prevent developers from hardcoding and committing environment variables to source control, they fail the reliability criteria.
&lt;/h2&gt;

&lt;p&gt;In a two person team, it's easy to maintain &lt;code&gt;.env&lt;/code&gt; files because you don't have to share environment variables with many other developers. As your team size grows, however, you start to run into the secret sprawl problem that I mentioned earlier and it becomes unwieldly to manually share environment variables.&lt;/p&gt;

&lt;p&gt;Take for example a microservices architecture where now you have many services, each demanding their own set of environment variables. Here, developers frequently face a phenomenon known as secret sprawl which is when environment variables get scattered across infrastructure and it all becomes unwieldy to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers need to centralize their environment variable management
&lt;/h2&gt;

&lt;p&gt;Naturally, the solution is to store environment variables in one centralized location and have developers fetch them from that place back to their applications. It turns out that centralization is indeed what bigger teams do but even then there is still variation. Sometimes, teams store environment variables in password managers; other times, teams encrypt them and store them directly in a private repository on GitHub. &lt;/p&gt;

&lt;p&gt;These methods work but they typically present an extra step of friction that is having to manually grab or trigger refetching environment variables before starting up an application; you could build a custom script that does the job of pulling secrets and injecting them into an application but that in itself presents a step of friction for you.&lt;/p&gt;

&lt;p&gt;What developers need is a frictionless tool that automatically pulls and injects environment variables into an application. For this, smarter teams use a dedicated tool that's called a secret manager, built to manage environment variables. These solutions like &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, &lt;a href="https://www.vaultproject.io/" rel="noopener noreferrer"&gt;Vault&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html" rel="noopener noreferrer"&gt;AWS Parameter Store&lt;/a&gt;, &lt;a href="https://cloud.google.com/secret-manager" rel="noopener noreferrer"&gt;Google Secret Manager&lt;/a&gt; help securely store environment variables and deliver them back to your infrastructure reliably. When set up correctly, these tools can serve environment variables efficiently across any complex microservices infrastructure from local development through CI/CD pipelines and to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Most developers don't know better
&lt;/h2&gt;

&lt;p&gt;Unfortunately, beyond the security and devops crowd, most developers have never heard of secret managers and the proof is in the number of YouTube videos and views for the topic of secret management versus anything else. Let's face it, secret management isn't considered to be a sexy topic the way artificial intelligence and ChatGPT is.&lt;/p&gt;

&lt;p&gt;The reason secret managers aren't popular is because they are unwieldy. That's right, the tools built to solve the secret sprawl problem I outlined earlier have histoically introduced new problems with undesirable characteristics. On one hand, there is difficulty in getting started; no one wants to watch a course and read through tens of pages of documentation just to learn the basic concepts of how store and fetch back environment variables from a secret manager. On the other hand, the easy tools are closed-source and, well, how can we trust them?&lt;/p&gt;

&lt;p&gt;Okay, I know that I'm going to get a lot of backlash now from die-hard Vault fans but let's be real here. If any secret management tool was as simple as installing the &lt;code&gt;dotenv&lt;/code&gt; package, importing it, and starting up your app, then we'd be seeing mass adoption of secret managers everywhere.&lt;/p&gt;

&lt;p&gt;But we're not.&lt;/p&gt;

&lt;p&gt;Instead, we're stuck with 30M+ downloads per week of the &lt;code&gt;dotenv&lt;/code&gt; package for Node.js alone and a sad statistic of &lt;a href="https://www.ekransystem.com/en/blog/secrets-management/" rel="noopener noreferrer"&gt;10% of organizations worldwide having adopted secret managers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers would love secret managers, if only they were easy to use and trustworthy
&lt;/h2&gt;

&lt;p&gt;At the beginning of this article, I made clear that my position is not that you have to ditch the .env file entirely. I'm asserting that your application's environment variables should not be stored directly in a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;While I have many tips and strategies for managing environment variables, the major one I'll allude to for this article is a hybrid approach that is to use a secret manager in conjunction with a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Instead of storing your application environment variables directly in a &lt;code&gt;.env&lt;/code&gt; file, you can store them in a dedicated secret management platform, preferably one that's easy to use with little overhead. Then, store an access token in the &lt;code&gt;.env&lt;/code&gt; file that your application can use to fetch environment variables from the secret manager at runtime. That's a simple adjustment you can make to improve the reliability of receiving the right set of environment variables at all times across your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's enough, show me what you're suggesting, gimme the code
&lt;/h2&gt;

&lt;p&gt;To keep things simple, I'm going to use &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt;, an open-source, end-to-end encrypted secret management platform that you can store environment variables with. You can also use another secret manager like Vault or AWS Parameter Store that each have their own SDKs that you can use to achieve the recommendation.&lt;/p&gt;

&lt;p&gt;I'm picking Infisical because it's self-hostable on your own infrastructure, &lt;a href="https://infisical.com/docs/documentation/getting-started/introduction" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt;, and beautiful. It's also worth noting that it's self-hostable on &lt;a href="https://infisical.com/docs/self-hosting/deployment-options/fly.io" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt; and Render as well as AWS, Kubernetes etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhicl7h192mko2x2oubaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhicl7h192mko2x2oubaw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyways, we'll be using the &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; to fetch back environment variables at runtime with this example, though there are other SDKs and methods available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Before we can fetch environment variables back into your Node application, you need to add them to a project in Infisical Cloud or in a self-hosted instance of Infisical.&lt;/p&gt;

&lt;p&gt;Okay, let's get started.&lt;/p&gt;

&lt;p&gt;First, install the &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;infisical-node&lt;/a&gt; package in your project:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;infisical-node &lt;span class="nt"&gt;--save&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, import the SDK and create a client instance with your &lt;a href="https://infisical.com/docs/documentation/platform/token" rel="noopener noreferrer"&gt;Infisical Token&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfisicalClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;infisical-node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InfisicalClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_infisical_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To ensure optimal performance, I'd recommend creating a single instance of the Infisical client and exporting it to be used across your entire app. The reason is because the &lt;a href="https://github.com/Infisical/infisical-node" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; caches every secret and updates it periodically, reducing excessive calls; this built-in caching makes syncing environment variables seamless at scale.&lt;/p&gt;

&lt;p&gt;I'd also recommend storing the Infisical Token in a &lt;code&gt;.env&lt;/code&gt; file in local development or as the only environment variable in production. This way, you don't have to hardcode it into your application and can use it to fetch the rest of your environment variables.&lt;/p&gt;

&lt;p&gt;Now you can use the client to fetch secrets for your application on demand:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello! My name is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Now whenever your application needs an environment variable, it can request it from &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;Infisical&lt;/a&gt; on demand. You're now able to view all the environment variables for your Node application from one central place and avoid any missing environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I trust a secret manager?
&lt;/h2&gt;

&lt;p&gt;Adopting a secret manager can be daunting at first and rightfully so. You have to trust that the solution you're working with is secure, that the vendor won't view or tamper with your data, and that the underlying infrastructure will work and deliver environment variables reliably when needed. In many ways, it does feel easier to store environment variables in a decentralized fashion or perhaps centralized but encrypted in a private repository on GitHub.&lt;/p&gt;

&lt;p&gt;There is, however, a right tool for every task and using dedicated tooling to manage environment variables is surely better than any manual process that's either not efficient or prone to error; this is especially true in cases where your infrastructure is sprawled out.&lt;/p&gt;

&lt;p&gt;The analogy I like to use is password managers like 1Password and Bitwarden. Before using one, I was content with managing dozens of passwords manually and occasionally forgetting them. The minute I started to have many different passwords across different services, each satisfying a different requirement, I faced a password sprawl that compelled me to sign up for a password manager because I couldn't keep hitting the "forget my password" button.&lt;/p&gt;

&lt;p&gt;The same is true for secret managers. When you're a solo developer, you can use manual approaches to store your environment variables. The minute you start to scale above five engineers, you should start thinking about maintaining your secret management hygiene. While there is no 100% guarantee for the reliability of any process, you can get close to 99.99% and my suggestions for selecting a secret manager are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pick a solution that's either open source or made by the big cloud providers; it will be more resilient that way and you can inspect and, in the open source case, make changes to the code if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick something that provides a good developer experience for the size of your team. If you have site reliability engineers and teams for process, you can afford to go with more complex tools. Otherwise, if you're a smaller team, go frictionless and focus on building the rest of your application.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;For the longest time, developers defaulted to storing all their environment variables in a &lt;code&gt;.env&lt;/code&gt; file largely because it was the most frictionless way to get up and running locally. Alternatives like other secret management platforms were too cumbersome to adopt and never became mainstream because they were too difficult to use/learn and intended for the security and devops crowd.&lt;/p&gt;

&lt;p&gt;In this article, however, I make clear that the approach of storing all of your environment variables in a &lt;code&gt;.env&lt;/code&gt; file lacks reliability when it comes to keeping your team's environment variables in sync. By using a dedicated secret manager, preferably one with little overhead, and instead keeping a single token in your &lt;code&gt;.env&lt;/code&gt; file that your application can consume and use to fetch the rest of your environment variables, you can preserve the security benefits of separating sensitive data from your codebase whilst ensuring reliability of environment variables across your infrastructure.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
