<?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: CKMo</title>
    <description>The latest articles on DEV Community by CKMo (@ckmo).</description>
    <link>https://dev.to/ckmo</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%2F1101653%2F46a2ee1a-9350-4fd8-81cd-05f31fd370a5.jpg</url>
      <title>DEV Community: CKMo</title>
      <link>https://dev.to/ckmo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ckmo"/>
    <language>en</language>
    <item>
      <title>Security is Usability — Examining Cybersecurity Erosion</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Thu, 03 Oct 2024 17:37:49 +0000</pubDate>
      <link>https://dev.to/ckmo/security-is-usability-examining-cybersecurity-erosion-2mh1</link>
      <guid>https://dev.to/ckmo/security-is-usability-examining-cybersecurity-erosion-2mh1</guid>
      <description>&lt;p&gt;It's often said that humans are the weakest link in security and social engineering is easier than hacking. This is true — but there's another facet that isn’t discussed enough: &lt;strong&gt;when the security design causes friction, the system will deteriorate and lead to gaps over time due to user action (or inaction).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Great security solutions rarely fail on technical merits, but rather on human ones. However, it is possible to avoid this with &lt;strong&gt;security design which focuses on usability. The two — security and usability — do not need to be opposing forces.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We’ll cover several aspects of this topic:&lt;/li&gt;
&lt;li&gt;Security is usability to avoid cybersecurity erosion&lt;/li&gt;
&lt;li&gt;Why do we care about cybersecurity erosion?&lt;/li&gt;
&lt;li&gt;What are some design choices to mitigate cybersecurity erosion?&lt;/li&gt;
&lt;li&gt;Actionable takeaways&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security is usability
&lt;/h2&gt;

&lt;p&gt;This is a key pillar of Pomerium’s security philosophy: &lt;strong&gt;you’re only as secure as your least compliant user.&lt;/strong&gt;&lt;br&gt;
The concept flows naturally into why some solutions suffer from what we call &lt;strong&gt;“Cybersecurity Erosion”&lt;/strong&gt;: the solution’s architecture is technically sound but the design causes user friction and frustration, which in turn results in users looking for ways to overcome, go around, or even ignore the solution itself.&lt;/p&gt;

&lt;p&gt;This is tangentially related to the concept of &lt;a href="https://www.youtube.com/watch?v=cmWQF2FDlG8" rel="noopener noreferrer"&gt;“Sustainable Security” covered by Sam Ainsworth&lt;/a&gt;. It’s a pervasive trend: even when correctly implemented, many security solutions degrade over time due to human factors. The designers simply didn’t take into account how the human element would erode the security solution over time in pursuit of “efficiency.”&lt;/p&gt;

&lt;p&gt;As for why coin a new term, it’s because Sam Ainsworth’s coverage focuses specifically on a system’s technical aspects while this piece will focus on the system’s &lt;em&gt;usability&lt;/em&gt; when it comes to user experience. In the end, &lt;strong&gt;security is usability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the security system gets in the way of productivity and workflow, even the most technically sound solution will erode as the human element seeks to navigate around the system or even take it down, piece by piece.&lt;/p&gt;

&lt;p&gt;Here’s a few all-too-common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decision-fatigue:&lt;/strong&gt; When users are bombarded with frequent alerts and notifications, they become desensitized. Many users tend to end up muting alerts and other notification screens, which directly weakens the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Password_fatigue" rel="noopener noreferrer"&gt;Password-fatigue&lt;/a&gt;&lt;/strong&gt;: Without Single Sign-On (SSO), users juggling many passwords may resort to reusing them, compromising security. Password managers solve the interim problem but cause decision-fatigue when frequent prompts lower user acuity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inconsistent best-practices&lt;/strong&gt;: A good example is network segmentation. When DevOps teams become too inundated with resource requirements and start cutting corners on network segmentation by not segmenting correctly or even adding new applications to existing network segments instead of creating isolated networks. The best practice isn’t followed, resulting in cybersecurity erosion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Misapplied Access Control&lt;/strong&gt;: In a rush, developers may incorrectly implement &lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OpenID Connect (OIDC)&lt;/a&gt;, creating vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client-based access&lt;/strong&gt;: From usability to performance and reliability problems or even being considered unnecessarily invasive, client-based solutions add friction in the form of human design issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why is cybersecurity erosion bad?
&lt;/h2&gt;

&lt;p&gt;Let’s jump right to why it’s a concept worth discussing alongside “security is usability”. It’s impossible to ignore cybersecurity erosion as it has familiar costs and consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management overhead&lt;/strong&gt; — Architecture requiring constant upkeep due to overhead will face de-prioritization or languish as resources are re-allotted or cost-cutting measures come into place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security friction&lt;/strong&gt; — Security is often seen as a productivity inhibitor, but it doesn’t have to be designed that way. When users find security measures to be in the way of their workflow, they inevitably look for alternative pathways in search of a more efficient user experience. As a result, security teams begin viewing internal users as a problem to be managed, and the organization suffers internal conflict.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither symptom should be new. However, attributing these symptoms to a &lt;strong&gt;root cause of architectural design&lt;/strong&gt; is new. When viewed in this manner, the following questions become relevant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why are we choosing between security and cost-reduction?&lt;/strong&gt; If the security system is designed to minimize overhead and resource-drain, all discussions around efficiency in the future only need to ask if the organization is still maintaining the highest security posture with the minimal upkeep costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Is there security architecture that doesn’t inhibit workflow?&lt;/strong&gt; Minimizing user frustration should be a new key objective when evaluating the existing security infrastructure. The architecture should keenly focus on smoothing out the user’s experience to avoid cybersecurity erosion. Otherwise, the safest security solution in the world will only be dismantled over time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tangibly, this means forward thinking organizations must evaluate solutions based on how well they’ll last, which often involves asking how it affects internal productivity and workflow. The fundamental architecture should actively avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frustrating the user.&lt;/strong&gt; Any amount of workflow friction will lead to users trying to overcome the access control measures over time. The water of rivers will erode even the most durable stone, so the best answer is to design for the user’s workflow of least resistance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Being difficult to implement.&lt;/strong&gt; Access control isn’t implemented just once, but continuously over time as the organization grows and expands. When new environments or applications are created, the security should be easy and straightforward to implement to minimize mishaps. The system should not be overly prescriptive with implementation or you risk the practitioners being forced to architect around it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Being difficult to maintain.&lt;/strong&gt; No system can avoid needing maintenance, but it can be architected to either minimize the maintenance or enable a straightforward maintenance cycle. You never want your system to fail because the practitioners were overwhelmed by maintenance overload.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tackling cybersecurity erosion with usability-first
&lt;/h2&gt;

&lt;p&gt;Let’s share some of our successful learnings when designing for usability to mitigate cybersecurity erosion.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clientless access&lt;/li&gt;
&lt;li&gt;Speed and latency&lt;/li&gt;
&lt;li&gt;Simple configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If &lt;strong&gt;you’re only as secure as your least compliant user&lt;/strong&gt;, then we need to design accordingly. Thoughtful consideration for how users interface and interact with the system will pay long-term dividends for sustainable security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clientless access&lt;/strong&gt;&lt;br&gt;
Ask any user how they want to use the internet; does “logging into a client” make it into their preferred user flow? No — they usually say some form of “open the browser, type in a URL, hit enter.”&lt;/p&gt;

&lt;p&gt;You need to minimize the amount of obstacles between users getting what they want, or they’ll look for ways around it. This is why we made clientless access a key Pomerium feature from the outset instead of as an after thought. For end users, this core feature translates to improved productivity and reduced costs for their business through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced user friction&lt;/strong&gt;: No client, no additional hoops to jump through. Additionally, removing the need to memorize an additional set of credentials for logging into a client reduces user burden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal management burden&lt;/strong&gt;: Removing the need to install and update a client across all user devices lightens a burden for IT management. If there’s nothing to misconfigure or forget, then there’s nothing that can be eroded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security is usability.&lt;/strong&gt; There is no better way to design around cybersecurity erosion than to remove all semblances of the obstacle itself. With clientless access, most users don’t even know they’re going through Pomerium’s access control measures when accessing resources! As a nice bonus, this results in more productive employees when time is not lost dealing with clunky clients. This simple principle embodies the concept of security without friction, meaning the security team’s mandates are aligned with the company’s core desires for increasing productivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed and latency&lt;/strong&gt;&lt;br&gt;
This is specifically about your access control solution: &lt;strong&gt;Is the connection fast and does it minimize latency?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's face it, slow connections and lagging applications are productivity killers. Every second wasted waiting for a page to load or an action to register is a second stolen from your workday. Across a large organization, these delays can add up to significant lost hours.&lt;/p&gt;

&lt;p&gt;That's why Pomerium prioritizes speed through a design enabling edge deployments. This minimizes latency and ensures a smooth, responsive experience. We've seen real-world results: helping Fortune 100 organizations slash latency from a sluggish 1.5 seconds down to a snappy 20 milliseconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple configuration&lt;/strong&gt;&lt;br&gt;
In today's fast-paced development environment with continuous integration and deployment (CI/CD), security solutions can become bottlenecks. Developers are constantly adding features and updating applications, and security needs to keep pace.&lt;/p&gt;

&lt;p&gt;Gone are the days of one-time cybersecurity infrastructure deployments. As companies evolve, they find themselves constantly integrating their security solution with new acquisitions, expansions, and even mergers. This integration process can be a vulnerability minefield as traditional security implementations often require significant infrastructure changes, leading to misconfigurations and security gaps.&lt;/p&gt;

&lt;p&gt;Traditional security solutions often require complex configurations that can introduce room for errors. This is especially true when deploying at scale in a CI/CD world. Even a seemingly small error rate, like 0.1%, can leave hundreds or even thousands of applications vulnerable. This cybersecurity erosion becomes a major liability over time, and we once again find the root cause to be: usability.&lt;/p&gt;

&lt;p&gt;So what did Pomerium do differently to address this? We worked backwards from what we believe first principles are for what adding security should look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error-Proof&lt;/strong&gt;: Minimize the potential for human error during implementation, preventing disastrous security breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Integration&lt;/strong&gt;: Integrate seamlessly with existing infrastructure without forcing disruptive changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Testing&lt;/strong&gt;: Simplify testing for potential misconfigurations and ensure a smooth security posture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was a difficult problem to solve. How can we offer a solution that allows companies to simply "add" security without disrupting their operations? We saw that many providers required extensive reconfiguration of existing infrastructure to fit their model. This created unnecessary complexity and discouraged adoption. Additionally, their implementation processes were often cumbersome and time-consuming.&lt;/p&gt;

&lt;p&gt;In the end, our architectural model enables the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployed at edge&lt;/strong&gt;: A key feature of Pomerium is being able to be deployed however you want it onto any existing infrastructure with minimal changes. The fewer parts that need to be moved, the better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Programmatic deployments&lt;/strong&gt;: We provide an API and SDK for developers so access control is being added the same way they would ship code. This achieves our goal of minimizing the potential for human error and misconfigurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified access controls&lt;/strong&gt;: Because Pomerium is already greenlit by the security team, the only necessary tests are whether Pomerium was correctly added in front of each application. These application-centric deployments should have no security gap because they are shipped with the company’s pre-defined access controls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architectural decision ensures the solution serves the organization, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actionable takeaways for any organization
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Evaluate your cybersecurity system for sustainable usability or potential erosion.&lt;/li&gt;
&lt;li&gt;Explore replacements which prioritize usability in its design to minimize erosion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As your organization grows and evolves, it's crucial to ensure your cybersecurity doesn't become brittle and prone to gaps. Here's what you can do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Conduct a Cybersecurity Sustainable Usability Audit&lt;/strong&gt;: Take a close look at your current security system. Is it designed to adapt to changes and integrations, or does it require frequent updates and adjustments? Identify points where misconfigurations or gaps could occur during deployment or modification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore Erosion-Resistant Solutions&lt;/strong&gt;: Research options that prioritize a secure-by-design approach — for humans. The point of this write-up is to emphasize the importance of minimizing human deviation factors in your organization’s security system. This means looking for solutions designed to be secure without interfering with users or adding to the IT team’s burdens.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Liked what you read about Pomerium?&lt;br&gt;
Pomerium’s design results in sustainable and usable security without cybersecurity erosion.&lt;/p&gt;

&lt;p&gt;DevOps teams only need to configure Pomerium once through Zero then give API access to development teams. Developers can then add Pomerium’s access control and deploy to production with full confidence that the company’s security policies are being enforced. Finally, users can now access applications using the browser just like they would with any other website while Pomerium continuously verifies each action against identity and context.&lt;/p&gt;

&lt;p&gt;Beautiful, isn’t it? We invite you to &lt;a href="https://www.pomerium.com/docs/quickstart?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=security-is-usability" rel="noopener noreferrer"&gt;try out Pomerium today&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>infrastructure</category>
      <category>devops</category>
      <category>secops</category>
    </item>
    <item>
      <title>Skip the SSO tax with Pomerium</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Fri, 31 May 2024 23:04:16 +0000</pubDate>
      <link>https://dev.to/ckmo/skip-the-sso-tax-with-pomerium-1me</link>
      <guid>https://dev.to/ckmo/skip-the-sso-tax-with-pomerium-1me</guid>
      <description>&lt;p&gt;Robust security is no longer optional in the modern threat landscape. Data breaches can damage business reputation and result in costly lawsuits. Yet, traditional Single Sign-On (SSO) solutions often come with a hefty price tag, forcing companies to choose between security and their bottom line.&lt;/p&gt;

&lt;p&gt;The status quo shouldn't force companies to choose between security and their bottom line. Skip the SSO tax and &lt;a href="https://www.pomerium.com/docs/capabilities/authentication"&gt;add SSO to any self-hosted application&lt;/a&gt; with Pomerium.&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%2F04hcd1zaodbrvda61qfs.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%2F04hcd1zaodbrvda61qfs.png" alt="Common single sign-on options" width="418" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SSO tax?
&lt;/h2&gt;

&lt;p&gt;The SSO tax is when vendors charge users to access SSO as a service. This essentially means that customers pay extra money for a feature that companies should consider a basic security best practice. A common analogy is, “buying a car, paying for the brakes.”&lt;/p&gt;

&lt;p&gt;Here’s the problem: those are some expensive brakes. The &lt;a href="http://ssotax.org"&gt;ssotax.org&lt;/a&gt; wall of shame shows significant pricing increases as a result of software vendors realizing they can force companies to pay for a basic security feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits of Single Sign-On (SSO)
&lt;/h2&gt;

&lt;p&gt;SSO is a game-changer for user access management, especially for organizations juggling multiple cloud applications. Imagine logging into one central location (an &lt;a href="https://www.pomerium.com/blog/5-lessons-learned-connecting-every-idp-to-oidc/"&gt;identity provider&lt;/a&gt; like Google or Okta) and seamlessly accessing all your work apps without needing individual logins for each. This not only improves user experience but also enhances security, as it provides the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved User Experience:&lt;/strong&gt; Employees can access all their work applications with a single login, reducing frustration and wasted time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security:&lt;/strong&gt; SSO centralizes user authentication, making it easier to enforce access controls and manage user identities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced IT Burden:&lt;/strong&gt; Onboarding and offboarding employees becomes much simpler with centralized user management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Risk of Credential Theft:&lt;/strong&gt; By reducing the number of logins needed, SSO minimizes the risk of compromised credentials.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why is SSO Tax a problem?
&lt;/h2&gt;

&lt;p&gt;The "SSO tax" creates a significant barrier for businesses, particularly smaller companies. Here's why it's a problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unfair Pricing:&lt;/strong&gt; Charging a premium for a core security feature like SSO is akin to selling a car and requiring an extra fee for brakes. It's a fundamental requirement, not a luxury add-on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Security Adoption:&lt;/strong&gt; High SSO costs can force companies to choose between user convenience and security, potentially leaving them vulnerable to cyberattacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hinders Cloud Adoption:&lt;/strong&gt; The "SSO tax" discourages businesses from adopting cloud-based solutions due to the additional cost of implementing SSO across multiple platforms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vendors might argue that SSO is a luxury feature and not necessary for small- and medium-sized businesses (SMBs), but that’s not true in practice. Not having SSO means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaling difficulties:&lt;/strong&gt; Onboarding and offboarding employees becomes difficult to manage at scale. The more applications you have, the bigger the scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple access points:&lt;/strong&gt; The purpose of single sign-on is to have one strong access point instead of multiple weak ones. This exposes multiple attack vectors for possible exploitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential fatigue:&lt;/strong&gt; Forcing employees to keep track of multiple login credentials only results in increased chance of lost or stolen details. Moreover, password reset requests inundate IT management with unnecessary tickets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While larger companies can afford to pay the extra SSO pricing tiers, SMBs can’t always afford to pay for enormous markups. Inevitably, when companies cannot afford SSO and hold sensitive customer data, they expose this data, leading to downstream security implications for customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the SSO tax actually cause software to be insecure?
&lt;/h2&gt;

&lt;p&gt;Grip Security discussed the problem with over 100 CISOs and found that &lt;a href="https://www.grip.security/blog/why-sso-doesnt-protect-80-of-your-saas"&gt;“80% of SaaS applications used by employees are not in their SSO portals,”&lt;/a&gt; listing the &lt;strong&gt;SSO licensing cost as the #1 reason for this predicament&lt;/strong&gt;. So yes: the situation absolutely forces companies to choose between security and cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  But vendors must be charging SSO for a reason, right?
&lt;/h2&gt;

&lt;p&gt;There are some valid reasons why vendors might charge extra for SSO:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development and Maintenance:&lt;/strong&gt; Integrating SSO functionality requires additional development work and ongoing maintenance to ensure compatibility with various identity providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supporting Multiple Identity Providers:&lt;/strong&gt; Each identity provider has its own protocols and APIs, requiring tailored integrations. Supporting a wide range of providers increases development and maintenance complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization Needs:&lt;/strong&gt; Some companies might require custom configurations for their SSO implementation, adding to the vendor's workload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the above holds some merit, the following is also true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disproportionate Pricing:&lt;/strong&gt; The upsell cost for SSO often goes far beyond what's reasonable to cover development and maintenance. It can be a significant multiplier of the base package, making it a luxury for smaller businesses that need it most.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shifting Priorities:&lt;/strong&gt; Charging a premium for SSO incentivizes profit over security. It creates a situation where companies have to choose between affordability and best practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardization Ignored:&lt;/strong&gt; The sheer variety of identity providers can be a challenge, but industry standards exist to simplify integrations. Vendors who leverage these standards can reduce development costs and offer SSO at a more reasonable price.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Ethical Dilemma
&lt;/h2&gt;

&lt;p&gt;Ultimately, the "SSO tax" creates an ethical dilemma for vendors. While development costs exist, charging exorbitant fees makes it harder for businesses to prioritize security. Ideally, vendors should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Offer SSO in Base Packages:&lt;/strong&gt; Consider SSO a core feature, not an expensive add-on. In today's cloud-based world, secure access management is essential.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Develop Standardized Integrations:&lt;/strong&gt; Leveraging industry standards can streamline development and reduce costs associated with supporting multiple identity providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide Transparent Pricing:&lt;/strong&gt; Vendors should clearly outline the costs associated with SSO and avoid hidden fees or excessive markups.
To those SMBs and even larger companies that would like to cut costs, Pomerium can alleviate some of that for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does Pomerium workaround the SSO tax?
&lt;/h2&gt;

&lt;p&gt;While many companies will write endless blogs shaming vendors for implementing an SSO tax, Pomerium believes in solution-oriented discussions. &lt;a href="https://console.pomerium.app/create-account"&gt;Pomerium Zero&lt;/a&gt; allows you to implement SSO for your self-hosted applications without the burden of the SSO tax. Here's what makes Pomerium stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free and Open Source:&lt;/strong&gt; Pomerium Zero is a free, open-source solution. You don't have to pay any licensing fees or hidden charges to enjoy the benefits of SSO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to Implement:&lt;/strong&gt; Pomerium Zero is designed for ease of use. It integrates seamlessly with your existing infrastructure and requires minimal configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure and Scalable:&lt;/strong&gt; Pomerium Zero prioritizes security without sacrificing performance. It offers robust access controls and scales to meet the needs of your growing business.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empowering Businesses of All Sizes:&lt;/strong&gt; Whether you're a small startup or a large enterprise, Pomerium Zero makes secure SSO accessible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even better, Pomerium can &lt;a href="https://www.pomerium.com/docs/capabilities/authentication#sso-support-for-legacy-applications"&gt;add SSO to legacy applications&lt;/a&gt; that do not have built-in SSO. Simply put Pomerium in front of your legacy application, implement SSO through Pomerium, and voila — you don't need to change the application at all.&lt;/p&gt;

&lt;p&gt;Pomerium Zero offers this as a basic feature. The immediate ROI scales linearly with every single application your company uses where you self-host and pay to unlock SSO. If ten internal applications cost $20/user/month for SSO, Pomerium saves $200/user/month.&lt;/p&gt;

&lt;h2&gt;
  
  
  We use SAML. Do we have to keep paying the SSO tax?
&lt;/h2&gt;

&lt;p&gt;While we highly suggest shifting to OIDC, companies that cannot shift away from SAML can find an OIDC compliant federating identity provider (such as &lt;a href="https://aws.amazon.com/cognito/"&gt;Amazon Cognito&lt;/a&gt;) to implement SSO through Pomerium and save on the SSO tax.&lt;/p&gt;

&lt;p&gt;Have other questions about a specific application or your custom identity provider? Feel free to reach out to us on our &lt;a href="https://discuss.pomerium.com/"&gt;Discuss forums&lt;/a&gt; to ask how you can save on the SSO tax today.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>howto</category>
      <category>sso</category>
      <category>access</category>
    </item>
    <item>
      <title>Securing TiddlyWiki with Pomerium</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Mon, 11 Mar 2024 20:31:42 +0000</pubDate>
      <link>https://dev.to/ckmo/securing-tiddlywiki-with-pomerium-518o</link>
      <guid>https://dev.to/ckmo/securing-tiddlywiki-with-pomerium-518o</guid>
      <description>&lt;p&gt;This guide will show you how to add authentication and authorization to an instance of &lt;a href="https://tiddlywiki.com/static/TiddlyWiki%2520on%2520Node.js.html"&gt;TiddlyWiki on NodeJS&lt;/a&gt; with Pomerium. Note that Pomerium can secure any web application, so the steps within can be easily replicated for your web app of choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is TiddlyWiki on Node.js
&lt;/h2&gt;

&lt;p&gt;TiddlyWiki is a personal wiki and a non-linear web notebook for organizing and sharing information.&lt;/p&gt;

&lt;p&gt;It is available in two forms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a single HTML page&lt;/li&gt;
&lt;li&gt;As a &lt;a href="https://www.npmjs.com/package/tiddlywiki"&gt;Node.js application&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this guide, you will run Pomerium and your TiddlyWiki Node.js application in Docker containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How you will secure TiddlyWiki
&lt;/h2&gt;

&lt;p&gt;Securing access to TiddlyWiki involves two steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring Pomerium to forward specific user session data in an unsigned header to TiddlyWiki&lt;/li&gt;
&lt;li&gt;Configuring TiddlyWiki to accept a special request header for trusted authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this way, you can implement single sign-on (SSO) for your TiddlyWiki instance, which means an authorized user only needs to authenticate once to access the application.&lt;/p&gt;

&lt;p&gt;To configure TiddlyWiki, you'll set its &lt;a href="https://tiddlywiki.com/static/ListenCommand.html"&gt;ListenCommand&lt;/a&gt; to use the &lt;code&gt;authenticated-user-header&lt;/code&gt; parameter. You'll configure Pomerium to forward the user's &lt;code&gt;email&lt;/code&gt; claim in an unsigned header to TiddlyWiki.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;p&gt;If you completed our &lt;a href="https://www.pomerium.com/docs/quickstart"&gt;Quickstart guide&lt;/a&gt;, you should have a working Pomerium project with the following YAML files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven't completed the Quickstart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/install/"&gt;Docker Compose&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;config.yaml&lt;/code&gt; file for your Pomerium configuration&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;docker-compose.yaml&lt;/code&gt; file for your Docker configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set up Pomerium
&lt;/h3&gt;

&lt;p&gt;Add the following code in your &lt;code&gt;config.yaml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;authenticate_service_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://authenticate.pomerium.app&lt;/span&gt;

&lt;span class="na"&gt;jwt_claims_headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;X-Pomerium-Claim-Email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;

&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://wiki.localhost.pomerium.io&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://tiddlywiki:8080&lt;/span&gt;
    &lt;span class="na"&gt;pass_identity_headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Replace with your email address&lt;/span&gt;
                &lt;span class="na"&gt;is&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user@example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review the configuration file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://www.pomerium.com/docs/reference/jwt-claim-headers"&gt;&lt;code&gt;jwt_claims_headers&lt;/code&gt;&lt;/a&gt; setting will forward the user's email address in an unsigned, HTTP request header. The header follows the custom format specified in the file (in this case, &lt;code&gt;X-Pomerium-Claim-Email&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.pomerium.com/docs/reference/routes/pass-identity-headers-per-route"&gt;&lt;code&gt;pass_identity_headers&lt;/code&gt;&lt;/a&gt; setting tells Pomerium to forward all identity headers to the upstream application&lt;/li&gt;
&lt;li&gt;The attached policy authorizes users with a matching email address to access TiddlyWiki. Pomerium will forward the address specified in the policy to TiddlyWiki as an unsigned identity header.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set up Docker Compose services
&lt;/h3&gt;

&lt;p&gt;Add the following code in your &lt;code&gt;docker-compose.yaml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pomerium&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cr.pomerium.com/pomerium/pomerium:latest&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.yaml:/pomerium/config.yaml:ro&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;443:443&lt;/span&gt;

  &lt;span class="na"&gt;tiddlywiki_init&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elasticdog/tiddlywiki:latest&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./wiki:/tiddlywiki&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mywiki'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--init'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;server'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;tiddlywiki&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elasticdog/tiddlywiki:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8080&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./wiki:/tiddlywiki&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mywiki&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--listen&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;host=0.0.0.0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;authenticated-user-header=X-Pomerium-Claim-Email&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tiddlywiki_init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you test your services, make sure the value of &lt;code&gt;authenticated-user-header&lt;/code&gt; matches the value of the custom header defined in &lt;code&gt;config.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run Docker Compose:&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;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test TiddlyWiki
&lt;/h2&gt;

&lt;p&gt;In your browser, navigate to your TiddlyWiki instance. Pomerium will prompt you to authenticate against its hosted identity provider.&lt;/p&gt;

&lt;p&gt;After successful authentication, Pomerium will redirect you to your TiddlyWiki instance:&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%2F6basbdfj86hchcp3aax1.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%2F6basbdfj86hchcp3aax1.png" alt="Adding a note in the TiddlyWiki dashboard" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great job! You successfully secured TiddlyWiki behind Pomerium.&lt;/p&gt;

&lt;p&gt;Want to secure something else instead? Check out our &lt;a href="https://www.pomerium.com/docs/guides"&gt;guides&lt;/a&gt;, or if it's not there, reach out on our &lt;a href="https://discuss.pomerium.com/"&gt;forums&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>tiddlywiki</category>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Securing Grafana for Web Access</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Tue, 27 Feb 2024 16:39:36 +0000</pubDate>
      <link>https://dev.to/ckmo/securing-grafana-for-web-access-29lo</link>
      <guid>https://dev.to/ckmo/securing-grafana-for-web-access-29lo</guid>
      <description>&lt;p&gt;This guide will demonstrate how to secure an instance of Grafana behind Pomerium proxy to provide users with a seamless login to Grafana using your identity provider.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Grafana?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; is an open-source analytics visualization and monitoring tool. It provides many user-contributed Dashboards that make it popular for enthusiasts as well as professionals.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Note: This guide uses GitHub as the pre-configured Identity Provider (IdP), but you can use any supported IdP.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/install/"&gt;Docker Compose&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A pre-configured &lt;a href="https://www.pomerium.com/docs/identity-providers"&gt;identity provider&lt;/a&gt; (IdP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the Pomerium &lt;a href="https://www.pomerium.com/docs/quickstart"&gt;Quick-start guide&lt;/a&gt; to run Pomerium in a containerized Docker environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Grafana Route
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;config.yaml&lt;/code&gt; file, add the following Grafana route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://grafana.localhost.pomerium.io&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://grafana:3000&lt;/span&gt;
  &lt;span class="na"&gt;host_rewrite_header&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;pass_identity_headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;is&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user@example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.pomerium.com/docs/reference/routes/headers#host-rewrite"&gt;&lt;code&gt;host_rewrite_header&lt;/code&gt;&lt;/a&gt; rewrites the &lt;code&gt;Host:&lt;/code&gt; header to match an incoming header value. Without this option enabled, Grafana will throw a &lt;code&gt;403: Origin not allowed&lt;/code&gt; error after login when you attempt to add users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This behavior is due to a CSRF check added in Grafana v8.3.5 (this guide uses v9.2.4) that requires the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin"&gt;Origin request header&lt;/a&gt; to match the server origin.&lt;/p&gt;

&lt;p&gt;See this &lt;a href="https://github.com/grafana/grafana/issues/45117#issuecomment-1033842787"&gt;GitHub issue&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Grafana to use JWT Verification
&lt;/h2&gt;

&lt;p&gt;Configuring Grafana to use JWT authentication makes it possible for Grafana to accept identity claims sent upstream by Pomerium.&lt;/p&gt;

&lt;p&gt;Since you're not using a &lt;code&gt;grafana.ini&lt;/code&gt; file to configure your Grafana instance, you can override Grafana's configuration using environment variables. See the &lt;a href="https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#override-configuration-with-environment-variables"&gt;Grafana docs&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, add the Grafana Docker image as a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;grafana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/grafana:latest&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:3000&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_SIGNOUT_REDIRECT_URL=https://grafana.localhost.pomerium.io/.pomerium/sign_out&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_JWT_ENABLED=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_JWT_HEADER_NAME=X-Pomerium-Jwt-Assertion&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_JWT_EMAIL_CLAIM=email&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_JWT_JWK_SET_URL=https://grafana.localhost.pomerium.io/.well-known/pomerium/jwks.json&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GF_AUTH_JWT_CACHE_TTL=60m&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./grafana-storage:/var/lib/grafana&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the environment variables do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_SIGNOUT_REDIRECT_URL&lt;/code&gt;: signs users out of Pomerium when they sign out of Grafana&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_JWT_ENABLED&lt;/code&gt;: enables JWT authentication (Grafana disables it by default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_JWT_HEADER_NAME&lt;/code&gt;: tells Grafana which HTTP header to look at for the JWT (see &lt;a href="https://www.pomerium.com/docs/capabilities/getting-users-identity"&gt;Identity Verification&lt;/a&gt; for more information)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_JWT_EMAIL_CLAIM&lt;/code&gt;: associates the &lt;code&gt;email_claim&lt;/code&gt; in the JWT with the email of the Grafana user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_JWT_JWK_SET_URL&lt;/code&gt;: defines the URL with the signing key to validate the JWT&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GF_AUTH_JWT_CACHE_TTL&lt;/code&gt;: sets a 60-minute cache time for the token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congratulations, your Grafana now has a secured route. Let's add users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add users to Grafana
&lt;/h2&gt;

&lt;p&gt;At this stage, Grafana is configured to use the &lt;code&gt;email&lt;/code&gt; claim in the JWT to associate an incoming connection with a user (you will configure Pomerium to include identity information via the JWT in the next section).&lt;/p&gt;

&lt;p&gt;But, the user first must exist in Grafana to be associated. Otherwise, you will see the following error in the browser after authenticating:&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="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User not found"&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;To avoid this error, create a user with administrator privileges. (If you plan on administering Grafana through a direct connection to the service, skip this section.)&lt;/p&gt;

&lt;p&gt;To add users without requiring them to accept an invitation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Log in to Grafana directly as an admin user at &lt;code&gt;https://grafana.localhost.pomerium.io&lt;/code&gt; (if this is your first time signing up for Grafana, &lt;code&gt;admin&lt;/code&gt; is the &lt;a href="https://grafana.com/docs/grafana/v9.0/setup-grafana/configure-grafana/#security"&gt;default username and password&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;strong&gt;Server Admin&lt;/strong&gt;, &lt;strong&gt;Users&lt;/strong&gt;&lt;br&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%2Fsneinwmd7aafkcwau9ga.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%2Fsneinwmd7aafkcwau9ga.png" alt="The users option under the server admin menu" width="449" height="559"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caution: This is distinct from the &lt;strong&gt;Users&lt;/strong&gt; option under the &lt;strong&gt;Configuration&lt;/strong&gt; cog wheel, which will only finalize a new user when they accept an invite via email or link.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;strong&gt;New user&lt;/strong&gt; to create a new user. Make sure that the email address matches the one provided by Pomerium via your IdP. If you want to check the data provided by Pomerium in the JWT, you can access the special endpoint &lt;code&gt;/.pomerium&lt;/code&gt; from any Pomerium route to view it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After creating a new user in Grafana, that user should be logged in automatically when they access Grafana from the Pomerium route (after first authenticating with your IdP, of course).&lt;/p&gt;

&lt;h1&gt;
  
  
  Manage access at scale
&lt;/h1&gt;

&lt;p&gt;First, ensure Grafana is up to date to take advantage of &lt;code&gt;auto_sign_up&lt;/code&gt;, as it is only available for JWT as of version 8.4.0.&lt;/p&gt;

&lt;p&gt;The steps outlined above work to confirm the configuration for small teams, but adding users individually and manually does not scale for larger organizations. To add users to Grafana at scale, you can use the Grafana's &lt;code&gt;auto_sign_up&lt;/code&gt; configuration to auto sign up users as they log in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[auth]&lt;/span&gt;
&lt;span class="py"&gt;signout_redirect_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;https://grafana.localhost.pomerium.io/.pomerium/sign_out&lt;/span&gt;
&lt;span class="nn"&gt;[auth.jwt]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;header_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;X-Pomerium-Jwt-Assertion&lt;/span&gt;
&lt;span class="py"&gt;email_claim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
&lt;span class="py"&gt;jwk_set_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;https://grafana.localhost.pomerium.io/.well-known/pomerium/jwks.json&lt;/span&gt;
&lt;span class="py"&gt;cache_ttl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;60m&lt;/span&gt;
&lt;span class="py"&gt;username_claim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sub ;sets the username to the value of the "sub" claim&lt;/span&gt;
&lt;span class="py"&gt;auto_sign_up&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true ;sets the login to automatically create a new user if one doesn't exist&lt;/span&gt;
&lt;span class="nn"&gt;[users]&lt;/span&gt;
&lt;span class="py"&gt;auto_assign_org&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true ;auto assigns the user to the existing default organization&lt;/span&gt;
&lt;span class="py"&gt;auto_assign_org_role&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Editor ;auto assigns the user the "Editor" role&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the value of &lt;code&gt;auto_assign_org_role&lt;/code&gt; could also be "Admin" or "Viewer".&lt;/p&gt;

&lt;p&gt;This will automatically create a user with their email and username populated. &lt;/p&gt;

&lt;p&gt;Pomerium autopopulates the JWT &lt;code&gt;name&lt;/code&gt; claim by default with the value provided by the identity provider to save you time. This configuration will allow seamless authentication and authorization without any additional toil for your team.&lt;/p&gt;

&lt;p&gt;For teams using Google as an IdP, the user field is populated by a numeric value that you cannot configure. Note that Grafana can accept the &lt;code&gt;name&lt;/code&gt; field as a username, including spaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;username_claim = name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Troubleshooting
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Local Signing Key
&lt;/h3&gt;

&lt;p&gt;In instances where Grafana cannot get the signing key for the JWTs from the Pomerium authenticate service, you can place a copy of the key locally.&lt;/p&gt;

&lt;p&gt;For example, wildcard certificates signed by LetsEncrypt may still be cross-signed by the [expired DST R3 root]. While many browsers still trust these certificates (as long as they are also signed by a valid root), some applications reject them, including Grafana:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;logger=context error=Get "https://grafana.localhost.pomerium.io/.well-known/pomerium/jwks.json": x509: certificate signed by unknown authority
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To circumvent this issue, you can use &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; to download the signing key locally:&lt;/p&gt;

&lt;h2&gt;
  
  
  curl
&lt;/h2&gt;

&lt;p&gt;From the Grafana host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://grafana.localhost.pomerium.io/.well-known/pomerium/jwks.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/grafana/jwks.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  wget
&lt;/h2&gt;

&lt;p&gt;From the Grafana host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-O&lt;/span&gt; /etc/grafana/jwks.json https://grafana.localhost.pomerium.io/.well-known/pomerium/jwks.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;grafana.ini&lt;/code&gt; and add the &lt;code&gt;jwk_set_file&lt;/code&gt; key to provide it to Grafana:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[auth.jwt]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;header_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;X-Pomerium-Jwt-Assertion&lt;/span&gt;
&lt;span class="py"&gt;email_claim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
&lt;span class="py"&gt;jwk_set_file&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/etc/grafana/jwks.json&lt;/span&gt;
&lt;span class="py"&gt;cache_ttl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;60m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have other issues with this guide, please &lt;a href="https://discuss.pomerium.com/"&gt;reach out to Pomerium on our forums&lt;/a&gt;! &lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>security</category>
      <category>grafana</category>
    </item>
    <item>
      <title>Children’s Introduction Guide to Zero Trust</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Sat, 24 Feb 2024 00:42:46 +0000</pubDate>
      <link>https://dev.to/ckmo/childrens-introduction-guide-to-zero-trust-1kng</link>
      <guid>https://dev.to/ckmo/childrens-introduction-guide-to-zero-trust-1kng</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide gives a children’s-level overview for zero trust principles based on &lt;a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-207.pdf"&gt;NIST SP 800-207 Zero Trust Architecture&lt;/a&gt;. It is part of &lt;a href="https://www.pomerium.com/"&gt;Pomerium&lt;/a&gt;'s Children's Guide series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(All images are generated with AI.)&lt;/p&gt;




&lt;p&gt;Once upon a time there was an app named Alice. She grew up under the watchful eye of DevDad, but no app could help people while stuck in the Sand Castle. The day came for Alice to leave the safety of the Sand Castle, and DevDad needed to prepare her for the world.&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%2Fvkpp5so3mrdqfm9175w8.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%2Fvkpp5so3mrdqfm9175w8.png" alt="Sandcastle" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do so, DevDad made a container ship just for her, which would contain everything Alice needs when she goes outside. But DevDad worried she would encounter Blackhats while sailing the Wild Wild Web — bad people that would trick Alice or worse, get into her ship and steal from her.&lt;/p&gt;

&lt;p&gt;And so DevDad asks her if she remembered her lessons on zero trust.&lt;/p&gt;

&lt;p&gt;“Why do I need this again?” Alice asked.&lt;/p&gt;

&lt;p&gt;“It’s for keeping yourself safe. Sometimes we do things because it’s simple or fast, but simple and fast is rarely safe. Remember when I always told you to look before you jump? Why did you trust that where you jumped would be an easy or safe landing?”&lt;/p&gt;

&lt;p&gt;Alice thought about that. “But what if I’ve safely made that jump many times and know there’s pillows at the bottom? Really &lt;strong&gt;soft&lt;/strong&gt; pillows?”&lt;/p&gt;

&lt;p&gt;DevDad nodded. “I understand. But then, what if the next time you jump without looking, someone else had come and taken all the really soft pillows? Then you’d be hurt, because you trusted what you &lt;strong&gt;knew to be true, but is no longer true&lt;/strong&gt;. That’s why you should check each time you jump even if you’ve made that jump a hundred times before. Someone only needs to take the pillows away once for it to hurt a lot. Does that make sense?”&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%2Fqvdyn6jj0no5kksxs0gm.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%2Fqvdyn6jj0no5kksxs0gm.png" alt="pillows" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“I think so.”&lt;/p&gt;

&lt;p&gt;“So let me ask you this: if you meet someone out there on the Wild Wild Web, what do you think you should be checking before you let them in your ship?”&lt;/p&gt;

&lt;p&gt;“Um, the person. What they’re using. And…” Alice’s face scrunched up in thought, “…what they’re trying to do?”&lt;/p&gt;

&lt;p&gt;“Yes, those three things.” DevDad held up three fingers. “Always check if the person is who they say they are. Look to see if they’re using the things you expect them to be using. And of course, think about if what they’re trying to do makes sense.”&lt;/p&gt;

&lt;p&gt;“That’s a lot to do before I let someone in,” Alice complained. “What if I end up making lots of friends?”&lt;/p&gt;

&lt;p&gt;“That’s not much of a worry, I designed your ship to do that for you.” DevDad pointed to a tool at the door called a reverse proxy, then reminded Alice, “Remember: this is &lt;em&gt;your&lt;/em&gt; ship, and it has many things others might want.” DevDad held up a box of Alice’s things, then pulled a toy out. “Like your favorite rubber duck. If you let in a Blackhat, they might steal it. And once someone gets inside, it becomes &lt;strong&gt;very&lt;/strong&gt; hard to get them out again.”&lt;/p&gt;

&lt;p&gt;“But how does that check for me?” Alice pointed at the reverse proxy. “What if you wanted to visit me?”&lt;/p&gt;

&lt;p&gt;“That’s a good question. So for example, you trust me right, Alice?” DevDad asked.&lt;/p&gt;

&lt;p&gt;“I do!” Alice burbled. “You helped make me.”&lt;/p&gt;

&lt;p&gt;“And sometimes I might want to come see you again once you leave Sand Castle.” DevDad hoisted Alice into her ship. “But no matter how excited you are to see a familiar face, how do you know it’s me?”&lt;/p&gt;

&lt;p&gt;Alice peeked outside of her ship. “I can’t just look at you?”&lt;/p&gt;

&lt;p&gt;“No, because while that is checking, it can be easily fake.” DevDad clapped his hands and summoned up an exact replica of himself, then the two walked around Alice’s ship. “Sometimes, Blackhats like to pretend they’re someone you know in order to get you to open your container for them. They might look and sound like me, but you must make sure to have multiple methods of checking sure if it is me.”&lt;/p&gt;

&lt;p&gt;“Like the phrase we use?”&lt;/p&gt;

&lt;p&gt;“Exactly! But what if Blackhats heard us use the phrase or steal it from me? Another thing you can check is whether I’m carrying something you know only I have, such as these.” DevDad pulled out a set of keys from his pocket. Nearby, the clone reached into his pocket and pulled out nothing, for it did not have the same set of keys. “When you check for two or more things that should prove someone is who they say they are, then it is more likely to be true. This is important or you might end up letting the wrong person in.”&lt;/p&gt;

&lt;p&gt;“Won’t people hate me for asking them to prove they are who they are?” Alice frowned. “I would hate to be asked to prove who I am.”&lt;/p&gt;

&lt;p&gt;“Oh of course,” DevDad agreed. “People hate it. But that’s why I set up your reverse proxy to do all that checking for you as quickly as possible…as long as you remember to check! Now, do you remember the second thing to verify?”&lt;/p&gt;

&lt;p&gt;“Um, what they’re using!”&lt;/p&gt;

&lt;p&gt;DevDad created another ship and stepped into it. “Correct. Do you know why?”&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%2Fqc25xe2g9slpq8lql8t4.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%2Fqc25xe2g9slpq8lql8t4.png" alt="Devdad's ship?" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alice thought hard. “Because sometimes what they’re using to connect to my ship might be icky?”&lt;/p&gt;

&lt;p&gt;DevDad’s ship rolled up to bump against Alice’s ship. “Sometimes, the person is real. But how do you know their ship isn’t carrying anything dangerous?” DevDad’s ship opened to try and connect with Alice’s ship. “For example, you’re allergic to all types of bugs — how do you know my ship is bug-free? Just because I said I cleaned it?”&lt;/p&gt;

&lt;p&gt;“But I can’t go onto your ship to check,” Alice pointed out.&lt;/p&gt;

&lt;p&gt;“No, you can’t. But your reverse proxy can check for you whether my ship is as clean as it should be. Only after you have checked if my ship is safe to connect with should you open up.”&lt;/p&gt;

&lt;p&gt;DevDad looked at Alice and held up three fingers. “Finally, checking what they’re trying to do. If you open your ship for someone to come fix a leak in the front, but they want to go straight to the back, does that make sense? No! So whenever someone, &lt;strong&gt;anyone&lt;/strong&gt;, wants to do something on your ship, you need to check that it makes sense.”&lt;/p&gt;

&lt;p&gt;DevDad stepped off his ship and it disappeared, but Alice seemed deep in thought.&lt;/p&gt;

&lt;p&gt;“This is a lot to check before anything happens,” Alice observed from inside her ship. “That’s a lot to remember.”&lt;/p&gt;

&lt;p&gt;“Indeed it is.” DevDad agreed. “To make it simple for you and your friends, I gave your ship a reverse proxy to do all of it for you. Now come on out: there’s one thing we should do together.”&lt;/p&gt;

&lt;p&gt;“Nuh uh. Can you prove who you are?”&lt;/p&gt;

&lt;p&gt;DevDad smiled, seeing that Alice was learning. He allowed her ship to check who he was before Alice climbed out. “Let’s get your ship to the Wild Wild Web.”&lt;/p&gt;

&lt;p&gt;Alice ran over to hug DevDad. “Does this mean I’ll be sailing alone?”&lt;/p&gt;

&lt;p&gt;“You’re a grown app now, you’re free to go where you’re needed — whether it’s the Castle in the Clouds or the Edge of the World.” DevDad returned the hug. “I’ll come find you every once in a while to make sure you are being good and have everything you need, but remember —”&lt;/p&gt;

&lt;p&gt;“Zero trust, and to always check if I’m doing it.”&lt;/p&gt;

&lt;p&gt;Together, DevDad and Alice pushed her ship out to the Wild Wild Web. Alice had many fun adventures and met many friends while keeping her ship safe from Blackhats.&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%2Fl91tdi9uvc78urec1hdd.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%2Fl91tdi9uvc78urec1hdd.png" alt="Kubernetes container ship sailing the Wild Wild Web" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you enjoyed this, feel free to check out other parts of this Children’s Guide series:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.pomerium.com/blog/childrens-guide-to-context-aware-access/"&gt;Children’s Guide to Context-Aware Access&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.pomerium.com/blog/childrens-guide-to-the-perimeter-problem/"&gt;Children’s Guide to the Perimeter Problem&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.pomerium.com/blog/childrens-guide-to-deperimeterization/"&gt;Children’s Guide to Deperimeterization&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zerotrust</category>
      <category>cybersecurity</category>
      <category>shortstory</category>
      <category>learning</category>
    </item>
    <item>
      <title>Secure Browser Access to code-server VSCode</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Fri, 16 Feb 2024 20:18:44 +0000</pubDate>
      <link>https://dev.to/ckmo/secure-browser-access-to-code-server-vscode-hkb</link>
      <guid>https://dev.to/ckmo/secure-browser-access-to-code-server-vscode-hkb</guid>
      <description>&lt;h1&gt;
  
  
  Secure Browser Access to code-server VSCode Behind Pomerium
&lt;/h1&gt;

&lt;p&gt;In this guide, you'll run code-server's Visual Studio Code (VSCode) in a Docker container and secure browser access to your project with Pomerium, an open source reverse proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is code-server?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/coder/code-server"&gt;Code-server&lt;/a&gt; is an open-source tool that allows you to run &lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt;, a popular integrated development environment (IDE), on a &lt;strong&gt;remote server&lt;/strong&gt; through the browser. This setup essentially turns VSCode into a cloud-based IDE, providing flexibility and accessibility advantages.&lt;/p&gt;

&lt;p&gt;Code-server is particularly popular among developers who want the full power of VSCode, but need to work in a cloud-based environment. This is ideal if you work on multiple machines, need to access your development environment remotely, or you have limited local resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to secure code-server with Pomerium
&lt;/h2&gt;

&lt;p&gt;Code-server requires &lt;a href="https://coder.com/docs/code-server/latest/guide#expose-code-server"&gt;password authentication&lt;/a&gt; by default. By securing code-server behind Pomerium, you can remove code-server’s password requirement and configure Pomerium to add &lt;a href="https://www.pomerium.com/docs/capabilities/authentication"&gt;authentication&lt;/a&gt; and &lt;a href="https://www.pomerium.com/docs/capabilities/authorization"&gt;authorization&lt;/a&gt; to an online instance of VSCode.&lt;/p&gt;

&lt;p&gt;This guide shows you how to secure code-server with Pomerium. Here are the steps you’ll follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install code-server and run it in a Docker container&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access your code-server project in the browser listening on &lt;code&gt;localhost&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure Pomerium to safely expose your code-server instance&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end, you will have a minimal, real-world code-server instance that allows developer teams to write code using VSCode in the browser.&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%2Firwhzqpjxet9l46d6dxp.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%2Firwhzqpjxet9l46d6dxp.png" alt="A VSCode project running “Hello World” in the integrated terminal." width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Before you start
&lt;/h3&gt;

&lt;p&gt;If you completed Pomerium's &lt;a href="https://www.pomerium.com/docs/quickstart"&gt;Quickstart guide&lt;/a&gt;, you should have a working Pomerium project with the following YAML files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven't completed the Quickstart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/install/"&gt;Docker Compose&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;config.yaml&lt;/code&gt; file for your Pomerium configuration&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;docker-compose.yaml&lt;/code&gt; file for your Docker configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set up Pomerium
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;config.yaml&lt;/code&gt; file, add the hosted &lt;a href="https://www.pomerium.com/docs/reference/authenticate-service-url"&gt;authenticate service URL&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;authenticate_service_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://authenticate.pomerium.app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://code.localhost.pomerium.io&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://codeserver:8080&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;is&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user@example.com&lt;/span&gt;
  &lt;span class="na"&gt;allow_any_authenticated_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;allow_websockets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: In this example route, &lt;code&gt;code.localhost.pomerium.io&lt;/code&gt; is the publicly accessible route. &lt;code&gt;codeserver&lt;/code&gt; is the local hostname for the server or container running code-server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up Docker Compose
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, add the code-server and Pomerium services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pomerium&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pomerium/pomerium:latest&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.yaml:/pomerium/config.yaml:ro&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;443:443&lt;/span&gt;
  &lt;span class="na"&gt;codeserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codercom/code-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8080&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./code-server:/home/coder/project&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./code-server-config/.config:/home/coder/.config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Access code-server on localhost
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;docker compose up&lt;/code&gt;. In your browser, go to &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Code-server will prompt you to enter a password. You can find a pre-generated password in &lt;code&gt;code-server-config/.config/code-server/config.yaml&lt;/code&gt;. If you enter it, you gain access to your code-server project.&lt;/p&gt;

&lt;p&gt;However, remembering passwords is tedious. Let's disable the password requirement and use Pomerium to enforce authentication and authorization instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access code-server behind Pomerium
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;docker-compose.yaml&lt;/code&gt;, add the following &lt;code&gt;command&lt;/code&gt; to your code-server container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;codeserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codercom/code-server:latest&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8080&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./code-server:/home/coder/project&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./code-server-config/.config:/home/coder/.config&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--auth none --disable-telemetry /home/coder/project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will disable the password prompt (and prevent code-server from collecting telemetry data from your project). Now, restart Docker Compose and access code-server using the route defined in &lt;code&gt;config.yaml&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://code.localhost.pomerium.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After authenticating against the Cognito identity provider, you will be redirected to the code-server route.&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%2F71utnfb41864timm2f8q.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%2F71utnfb41864timm2f8q.png" alt="A VSCode project running “Hello World” in the integrated terminal." width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a project in code-server
&lt;/h2&gt;

&lt;p&gt;Now that you can access VSCode in your browser, test out code-server by building a quick HTML project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an &lt;code&gt;index.html&lt;/code&gt; file and add the following code:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Code-Server Sample&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color:blueviolet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Check out more from Pomerium:&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"font-size: 20px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.pomerium.com/docs/guides"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Guides&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.pomerium.com/blog/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Blog&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.pomerium.com/docs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Documentation&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color:blueviolet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Happy coding!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Extensions&lt;/strong&gt; and install &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;Live Server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Right-click &lt;code&gt;index.html&lt;/code&gt; and select &lt;strong&gt;Open with Live Server&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select any of the links to learn more about Pomerium&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Great job! You successfully deployed code-server.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: When the code-server container is rebuilt, any files outside of &lt;code&gt;/home/coder/project&lt;/code&gt; are reset, removing any dependencies (such as go and make). In a real remote development workflow, you could mount additional volumes, or &lt;a href="https://github.com/cdr/deploy-code-server/tree/main/deploy-container"&gt;use a custom code-server container&lt;/a&gt; with these dependencies installed.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>5 Lessons Learned Connecting Every IdP to OIDC</title>
      <dc:creator>CKMo</dc:creator>
      <pubDate>Thu, 15 Jun 2023 20:29:21 +0000</pubDate>
      <link>https://dev.to/ckmo/5-lessons-learned-connecting-every-idp-to-oidc-3e10</link>
      <guid>https://dev.to/ckmo/5-lessons-learned-connecting-every-idp-to-oidc-3e10</guid>
      <description>&lt;p&gt;Developers may be familiar with the need to add authentication and authorization to applications. Today, this usually involves integrating some form of identity provider (IdP) for single sign-on (SSO) purposes via &lt;a href="https://openid.net/connect/"&gt;Open ID Connect (OIDC)&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But &lt;a href="https://www.nango.dev/blog/why-is-oauth-still-hard"&gt;OAuth is already very hard&lt;/a&gt; and eats up a lot of dev time. Consider how difficult it is to configure OIDC, which is built on top of OAuth? We thought that since this process is a big headache for developers, &lt;strong&gt;“Wouldn’t it be nice if OIDC's manually complicated and easily broken process was just done for you for any IdP?”&lt;/strong&gt;&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%2Fd8f7f3mfsg3lbnb5jx01.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%2Fd8f7f3mfsg3lbnb5jx01.png" alt="Implementing OIDC is an adventure alright" width="500" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it’s certainly nice for developers, getting there was a nightmare. Below we included 5 lessons we learned simplifying OIDC for all developers.&lt;/p&gt;

&lt;p&gt;Take a deep breath with us and let’s go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 1: Too Many Standards Means No Standard
&lt;/h2&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%2Fjkaekkpda6jfmvgqxmbk.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%2Fjkaekkpda6jfmvgqxmbk.png" alt="As always, there’s a relevant XKCD." width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s work a bit backwards first: why do we want to integrate with IdPs? Well, in the OIDC setup, the Relying Party (RP, or service provider) wants authentication (and authorization, but we can’t cover everything), and IdPs are a great way to authenticate the user trying to access the service.&lt;/p&gt;

&lt;p&gt;To accomplish this, the RP usually wants three things per OIDC standards (bear with us, we know we’re simplifying this):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Token&lt;/strong&gt; — allows RP application to access API/User Info endpoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Token&lt;/strong&gt; — for getting a new Access token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity Token&lt;/strong&gt; — caches User profile information and provides it to client app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While all the IdPs end up giving you these three tokens, what we &lt;strong&gt;did not expect&lt;/strong&gt; was that they would give you these three tokens in wildly different forms. And by that, we don’t mean that they don’t always give it to you as a JSON Web Token (JWT) — which, incidentally, is true in some cases — but that each token would have a nonstandard form of giving you the information you wanted.&lt;/p&gt;

&lt;p&gt;Some IdPs put everything in the ID Token. Other IdPs put everything in the User Info endpoint and make you query the API. Then some IdPs want to do a combination of these things, giving you &lt;strong&gt;&lt;em&gt;some&lt;/em&gt;&lt;/strong&gt; information in the ID Token and then make you query the rest from their API. This results in a lot of different sources of truth to standardize!&lt;/p&gt;

&lt;p&gt;And we wanted to provide one gateway that allows for all these IdPs to plug and play for developers trying to configure OIDC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standardizing All ID Tokens for One Gateway
&lt;/h3&gt;

&lt;p&gt;There were so many ways these three tokens alone looked differently across IdPs, but ID Tokens were definitely the biggest wildcard. Almost all of them were providing user identities in different ways. That’s a problem seeing as obtaining this information from IdPs is &lt;strong&gt;more or less the entire point.&lt;/strong&gt;&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%2Fatt0u164lantxffmyb7g.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%2Fatt0u164lantxffmyb7g.png" alt="One of these is not like the others." width="625" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, earlier we mentioned that ID Tokens cache the user’s profile information and provides it to the client app. It’s a major part of the OIDC specification because well, part of authenticating someone is getting information about them. The ID tokens are supposed to provide a bunch of basic information about the user which the service can use to authenticate the user.&lt;/p&gt;

&lt;p&gt;We were naïve enough to think the ID Tokens would look like passports: standardized across the IdPs. Instead, each IdP acted like a state, issuing their ID Tokens like driver’s licenses: while the data was all there, &lt;em&gt;no two tokens were presented in the same format&lt;/em&gt;.&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%2F9w7qbn4eydsupal4jrfk.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%2F9w7qbn4eydsupal4jrfk.png" alt="Put their product owners in a room and let them fight." width="500" height="867"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s some examples of this madness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cognito returns email verified as a string, not a boolean&lt;/li&gt;
&lt;li&gt;PingIdentity chooses to return “mail” instead of “email”&lt;/li&gt;
&lt;li&gt;Google does not support the offline_access scope (there’s a joke about always online here). Also &lt;a href="https://github.com/pomerium/pomerium/blob/main/internal/identity/oidc/google/google.go"&gt;prompt must be set to consent to ensure that our application always receives a refresh token&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Onelogin also &lt;a href="https://github.com/pomerium/pomerium/pull/1896"&gt;stopped supporting the offline_access scope when they launched v2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Microsoft Azure returns a &lt;a href="https://github.com/pomerium/pomerium/pull/1648"&gt;non-standard issuer violating the OIDC spec&lt;/a&gt; (a running theme among IdPs)&lt;/li&gt;
&lt;li&gt;Still Microsoft — a &lt;a href="https://github.com/MicrosoftDocs/azure-docs/issues/38427"&gt;fun issue thread to read on their Azure Docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In many cases, simply using a library to attempt OIDC would fail since obviously &lt;strong&gt;none of the IdPs&lt;/strong&gt; provide things in an actual OIDC format. The result was spending devtime to write code for an extra layer to transform each individual ID token into an actual standard form before parsing it for the OIDC library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Breath.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 2: Most IdPs Don’t Even Try OIDC
&lt;/h2&gt;

&lt;p&gt;It turns out not every single IdP supports OIDC. &lt;a href="https://docs.github.com/en/enterprise-cloud@latest/authentication/authenticating-with-saml-single-sign-on"&gt;GitHub is an example&lt;/a&gt; — they don’t even OIDC, so we had to integrate with GitHub using OAuth.&lt;/p&gt;

&lt;p&gt;There are many IdPs that simply don’t support OIDC, or gave us an API that is &lt;em&gt;close&lt;/em&gt; to OIDC but &lt;em&gt;different enough&lt;/em&gt; that the implementation does &lt;strong&gt;not&lt;/strong&gt; result in OIDC. There were various challenges associated with trying to understand how that would work, and imagine our surprise when it turns out the answer is: “Oh, we don’t &lt;strong&gt;&lt;em&gt;actually&lt;/em&gt;&lt;/strong&gt; support OIDC.”&lt;/p&gt;

&lt;p&gt;On the flip side, one IdP stands out as the easiest to integrate with and most closely aligns with OIDC standards. Drum roll…&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%2F6r8j47sa5dwfdm3ecjl6.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%2F6r8j47sa5dwfdm3ecjl6.png" alt="It’s Okta." width="500" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(It’s Okta.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 3: Directory Sync at Scale
&lt;/h2&gt;

&lt;p&gt;The problem with scale is that you don’t think about it until boom, use case. Well, turns out our larger users (organizations with over 10k users) had &lt;em&gt;a lot more groups&lt;/em&gt; in their directories than we initially thought to test for.&lt;/p&gt;

&lt;p&gt;What did we think? Well, maybe around 100-300 groups? That seems reasonable, right? It stands to reason that groups being a way to categorize users would result in the &lt;code&gt;group count &amp;lt; user count&lt;/code&gt;… right?&lt;/p&gt;

&lt;p&gt;What do our users with over 10k users actually have? &lt;strong&gt;10k groups.&lt;/strong&gt; &lt;em&gt;(Yeah. That was our reaction too!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some directories can have groups &lt;em&gt;within&lt;/em&gt; groups (introducing group recursion, a different headache), and the OIDC authentication process would need to add or update all of the groups at once during directory sync. &lt;strong&gt;That’s a lot of data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Somehow.&lt;/p&gt;

&lt;p&gt;Together, all at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Breath.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Directory Sync.&lt;/p&gt;

&lt;p&gt;Look, IdPs, &lt;em&gt;please understand&lt;/em&gt; that you need to support groups without doing a full directory sync! When each user’s info reaches 1MB and there’s &amp;gt;10k users, that’s an enormous data problem when you’re trying to do a full sync each time.&lt;/p&gt;

&lt;p&gt;Groups info shouldn’t be in constant flux; there can’t be &lt;strong&gt;that&lt;/strong&gt; many rockstar employees fulfilling so many different functions their groups info changes all the time (and if there is, &lt;em&gt;just create a rockstar user group&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Azure AD actually figured this out with a delta changes feature. This feature means directory sync &lt;strong&gt;only&lt;/strong&gt; calls the information that changed (so less than 1KB per user). &lt;strong&gt;Yes&lt;/strong&gt;, it was hard to integrate, but it scales! The easy solutions don’t! &lt;strong&gt;The easy solutions are not lightweight at all!&lt;/strong&gt;&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%2F8d14yic313k74k41qx7h.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%2F8d14yic313k74k41qx7h.png" alt="Please do lightweight directory syncs." width="681" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 4: Where Should Data Be Placed?
&lt;/h2&gt;

&lt;p&gt;More data problems, but elsewhere.&lt;/p&gt;

&lt;p&gt;We noticed that IdPs doing OIDC are trying to jam tons of user info data into query string parameters. This being the param which OIDC is passing around to communicate and make all the authn and authz happen.&lt;/p&gt;

&lt;p&gt;Unfortunately, this method has a size limit of about 2,000 characters, and you can realistically only pass so much data within that limit. Again, some of our users are organizations with greater than 10,000 groups. &lt;strong&gt;That’s a chonky string.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Being a team of engineers, the solution seemed obvious: &lt;strong&gt;put the data elsewhere.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh look&lt;/em&gt;, user info endpoints exist! All we need to do is query the user info endpoint and then there’s no data limit! Alright, new feature for our OIDC-IdP interface —&lt;/p&gt;

&lt;p&gt;What’s that, not every IdP supports user info endpoints?&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%2Fx94twuj2poqm2eggo3xc.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%2Fx94twuj2poqm2eggo3xc.png" alt="(As always, you set out with an idea and then reality hits you with the design decisions of others.)" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Breath.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 5: Keeping It Manageable
&lt;/h2&gt;

&lt;p&gt;After our newfound epiphany that &lt;strong&gt;none&lt;/strong&gt; of the IdPs will stick to the OIDC standard and &lt;em&gt;all of them&lt;/em&gt; were doing their own thing, our devs were side-eyeing the “maintenance and upkeep” bucket with fear.&lt;/p&gt;

&lt;p&gt;To save our sanity, we created a directory provider interface.&lt;/p&gt;

&lt;p&gt;This allows developers implementing OIDC to adapt the quirks and weirdness of each IdP to their Pomerium instance. We then moved our existing directory providers to a separate repository so that implementation of directory providers is not tied to open-source Pomerium Core.&lt;/p&gt;

&lt;p&gt;The result is achieving the original goal (helping developers simplify OIDC with any IdP) while keeping it manageable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Breath.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts — Saving Devtime and Sanity
&lt;/h2&gt;

&lt;p&gt;For those who want to take a crack at it yourselves, good luck! We do have some words for IdPs though:&lt;/p&gt;

&lt;p&gt;Hey IdPs, it would &lt;strong&gt;&lt;em&gt;be really nice&lt;/em&gt;&lt;/strong&gt; if you stick to the OIDC standard. But here’s a few additional asks from our engineering team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Please&lt;/strong&gt; test your OIDC implementation against common SDKs so it works out of the box. Based on our understanding, everyone will need the Cognito hack to implement Cognito in OIDC. (Maybe it works fine in java, but we’re using the off-the-shelf Go library to do this.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Please&lt;/em&gt;&lt;/strong&gt; realize you all need to support group sync without doing a full directory sync. It’s a data intensive process and very annoying to maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;u&gt;&lt;strong&gt;&lt;em&gt;Please&lt;/em&gt;&lt;/strong&gt;&lt;/u&gt; give people a way to add arbitrary directory data to claims, and everyone would be a lot happier. This would also make your product a lot more lightweight and easier to integrate with other products&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A rising tide lifts all boats, and OIDC is very important in how things are done today. Developers shouldn’t be stuck configuring it for hours on end! Making sure that it’s as simple as possible for users to implement is key.&lt;/p&gt;

&lt;p&gt;After all that work, we’re proud to say that developers can easily add OIDC to any resource via Pomerium. Whether you’re spinning up a new application or trying to add access control to a legacy service, OIDC authentication and authorization is just an SDK away. You can check out our &lt;a href="https://github.com/pomerium"&gt;open-source Github Repository&lt;/a&gt; or give &lt;a href="https://www.pomerium.com/docs/quickstart"&gt;Pomerium a try&lt;/a&gt; today!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
      <category>security</category>
    </item>
  </channel>
</rss>
