<?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: Samrose Ahmed</title>
    <description>The latest articles on DEV Community by Samrose Ahmed (@samrose).</description>
    <link>https://dev.to/samrose</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%2F827026%2F5a1402de-cd4e-4bb2-9203-89c26b440b05.jpeg</url>
      <title>DEV Community: Samrose Ahmed</title>
      <link>https://dev.to/samrose</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samrose"/>
    <language>en</language>
    <item>
      <title>How we build a regional cell-based cloud architecture on AWS</title>
      <dc:creator>Samrose Ahmed</dc:creator>
      <pubDate>Tue, 12 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apptrail/how-we-build-a-regional-cell-based-cloud-architecture-on-aws-ggd</link>
      <guid>https://dev.to/apptrail/how-we-build-a-regional-cell-based-cloud-architecture-on-aws-ggd</guid>
      <description>&lt;p&gt;At least for me, building on the cloud gives often gives me unexpected joy. To think that I can deploy servers in Bahrain or Japan from my couch is still something I get excited about!&lt;/p&gt;

&lt;p&gt;At Apptrail, we run completely on the cloud, specifically AWS, and one of the main reasons is how easy it is to launch services in new geographical regions. We deploy our services to independent cloud regions and provide our customers with regional endpoints (e.g. &lt;code&gt;events.us-west-2.apptrail.com&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Here are some of our learnings from building a fully regional service on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are cloud regions?​
&lt;/h2&gt;

&lt;p&gt;Cloud providers have a concept of regions for their cloud. These are isolated geographical regions where their physical infrastructure is hosted and where they offer cloud services. For example, at the time of this article, AWS offers 26 different cloud regions. Software applications built on the cloud can leverage cloud regions to also build a concept of regions in their applications to improve their services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cellular architecture​
&lt;/h3&gt;

&lt;p&gt;To understand regionality, it's good to understand &lt;em&gt;cellular architecture&lt;/em&gt;. Cellular (or cell-based) architecture is a way of separating systems into isolated &lt;em&gt;cells&lt;/em&gt; to reduce the blast radius from something going wrong. The idea is that a failure shouldn't ever cross cells, and so cellularization is a way of creating those independent partitions. The actual method of choosing a cell can be anything, from random based on ID to logical like geographical region. You can also have nested cells for further isolation (e.g. &lt;em&gt;Large volume customers in US West region&lt;/em&gt; could be a particular cell). AWS Availability zones, for example, are also sub-regional cells. All in all, cellularization is a very powerful way of designing available systems, you can &lt;a href="https://www.youtube.com/watch?v=swQbA4zub20"&gt;learn more about it here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why regions exist​
&lt;/h3&gt;

&lt;p&gt;Regions, then, are just cells that are based on geographical region. Regions serve several purposes. From an availability and reliability perspective, regions are at the center of a cloud's reliability strategy. In a cellular architecture, regions serve as the first and most principal cells. They ensure that there is a logical containment of resources that are isolated from others. This helps prevent widespread outages.&lt;/p&gt;

&lt;p&gt;Regions do refer to actual geographic regions, so this is also an important part of why they exist. One benefit of this is latency. Providing a way for customers to ensure that their workloads run in a particular region helps them with running workloads close to their customers.&lt;/p&gt;

&lt;p&gt;Another important usecase is compliance and data sovereignty. Many countries are passing legislation requiring user data and other sensitive data to be physically stored in locations under their jurisdiction. Cloud regions are a way to ensure compliance with such regulations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi region architectures​
&lt;/h2&gt;

&lt;p&gt;Because cloud providers do the hard work of making sure all their services are available in isolated regions, one benefit customers get is being able to run multi region workloads. Multi region architecture is a way to get another layer of reliability beyond multi availability zone. You can, for example, run a load balanced service across multiple regions using Route 53 for latency based routing and health check based failover. One can also use regions for data preservation and backup, e.g. with Amazon S3. Region wide outages are pretty rare at AWS so active multi region for services is likely overkill (as it may also come with downsides like cross region data transfer), but everyone has their availability requirements and multi region architectures are a powerful tool to leverage for increased availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regionalized architectures​
&lt;/h2&gt;

&lt;p&gt;A regionalized architecture is one where the regionality is part of the interface of the service. For example, in regional architectures, one has dedicated regional endpoints that clients use for each supported region. Each regional service in a regional architecture should be independent of other instances running in other regions.&lt;/p&gt;

&lt;p&gt;As an example, say we have an image processing API. Our clients use this API to upload, process, and retrieve videos. To regionalize this API, we can deploy the API to multiple regions and offer endpoints like &lt;code&gt;region1.videoapi.example.com&lt;/code&gt; and &lt;code&gt;region2.videoapi.example.com&lt;/code&gt; for our clients to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Difference between multi region and regionalized architectures​
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hQVHe4Zw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/regional-diagram-ef9b5ea0c5dec022647f24f931252019.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hQVHe4Zw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/regional-diagram-ef9b5ea0c5dec022647f24f931252019.png" alt="" width="880" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Comparison between regional (left) and multi region architectures&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The key difference between multi region and regionalized architectures is that in regional architectures, the region is part of the contract of the service, whereas in multi region architectures it is solely part of the implementation. In a multi region architecture, regions are used as cells for increased availability or as a failover. There is no guarantee that a specific customer's requests will run in a specific region. Rather, the customer doesn't even have to know about the concept of region vis-à-vis the service. In a regional architecture, however, the region is part of the public API, and customers choose or are informed of the region they are associated with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing regions for a regional architecture​
&lt;/h3&gt;

&lt;p&gt;When building a regionalized architecture, one needs to pick a list of geographical regions to support and a methodology to assign them. You're likely deployed on a cloud, so a simple decision is to choose your regions to correspond to cloud regions. This is &lt;a href="https://apptrail.com/docs/applications/guide/regions"&gt;what we do at Apptrail&lt;/a&gt;, for example. One can rename them, or just use the same names, which is what we do at Apptrail ourselves.&lt;/p&gt;

&lt;p&gt;However, a one-to-one mapping is not necessary. You can also come up with regions that correspond to multiple cloud regions. For example, a region structure could look as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Region&lt;/th&gt;
&lt;th&gt;AWS Region(s)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;us&lt;/td&gt;
&lt;td&gt;us-east-1, us-west-2, us-east-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eu&lt;/td&gt;
&lt;td&gt;eu-west-1, eu-west-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jp&lt;/td&gt;
&lt;td&gt;ap-northeast-1, ap-northeast-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;in&lt;/td&gt;
&lt;td&gt;ap-south-1, ap-south-2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Regionalization scheme using multi region cells&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Such a scheme gives one some benefit of each application region consisting of multiple cloud regions, which can improve availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use a regional architecture​
&lt;/h2&gt;

&lt;p&gt;Most services likely don't need to be fully regionalized. Unlike multi-regionality, which is solely a technical engineering decision, choosing to regionalize your public APIs or services is more so a product decision. It should generally serve some need or purpose for your customer. We observe common usecases:&lt;/p&gt;

&lt;h4&gt;
  
  
  Data residency requirements​
&lt;/h4&gt;

&lt;p&gt;Regionalization of your services is a way of allowing your customers to ensure their data is stored and processed in a specific region. This is often requested due to regulatory reasons.&lt;/p&gt;

&lt;h4&gt;
  
  
  Latency​
&lt;/h4&gt;

&lt;p&gt;For other applications, minimizing client latency is highly important. Keeping requests in the region closest to a customer is a way to achieve this. However, as keeping requests in region is not inherently a strict requirement, complete regionalization may or may not be the correct approach here, as a single endpoint with latency based routing may also fulfill the requirements. The desired experience of the customer is important to consider here (e.g. do you want your customer to have to think of regions?).&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing components to regionalize​
&lt;/h2&gt;

&lt;p&gt;When evaluating a regional architecture, a natural question is what components to regionalize. Specifically, which services to have a publicly regional interface for. There are several considerations here, and the answer goes back to why one is using a regional architecture in the first place. A useful heuristic we use is one between &lt;em&gt;control planes&lt;/em&gt; and &lt;em&gt;data planes&lt;/em&gt;. Generally, control plane services shouldn't be regional, but dataplane services can be. To understand why, we may consider the common actions we do in the control plane: e.g. billing, user management, or other global configuration. These often have single region dependencies and are relatively infrequent. For us, it's neither important nor desirable to have these be regionalized. On the other hand, our data plane processes that process and store important data are regionalized.&lt;/p&gt;

&lt;p&gt;Note that while this is a general guideline that we ourselves have found useful, it's in no way prescriptive. There are many cases where one may make the control plane regionalized as well. In general, the reason for regionalization should be central to this decision. One should consider how regionalizing a service will help or prevent them from achieving that goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we deploy to many regions​
&lt;/h2&gt;

&lt;p&gt;Infrastructure and deployment automation is key to being able to maintain consistency, reliability, and understandability while deploying many services across different regions. Thankfully, infrastructure as code solutions, particularly the AWS CDK, make this much easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Staged deployment using Waves​
&lt;/h3&gt;

&lt;p&gt;We use a concept of &lt;em&gt;waves&lt;/em&gt; when deploying software at Apptrail. Going back to cellular architecture, a wave is essentially a set of cells to deploy to concurrently. For example, currently, our waves are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wave&lt;/th&gt;
&lt;th&gt;Apptrail Regions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wave 1&lt;/td&gt;
&lt;td&gt;ap-south-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wave 2&lt;/td&gt;
&lt;td&gt;eu-west-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wave 3&lt;/td&gt;
&lt;td&gt;us-west-2, us-east-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Our current waves at Apptrail&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Deploying to one wave at a time ensures that faulty changes don't cause global outages. Combined with bake times (adding wait times between waves to monitor for degradation) and automated rollbacks, waves can help ensure that you don't have catastrophic failures. We've found them to be very useful for staging our changes. You can &lt;a href="https://aws.amazon.com/builders-library/automating-safe-hands-off-deployments/"&gt;learn more about waves here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure as Code - CDK​
&lt;/h3&gt;

&lt;p&gt;Completely automating your infrastructure is essential when deploying to many regions since one is duplicating one's entire application and services each time they deploy to a new region. We use the AWS CDK to help us do this. CDK is a wrapper around CloudFormation that lets you write your infrastructure as real code (e.g. we use Typescript). It makes building reusable abstractions (called &lt;em&gt;constructs&lt;/em&gt;) as easy as writing a class or a function (&lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html"&gt;Learn more about it here&lt;/a&gt;, we think it's one of the coolest things AWS offers!).&lt;/p&gt;

&lt;p&gt;The CDK also comes with useful high level abstractions out of the box, so you don't have to reinvent the wheel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mBRrI_vp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/apptrail-waves-ffbffb671a220d613cf67fdf09505129.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mBRrI_vp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/apptrail-waves-ffbffb671a220d613cf67fdf09505129.png" alt="" width="563" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A pipeline deploying one of our regional services to one of our waves&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For example, we use &lt;a href="https://aws.amazon.com/blogs/developer/cdk-pipelines-continuous-delivery-for-aws-cdk-applications"&gt;CDK Pipelines&lt;/a&gt; for deploying all of our infrastructure at Apptrail. In CDK Pipelines, stages and &lt;em&gt;waves&lt;/em&gt; are supported natively so you can easily deploy cellular applications. At Apptrail, we've developed a standard &lt;em&gt;Pipeline&lt;/em&gt; construct that sets up our standard waves and makes creating a regionalized service conforming to Apptrail regions and waves very simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other considerations around regional architectures​
&lt;/h2&gt;

&lt;p&gt;Here are some other things we've learned building regional applications on AWS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use separate AWS accounts per region​
&lt;/h4&gt;

&lt;p&gt;This is general AWS best practice but reinforces thinking of each instance of a service deployed in a region as separate with clearly delineated blast radiuses.&lt;/p&gt;

&lt;h4&gt;
  
  
  Managing cost​
&lt;/h4&gt;

&lt;p&gt;Regionalization inherently comes with some additional cost. However, when an application is architected correctly, the additional cost due to regionalization should mainly be a fixed cost per region, which is generally negligible at scale. Regionalized services shouldn't generally have excessive have cross-region data transfer (databases and other global data is often the exception, but this should be low cost).&lt;/p&gt;

&lt;h4&gt;
  
  
  Global data​
&lt;/h4&gt;

&lt;p&gt;A common consideration when evaluating a regionalized or multi region architecture is what to do with global data. There's no one answer here. Keeping in mind our earlier discussion on choosing components to regionalize and data planes &amp;amp; control planes, there are several ways we could deal with this. For example, we could keep global data in one control plane region, and our regionalized data plane services can depend on this control plane. This is what we use ourselves at Apptrail. However, this may or may not be acceptable. If latency is the primary motivation for regionalization, then this is less than ideal. There are several ways to deal with this, including DynamoDB Global Tables and database replication, that are beyond the scope of this article (see this &lt;a href="https://www.youtube.com/watch?v=2e29I3dA8o4"&gt;video&lt;/a&gt; for some more information). On the other hand, if the main reason for regionalization is data residency, and our control plane only stores non-sensitive configuration, then this is a more fitting approach.&lt;/p&gt;

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

&lt;p&gt;As it gets easier and easier to deploy to the cloud, and with increased concern about data sovereignty, regional architectures are becoming more common. This gave you an overview of how we easily maintain our regional services on AWS at Apptrail. You might not need regionalization for your next project, but I hope this was helpful and informative.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What do you think of regionalization, do you use it in your applications? Feel free to reply.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>aws</category>
      <category>software</category>
    </item>
    <item>
      <title>The difference between internal and customer facing audit logs</title>
      <dc:creator>Samrose Ahmed</dc:creator>
      <pubDate>Mon, 07 Mar 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apptrail/the-difference-between-internal-and-customer-facing-audit-logs-2p65</link>
      <guid>https://dev.to/apptrail/the-difference-between-internal-and-customer-facing-audit-logs-2p65</guid>
      <description>&lt;p&gt;As a software company, you likely store audit logs internally for debugging, security, and compliance. But can your customers access these audit logs self service?&lt;/p&gt;

&lt;p&gt;Learn about the difference between storing audit logs internally and offering your customers self service access to their own audit logs.&lt;/p&gt;

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

&lt;p&gt;Audit logs are a record of activity in an application. They help answer questions like who, what, where, when, and how a specific action occurred, and what resources it affected. They are used for debugging, security, monitoring, and compliance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internal audit logs​
&lt;/h2&gt;

&lt;p&gt;A software company should store audit logs internally as a best practice. They are needed to be for developer debugging and also to be able to answer support questions like what happened during a specific incident. Maintaining audit logs is also required for compliance with common standards like SOC II.&lt;/p&gt;

&lt;p&gt;Internal audit logs are generally stored in log providers like Cloudwatch or DataDog, or object stores like Amazon S3. They are only accessible by employees of the software company, preferably specifically the security or DevOps teams. An employee should be able to query the logs to extract specific data in response to common questions like who performed a specific action.&lt;/p&gt;

&lt;p&gt;In a multitenant SaaS company, each audit log is likely associated with a specific tenant. For example, if we examine an audit log for a DeleteUser operation, the audit log will contain information about which tenant the operation was related to. However, employees generally have access to all tenants' audit logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can a customer access their audit logs?​
&lt;/h3&gt;

&lt;p&gt;In a situation where a SaaS company is following best practices and storing audit logs for all actions in their application, how does a customer of the company access audit logs relating to their account? Because the audit logs are internal, not partitioned by tenant, and not accessible except to internal employees, the process for a customer to access their audit logs is manual. A common flow is a customer creates a support ticket, an engineer or support associate queries the internal logs, and posts the information back to the customer in the ticket. Companies often build internal tooling to make this process easier for their employees.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kdEQutxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0cuoeuymnxob7tykwac8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kdEQutxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0cuoeuymnxob7tykwac8.png" alt="" width="827" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Disadvantages of only maintaining internal audit logs​
&lt;/h4&gt;

&lt;p&gt;Exclusively storing audit logs internally without offering a way for customers to easily consume those audit logs comes with many drawbacks. The SaaS company is essentially serving as a human proxy to the internal audit logs system. First, it is reactive, meaning the customer can only request their audit logs after an event has occurred, when often they need them most when the event is occurring (or even before to perform security monitoring). Second, the entire process is manual, which wastes both the SaaS company's and customers' time and severely limits the number of audit logs that the customer can request. Thirdly, it prevents customers from being to extract full value out of their audit logs, and keeps customers from having visibility into activity in their account.&lt;/p&gt;

&lt;h2&gt;
  
  
  External, or customer facing, audit logs​
&lt;/h2&gt;

&lt;p&gt;External audit logs are audit logs that the customers of a SaaS product can access self service.&lt;/p&gt;

&lt;p&gt;A key first requirement here, naturally, is that each customer is only able to access their own audit logs and not any other customer's audit logs. This requires storing the audit logs so that they are partitioned by customer. It also requires building an API service that lets authenticated customers query their own logs.&lt;/p&gt;

&lt;p&gt;Such a system allows a SaaS customer to access their audit logs automatedly without needing to involve the SaaS company.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of self service audit logs​
&lt;/h3&gt;

&lt;p&gt;Being able to access audit logs self service opens many usecases for SaaS customers. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The customer is free to query and retrieve as many audit logs as they want. Ideally, they should be able to continuously export all their audit logs out of the SaaS for analytics, monitoring, or archival.&lt;/li&gt;
&lt;li&gt;Both the SaaS owner and SaaS customer do not need to expend manual effort to exchange audit logs.&lt;/li&gt;
&lt;li&gt;Customers can build proactive security monitoring systems that use audit logs for threat detection, using SIEM or other tools. This allows customers to make realtime use of their audit events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, externally facing audit logs give SaaS customers full insight into their SaaS activity. This enables them to consume and use SaaS audit logs themselves for security monitoring, auditing, risk management, or any other use that requires audit events.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should I use internal or external audit logs?​
&lt;/h2&gt;

&lt;p&gt;Internal and external audit logs are not mutually exclusive, rather they are complementary.&lt;/p&gt;

&lt;p&gt;When evaluating using internal or external audit logs, the answer is fairly simple. Every company should maintain internal audit logs. This is a best security practice, and is mandated by compliance standards like SOC 2. It is required for debugging and to be able to answer questions in the case of an incident.&lt;/p&gt;

&lt;p&gt;SaaS companies should also offer their customers a way to access their own audit logs self service. This is the best way to ensure that your customers have the best security posture, and to prevent yourself from having to deal with manual audit requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary​
&lt;/h2&gt;

&lt;p&gt;To summarize, SaaS companies should store audit logs internally and should also offer a system for their customers to easily access their own audit logs without a manual process. To outline the differences between internal and external audit logs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Internal audit logs&lt;/th&gt;
&lt;th&gt;External audit logs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Used by&lt;/td&gt;
&lt;td&gt;SaaS company employees&lt;/td&gt;
&lt;td&gt;SaaS customers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Log providers, object stores&lt;/td&gt;
&lt;td&gt;Custom: API layer + data store or managed (&lt;a href="https://apptrail.com"&gt;Apptrail&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer access&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Self service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We can see that internal and external audit logs serve two different purposes and that internal audit logs are not a substitute for external audit logs. Internal audit logs are a baseline measure that lets the &lt;em&gt;employees&lt;/em&gt; of a SaaS company audit all API and user activity whereas external, or customer facing, audit logs allow customers to access their own audit logs.&lt;/p&gt;

&lt;p&gt;If you're an engineer or owner working on a SaaS product, keep in mind building externally facing audit logs for your customers.&lt;/p&gt;

</description>
      <category>software</category>
      <category>logging</category>
      <category>programming</category>
      <category>security</category>
    </item>
    <item>
      <title>S3 POST Policy - The hidden S3 feature you haven't heard of</title>
      <dc:creator>Samrose Ahmed</dc:creator>
      <pubDate>Mon, 14 Feb 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apptrail/s3-post-policy-the-hidden-s3-feature-you-havent-heard-of-k2g</link>
      <guid>https://dev.to/apptrail/s3-post-policy-the-hidden-s3-feature-you-havent-heard-of-k2g</guid>
      <description>&lt;p&gt;Say you're building an application and you need to let your users upload files to S3. How would you go about it?&lt;/p&gt;

&lt;p&gt;Particularly, imagine our clients are uploading a lot of files of different sizes, and are sensitive to latency.&lt;/p&gt;

&lt;p&gt;Let's walk through a journey of AWS APIs, and explore a little known feature of S3 called &lt;em&gt;POST Policies&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Presigned URLs​
&lt;/h2&gt;

&lt;p&gt;Your immediate instinct may be to use &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html"&gt;S3 presigned URLs&lt;/a&gt;. Presigned URLs let you create a URL that you can share and allow a user to download or upload to an S3 bucket. You create the presigned URL server side using IAM credentials that have the valid S3 permissions and then share the URL to allow user actions. Clients simply use HTTP clients to connect to the URL. You can set an expiry time to any date time to ensure the access is short lived and you can also attach an IAM policy to the presigned URL to limit the permissions the client has.&lt;/p&gt;

&lt;p&gt;All in all, presigned URLs are pretty powerful and sound like a great choice for allowing credential-less S3 actions. They have one major limitation, however.&lt;em&gt;S3 presigned upload urls require you to know the Content length before hand.&lt;/em&gt; Because of the way presigned URLs work, using AWS4 Signatures, the Content-Length is a required component when generating the presigned URL. This means we can't return one presigned URL and allow our clients to upload objects of variable size while it is not expired.&lt;/p&gt;

&lt;p&gt;As a workaround, we can have the client request a presigned URL every time they want to perform an upload. This is not necessarily a big deal, and may be perfectly suitable for many scenarios.&lt;/p&gt;

&lt;p&gt;However, this results in an additional call for every upload and may not be desirable. For example, say we want our clients to have a short lived session where they can upload a large number of objects, and latency is important.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new API using temporary credentials​
&lt;/h2&gt;

&lt;p&gt;Presigned URLs don't seem to work well for our usecase, so let's try a new approach. AWS IAM offers APIs to &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html"&gt;request temporary security credentials&lt;/a&gt;. There's a few different APIs, but let's see if we can use &lt;a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html"&gt;AssumeRole&lt;/a&gt; to return temporary credentials to our client.&lt;/p&gt;

&lt;p&gt;As an approach, we can call STS AssumeRole server side and return temporary IAM credentials to our client. We can use IAM &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session"&gt;session policies&lt;/a&gt; to limit the S3 permissions the client has access to. We can also use the &lt;a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters"&gt;DurationSeconds&lt;/a&gt; parameter to limit the validity of the credentials, but only up to a minimum of 15 minutes.&lt;/p&gt;

&lt;p&gt;Our clients would then use the credentials and upload files using the AWS SDK. If we're offering this as a part of our API, we'd likely want to write a language native client that wraps the AWS SDK and takes care of refreshing the credentials.&lt;/p&gt;

&lt;p&gt;Security-wise, you may feel icky having to return credentials using your API, but the approach is generally sound as long as the credentials are short lived and you are giving access to authenticated callers with narrow permissions.&lt;/p&gt;

&lt;p&gt;This approach works, but besides having to implement this API, comes with several downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dealing with unsigned credentials.&lt;/li&gt;
&lt;li&gt;Our client needs to depend on heavyweight AWS SDKs, rather than a simple HTTP Client.&lt;/li&gt;
&lt;li&gt;We can't control the size of the object our client uploads. This can be a concern with untrusted or semi-trusted clients, who could upload very large files to our S3 bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enter POST Policy​
&lt;/h2&gt;

&lt;p&gt;We're dissatisfied with our previous approach. Let's explore a lesser known Amazon S3 feature: &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html"&gt;POST Policy&lt;/a&gt;. You might be thinking, &lt;em&gt;"POST?, isn't it S3 PUT object?"&lt;/em&gt;, and you're right, but Amazon actually introduced a POST API for uploading S3 objects to enable browser based S3 uploads.&lt;/p&gt;

&lt;p&gt;As a note, you'll generally hear of POST Policy in the context of browser based uploads, but there's nothing inherent preventing us from using it in any environment.&lt;/p&gt;

&lt;p&gt;A POST policy is essentially a JSON document that you create, sign, and return to your clients to specify what conditions are required for a successful POST object upload.&lt;/p&gt;

&lt;h4&gt;
  
  
  What does a POST policy look like?​
&lt;/h4&gt;

&lt;p&gt;POST policies are fairly powerful: you can specify the exact date time the policy expires and include conditions on properties like the &lt;em&gt;ACL&lt;/em&gt;, &lt;em&gt;Bucket&lt;/em&gt;, &lt;em&gt;Key prefix&lt;/em&gt;, and &lt;em&gt;Content length range&lt;/em&gt; (minimum and maximum). You can also use operators like "starts_with" in addition to exact matches to add dynamic logic to your policy.&lt;/p&gt;

&lt;p&gt;Let's take a look at an example POST policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expiration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-02-14T13:08:46.864Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"acl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bucket-owner-full-control"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"bucket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-bucket"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"starts-with"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stuff/clientId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"content-length-range"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1048576&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10485760&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The policy results in the following conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The policy expires on Mon Feb 14 2022 13:08:46 UTC. After this time, any client using the policy to perform a POST upload will get a 403 error.&lt;/li&gt;
&lt;li&gt;The ACL on the object must be &lt;code&gt;Bucket owner full control&lt;/code&gt;, which ensures we, as the bucket owner, have full control of uploaded objects.&lt;/li&gt;
&lt;li&gt;We specify a specific bucket by name (&lt;code&gt;my-bucket&lt;/code&gt;) to allow uploads to.&lt;/li&gt;
&lt;li&gt;The S3 key of the uploaded object must have a specific prefix. Here, we use it ensure our client only has permission to upload under their prefix by specifying their client ID as the key prefix.&lt;/li&gt;
&lt;li&gt;The uploaded object must be between 1MB and 10MB in size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Signing the policy​
&lt;/h4&gt;

&lt;p&gt;After forming a POST policy, we have to &lt;em&gt;sign&lt;/em&gt; the policy using valid IAM credentials (with the requisite permissions), similar to how we sign presigned URLs. You can view the complete procedure on calculating the signature &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html#sigv4-post-signature-calc"&gt;here&lt;/a&gt; but it essentially involves Base64 encoding the policy and signing it using AWS SigV4. Unfortunately, unlike presigned URLs, the AWS SDKs don't provide helper methods to create the POST Policy. You can write it yourself or consult the few examples and community libraries out there. If you're using Java/JVM, check out &lt;a href="https://github.com/minio/minio-java/blob/master/api/src/main/java/io/minio/PostPolicy.java"&gt;Minio's implementation&lt;/a&gt; as a well maintained reference.&lt;/p&gt;

&lt;h4&gt;
  
  
  Letting our clients perform POST uploads​
&lt;/h4&gt;

&lt;p&gt;Once we've created the POST policy, our client's can use the POST policy to perform POST S3 uploads. S3 POST uploads are multipart form data requests to the S3 Bucket URL (e.g. &lt;code&gt;https://examplebucket.s3-us-west-2.amazonaws.com/&lt;/code&gt;) containing the key's specified in the POST policy. As a code example in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;uuid&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Add an endpoint for the client to request a POST Policy
&lt;/span&gt;&lt;span class="n"&gt;post_policy_form_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/postPolicyFormData"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;post_policy_form_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"x-amz-date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"20220213T233352Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"x-amz-signature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"efa9bbc&amp;lt;...&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"acl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"bucket-owner-full-control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"x-amz-security-token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;...&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"x-amz-algorithm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"AWS4-HMAC-SHA256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"x-amz-credential"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"ASIA&amp;lt;..&amp;gt;."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"eyJleHBpcmF...&amp;lt;base64 encoded policy&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;".json"&lt;/span&gt;
&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"file_content"&lt;/span&gt;
&lt;span class="n"&gt;multipart_form_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;post_policy_form_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;upload_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://examplebucket.s3-us-west-2.amazonaws.com"&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upload_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;multipart_form_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;POST policies satisfy all of our requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are using signed policies without raw credentials.&lt;/li&gt;
&lt;li&gt;Our clients can make HTTP requests without the AWS SDK.&lt;/li&gt;
&lt;li&gt;We can granularly control the expiration, permissions, and object properties,&lt;/li&gt;
&lt;li&gt;Our clients can upload objects as long as the POST policy is not expired without needing to make additional requests.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We took a short look at the S3 object upload landscape, and discovered a powerful feature called POST Policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usecases​
&lt;/h3&gt;

&lt;p&gt;Lets take a look at some usecases that POST policies unlock:&lt;/p&gt;

&lt;h4&gt;
  
  
  Browser based uploads​
&lt;/h4&gt;

&lt;p&gt;Particularly for large sized files, POST policies provide a convenient way to enable your client's to upload files client side, without needing to go through a server proxy. This can be convenient if you're using API Gateway or Lambda which have content size limits. Additionally, this can give your client better upload speed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Short lived low-latency upload sessions​
&lt;/h4&gt;

&lt;p&gt;As we discussed, we can use POST policies to let our clients maintain a short lived, controlled session with specific permissions where they can upload many objects of variable size, without any additional latency besides S3 latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guidance​
&lt;/h3&gt;

&lt;p&gt;As a takeway, if you are looking to incorporate S3 object upload from your clients in your application, follow the general guidance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer presigned URLs. They're simpler, are already supported in the AWS SDKs and are well documented.&lt;/li&gt;
&lt;li&gt;Use POST policies otherwise. As we discussed, if latency is important, or you want form based browser uploads.&lt;/li&gt;
&lt;li&gt;Don't use the second approach we discussed (using &lt;code&gt;AssumeRole&lt;/code&gt;). You can generally achieve the equivalent using a POST policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are you using POST policies, or do you know of an interesting usecase they enable? Feel free to reply.&lt;/p&gt;

</description>
      <category>software</category>
      <category>aws</category>
      <category>serverless</category>
      <category>s3</category>
    </item>
    <item>
      <title>What makes a good audit trail?</title>
      <dc:creator>Samrose Ahmed</dc:creator>
      <pubDate>Sat, 05 Feb 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apptrail/what-makes-a-good-audit-trail-42ff</link>
      <guid>https://dev.to/apptrail/what-makes-a-good-audit-trail-42ff</guid>
      <description>&lt;p&gt;At Apptrail, we obsess over audit trails and how to make them most valuable for our customers, so we thought we'd examine some real world examples of audit trails and see what makes some stand out from others.&lt;/p&gt;

&lt;p&gt;There's a lot of details and requirements that go into building an audit trails solution, from availability and immutability to security and delivery, but, let's examine some of the features that differentiate solutions from one another.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's an audit trail anyway?​
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you're already familiar with audit trails, feel free to skip this section.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An audit trail is a way to record user or API activity and surface that information. Generally, an audit trail lets admins or users answer the &lt;em&gt;Who&lt;/em&gt;, &lt;em&gt;When&lt;/em&gt;, &lt;em&gt;Where&lt;/em&gt;, and &lt;em&gt;What&lt;/em&gt; of an action. Audit trails can be used to monitor suspicious activity or replay activity in the aftermath of an event.&lt;/p&gt;

&lt;p&gt;We use &lt;em&gt;audit trails&lt;/em&gt;, &lt;em&gt;audit logs&lt;/em&gt;, and &lt;em&gt;audit events&lt;/em&gt; here interchangeably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some real world examples​
&lt;/h2&gt;

&lt;p&gt;Lets take a whirl through some popular tools that offer audit logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Admin​
&lt;/h3&gt;

&lt;p&gt;Google Workspace has a mature audit logs offering. Let's see what we can do:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PnnNuGiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/gadmin1-82647547805b5fba819d9c6619f8cece.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PnnNuGiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/gadmin1-82647547805b5fba819d9c6619f8cece.png" alt="G Admin audit logs" width="880" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Immediately, we can see all the recent actions that took place with Google workspace. The information contains the event name, description, time, who did the action (&lt;em&gt;actor&lt;/em&gt;), and the IP address associated with the actor. The data is filterable and offers a basic CSV export through the UI. Google offers several audit logs, and data retention (how long the data is stored), ranges from 6 to 15 months.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stripe​
&lt;/h3&gt;

&lt;p&gt;Stripe uses logs in a few places. Let's take a look.&lt;/p&gt;

&lt;h4&gt;
  
  
  Security history​
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GEtDpOmY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/stripe1-bbc2ef7620b5aa3760c98ab8b8244714.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GEtDpOmY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/stripe1-bbc2ef7620b5aa3760c98ab8b8244714.png" alt="Stripe security history" width="880" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These events contain important actions, and similarly add information about the when, who, and where of the action. The results are accessible in the Dashboard UI, and exportable to CSV.&lt;/p&gt;

&lt;h4&gt;
  
  
  Request logs​
&lt;/h4&gt;

&lt;p&gt;Stripe also offers developer oriented request logs. These are often used for debugging but are also essentially audit logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aoo_I9lC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/stripe2-eb6db5bd9019140a58eee0e445783115.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aoo_I9lC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://apptrail.com/assets/images/stripe2-eb6db5bd9019140a58eee0e445783115.png" alt="Stripe request logs" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Stripe request logs contain full request, response, and context data for every HTTP request made to the API. They're viewable through the Stripe Dashboard UI and filterable on each dimension. Stripe request logs have a 15 month data retention period.&lt;/p&gt;

&lt;h3&gt;
  
  
  Github​
&lt;/h3&gt;

&lt;p&gt;Github offers a pretty full featured &lt;a href="https://docs.github.com/en/enterprise-cloud@latest/admin/user-management/managing-organizations-in-your-enterprise/streaming-the-audit-logs-for-organizations-in-your-enterprise-account"&gt;audit logs solution&lt;/a&gt;to its Enterprise customers. You can access Github audit logs by 1) using the web UI, 2) polling with the REST API, and 3) streaming to destinations like S3 or Splunk using their audit log streaming feature.&lt;/p&gt;

&lt;p&gt;Streaming audit logs is an important feature that a lot of audit logs solutions lack. It unlocks a lot of usecases, like being able to explore a large amount of data or retaining ownership over data, that a UI or API based approach don't allow.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS CloudTrail​
&lt;/h3&gt;

&lt;p&gt;AWS offers audit logs for most of its services using &lt;a href="https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html"&gt;CloudTrail&lt;/a&gt;. You can query audit logs from the Console UI and using the AWS APIs. You can also deliver AWS audit logs to your S3 bucket or CloudWatch logs group. CloudTrail offers a pretty limited (heavily paginated and throttled) &lt;a href="https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_LookupEvents.html"&gt;LookupEvents&lt;/a&gt; API to query audit data but in general nudges you towards sending audit logs to S3.&lt;/p&gt;

&lt;h3&gt;
  
  
  And more​
&lt;/h3&gt;

&lt;p&gt;There's many more software services offering audit logs. For the sake of brevity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://support.zendesk.com/hc/en-us/articles/4408828001434"&gt;Zendesk&lt;/a&gt; offers audit logs through a UI, with filters, CSV export, and a REST query API. Logs are retained for 1 year, which is not configurable.&lt;/li&gt;
&lt;li&gt;1Password offers a UI based &lt;a href="https://support.1password.com/activity-log/"&gt;activity log&lt;/a&gt; with viewable and searchable activity including event, actor, and date, but omitting context such as IP. The activity log has a non configurable retention of 6 months. Additionally, they offer a more extensive REST &lt;a href="https://blog.1password.com/introducing-events-api/"&gt;Events API&lt;/a&gt; for programmatic access and access to more audit events.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison​
&lt;/h2&gt;

&lt;p&gt;That covers a bit about audit trails, how customers use them, and what elements make them most useful to customers. Summarizing our survey:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Filterable?&lt;/th&gt;
&lt;th&gt;Exportable?&lt;/th&gt;
&lt;th&gt;API access?&lt;/th&gt;
&lt;th&gt;Streaming?&lt;/th&gt;
&lt;th&gt;Configurable retention?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;G Admin&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1Password&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zendesk&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Github&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudTrail&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We can see audit trails vary on several dimensions:&lt;/p&gt;

&lt;h4&gt;
  
  
  Self service access​
&lt;/h4&gt;

&lt;p&gt;Admins being able to access the audit logs themselves, without needing a manual request, is the first step to a customer facing audit trail. At the bare minimum, a web UI to explore audit logs should be provided.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exportability​
&lt;/h4&gt;

&lt;p&gt;Viewing audit logs in a UI is good for one off usecases, but users often want to export the data for analysis with other tools.&lt;/p&gt;

&lt;h4&gt;
  
  
  Programmatic API access​
&lt;/h4&gt;

&lt;p&gt;Users want to be able to interact with their data programatically, for scripting, workflows, etc. The API should allow for querying events by time and filtering on fields. These APIs are generally paginated and throttled, as there is an unbounded number of audit logs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Audit log streaming​
&lt;/h4&gt;

&lt;p&gt;When there's a large amount of audit logs, a poll based API is not sufficient, and users will want to have their data pushed into tools like S3 or Splunk for data analysis.&lt;/p&gt;

&lt;h4&gt;
  
  
  Data retention​
&lt;/h4&gt;

&lt;p&gt;Audit logs must be immutable to protect their integrity, but they are usually retained for a period of time, ranging from months to years. Ideally, this should be configurable by the user. Adding audit log streaming also automatically enables this, as it gives the customer ownership of their audit data (essentially unlimited retention).&lt;/p&gt;

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

&lt;p&gt;That was a short overview of some popular tools and how they offer audit trails to their customers. We can see there are a range of different features that go into an audit logs solution, and software providers vary in what they currently offer.&lt;/p&gt;

&lt;p&gt;Do you have any examples of great audit logs? Feel free to share.&lt;/p&gt;



&lt;p&gt;Interested in adding world class audit logs to your own SaaS?&amp;lt;!-- --&amp;gt; &lt;a href="https://apptrail.com?utm_source=blog"&gt;&lt;strong&gt;Apptrail&lt;/strong&gt;&lt;/a&gt; &amp;lt;!-- --&amp;gt;is fully managed Audit trails as a Service.&amp;lt;!-- --&amp;gt; &lt;a href="https://dev.to/docs/applications/guide"&gt;Learn more&lt;/a&gt; or&amp;lt;!-- --&amp;gt; &lt;a href="https://apptrail.com/signup?utm_source=blog"&gt;Get started&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>auditlogs</category>
      <category>saas</category>
      <category>software</category>
      <category>security</category>
    </item>
  </channel>
</rss>
