<?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: discernible-io</title>
    <description>The latest articles on DEV Community by discernible-io (@discernible-io).</description>
    <link>https://dev.to/discernible-io</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%2F2685195%2F3b6a1e9f-4c9f-41a2-bda5-8a71e3072750.png</url>
      <title>DEV Community: discernible-io</title>
      <link>https://dev.to/discernible-io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/discernible-io"/>
    <language>en</language>
    <item>
      <title>API keys leak. Certificates expire.</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Thu, 16 Oct 2025 12:18:39 +0000</pubDate>
      <link>https://dev.to/discernible-io/api-keys-leak-certificates-expire-25em</link>
      <guid>https://dev.to/discernible-io/api-keys-leak-certificates-expire-25em</guid>
      <description>&lt;h2&gt;
  
  
  Live Event Today: Mutual Trust, No Secrets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  RODiT and the Future of API Authentication
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;📅 When:&lt;/strong&gt; Today, 3pm UTC&lt;br&gt;&lt;br&gt;
&lt;strong&gt;🎯 What:&lt;/strong&gt; Live Q&amp;amp;A and deep dive into RODiT technology&lt;/p&gt;

&lt;p&gt;Join us as we talk with &lt;strong&gt;Discernible IO&lt;/strong&gt; about &lt;strong&gt;RODiT (Rich Online Digital Tokens)&lt;/strong&gt;, a new approach to API authentication with verifiable on-chain identities.&lt;/p&gt;

&lt;h3&gt;
  
  
  About RODiT
&lt;/h3&gt;

&lt;p&gt;Built on &lt;a href="https://near.org" rel="noopener noreferrer"&gt;@NEARProtocol&lt;/a&gt; by Discernible, RODiTs bring mutual blockchain-based trust to API authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Watch Live
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NEAR DevHub&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/@NEARDevHub" rel="noopener noreferrer"&gt;https://www.youtube.com/@NEARDevHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bring your questions and join the conversation!&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>nearprotocol</category>
      <category>api</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Creating Debian Packages: A Quick Guide</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Thu, 02 Oct 2025 09:37:54 +0000</pubDate>
      <link>https://dev.to/discernible-io/creating-debian-packages-a-quick-guide-72n</link>
      <guid>https://dev.to/discernible-io/creating-debian-packages-a-quick-guide-72n</guid>
      <description>&lt;p&gt;Creating your own Debian packages is simpler than you might think. Here's a streamlined approach to get you started quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Setup
&lt;/h2&gt;

&lt;p&gt;First, you'll need the essential tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential devscripts debhelper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Package Structure
&lt;/h2&gt;

&lt;p&gt;Create your package directory structure. At minimum, you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-package/
├── debian/
│   ├── control
│   ├── changelog
│   ├── rules
│   └── compat
└── [your source files]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;debian/control&lt;/code&gt; file describes your package, &lt;code&gt;changelog&lt;/code&gt; tracks versions, &lt;code&gt;rules&lt;/code&gt; defines the build process, and &lt;code&gt;compat&lt;/code&gt; specifies the debhelper compatibility level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Package
&lt;/h2&gt;

&lt;p&gt;Once your debian directory is properly configured, building is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dpkg-buildpackage &lt;span class="nt"&gt;-us&lt;/span&gt; &lt;span class="nt"&gt;-uc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-us -uc&lt;/code&gt; flags skip signing the source and changes files, which is perfect for local development and testing. This command will create your &lt;code&gt;.deb&lt;/code&gt; file in the parent directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Install your package locally to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; ../your-package_version_architecture.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the essence of it. While there are many nuances to packaging, this approach using &lt;code&gt;dpkg-buildpackage -us -uc&lt;/code&gt; provides a reliable foundation for creating functional Debian packages.&lt;/p&gt;

&lt;p&gt;For a more comprehensive guide with detailed examples, check out &lt;a href="https://benjamintoll.com/2023/06/21/on-creating-deb-packages/" rel="noopener noreferrer"&gt;this excellent tutorial on creating deb packages&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>debian</category>
    </item>
    <item>
      <title>Internet Trust Chains</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Thu, 28 Aug 2025 13:35:01 +0000</pubDate>
      <link>https://dev.to/discernible-io/internet-trust-chains-1b4</link>
      <guid>https://dev.to/discernible-io/internet-trust-chains-1b4</guid>
      <description>&lt;p&gt;Internet trust is built on quite shaky foundations. Moving packets around to the correct computer that controls each IP address involves often no less than 3 large complex pyramids of trust: BGP, DNS and PKI. Any crack in any of these leads to the others crumbling.&lt;/p&gt;

&lt;p&gt;Let's start with BGP, it works like this:&lt;/p&gt;

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

&lt;p&gt;The DNS pyramid has the following components:&lt;/p&gt;

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

&lt;p&gt;And the PKI pyramid has these:&lt;/p&gt;

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

&lt;p&gt;We can compare these pyramids as follows:&lt;/p&gt;

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

&lt;p&gt;You can easily see that BGP, the foundation, has enormous gaps. By exploiting BGP it is possible to compromise both DNS and PKI, despite all the current mitigations in place.&lt;/p&gt;

&lt;p&gt;In particular, across all levels, there are significant gaps in &lt;br&gt;
Administrative Controls, with fraudulent participants obtaining approval, Real-time Validation and Revocation, which barely works at the PKI level as it can't scale, Transparency Mechanisms, as both IP and domain asset owners can't control who makes security assertions about their assets, Man in the middle attacks due to poor Authentication mechanisms, &lt;/p&gt;

&lt;p&gt;All these gaps result in poor security. For example the support for strong mutual authentication is poor, both in server-client and peer to peer applications. Deployments are complex, expensive and brittle.&lt;/p&gt;

&lt;p&gt;In the next article we will explain how RODiT technology can help overcoming many of these challenges.&lt;/p&gt;

</description>
      <category>internet</category>
      <category>trust</category>
      <category>pki</category>
      <category>dns</category>
    </item>
    <item>
      <title>The Chain of Trust in X.500 Digital Certificates: Power, Control, and Real-World Failures</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Mon, 07 Jul 2025 10:45:36 +0000</pubDate>
      <link>https://dev.to/discernible-io/-the-chain-of-trust-in-x500-digital-certificates-power-control-and-real-world-failures-2244</link>
      <guid>https://dev.to/discernible-io/-the-chain-of-trust-in-x500-digital-certificates-power-control-and-real-world-failures-2244</guid>
      <description>&lt;p&gt;Digital certificates form the backbone of modern internet security, enabling everything from secure web browsing to email encryption. At the heart of this system lies the concept of a "chain of trust" based on X.500 digital certificates. However, while this system appears robust on paper, real-world incidents reveal significant vulnerabilities and power imbalances that affect global internet security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding X.500 Digital Certificates
&lt;/h2&gt;

&lt;p&gt;X.500 digital certificates are based on the ITU-T X.509 standard, which defines the format for public key certificates. These certificates bind a public key to an identity (such as a person, organization, or device) and are digitally signed by a Certificate Authority to verify their authenticity.&lt;/p&gt;

&lt;p&gt;Each X.509 certificate contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject information&lt;/strong&gt;: The entity being certified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public key&lt;/strong&gt;: The cryptographic key for the certified entity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issuer information&lt;/strong&gt;: The CA that signed the certificate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital signature&lt;/strong&gt;: The CA's cryptographic signature&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validity period&lt;/strong&gt;: When the certificate is valid&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensions&lt;/strong&gt;: Additional information like key usage and certificate policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Chain of Trust Explained
&lt;/h2&gt;

&lt;p&gt;The chain of trust is a hierarchical model where trust flows from a root Certificate Authority down through intermediate CAs to end-entity certificates. This creates a tree-like structure of trust relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Certificate Authorities
&lt;/h3&gt;

&lt;p&gt;At the top of the hierarchy sit &lt;strong&gt;Root CAs&lt;/strong&gt;. These are self-signed certificates that serve as the ultimate trust anchors. Root CAs are pre-installed in operating systems, browsers, and other software applications. When you see a padlock icon in your browser, it's because the certificate chain ultimately traces back to a trusted root CA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intermediate Certificate Authorities
&lt;/h3&gt;

&lt;p&gt;Between root CAs and end-entity certificates are &lt;strong&gt;Intermediate CAs&lt;/strong&gt; (also called subordinate CAs). Root CAs typically don't issue certificates directly to end users. Instead, they issue certificates to intermediate CAs, which then issue certificates to other intermediates or directly to end entities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain Validation Process
&lt;/h3&gt;

&lt;p&gt;When a certificate is presented, the validating software:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checks the end-entity certificate's signature against the issuing intermediate CA&lt;/li&gt;
&lt;li&gt;Validates each intermediate CA certificate up the chain&lt;/li&gt;
&lt;li&gt;Verifies that the chain terminates at a trusted root CA&lt;/li&gt;
&lt;li&gt;Confirms that all certificates in the chain are valid and not revoked&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The CA/Browser Forum: Who Holds the Power?
&lt;/h2&gt;

&lt;p&gt;The CA/Browser Forum is the industry consortium that sets standards for Certificate Authorities and web browsers. Understanding its membership structure reveals who truly controls internet certificate policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Membership Structure and Power Distribution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Certificate Authority Members&lt;/strong&gt;: The most influential CAs include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DigiCert&lt;/strong&gt;: One of the largest commercial CAs globally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sectigo (formerly Comodo)&lt;/strong&gt;: Major commercial CA with significant market share&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GlobalSign&lt;/strong&gt;: European-based CA with worldwide operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entrust&lt;/strong&gt;: Enterprise-focused CA with government contracts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let's Encrypt (ISRG)&lt;/strong&gt;: Non-profit CA that has revolutionized certificate accessibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GoDaddy&lt;/strong&gt;: Web hosting company with substantial CA operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Browser Members&lt;/strong&gt;: The entities that ultimately enforce certificate policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google (Chrome)&lt;/strong&gt;: Controls the largest browser market share globally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mozilla (Firefox)&lt;/strong&gt;: Maintains independent root store policies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft (Edge/IE)&lt;/strong&gt;: Integrates with Windows certificate stores&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apple (Safari)&lt;/strong&gt;: Controls certificate policy for iOS and macOS ecosystems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Power Dynamics and Decision Making
&lt;/h3&gt;

&lt;p&gt;The Forum operates on a consensus model, but practical power is unevenly distributed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser Dominance&lt;/strong&gt;: Browsers hold ultimate veto power because they control what certificates users actually trust. Google's Chrome team, in particular, has driven major policy changes including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mandatory Certificate Transparency logging&lt;/li&gt;
&lt;li&gt;Shorter certificate lifespans&lt;/li&gt;
&lt;li&gt;Stricter validation requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Commercial CA Influence&lt;/strong&gt;: Large commercial CAs influence standards through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical expertise and implementation experience&lt;/li&gt;
&lt;li&gt;Financial resources for standards development&lt;/li&gt;
&lt;li&gt;Market relationships with enterprise customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Voting Structure&lt;/strong&gt;: The Forum uses a two-thirds majority voting system, but browsers can effectively override decisions by changing their root store policies unilaterally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recent Power Struggles
&lt;/h3&gt;

&lt;p&gt;Several incidents illustrate the power dynamics:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symantec Distrust (2017)&lt;/strong&gt;: Google unilaterally decided to distrust Symantec certificates, forcing the CA to sell its business to DigiCert. This demonstrated browsers' ultimate authority over the certificate ecosystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Certificate Transparency Mandate&lt;/strong&gt;: Browsers, led by Google, mandated CT logging despite resistance from some CAs concerned about operational complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Control Mechanisms: DNS-Based Certificate Authority Authorization (CAA)
&lt;/h2&gt;

&lt;p&gt;Domain holders have limited mechanisms to control which CAs can issue certificates for their domains, that unfortunately are not used much.&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS CAA Records
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Certificate Authority Authorization (CAA)&lt;/strong&gt; records allow domain owners to specify which CAs are authorized to issue certificates for their domains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CAA Record Format&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issue "digicert.com"
example.com. CAA 0 iodef "mailto:security@example.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CAA Properties&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;issue&lt;/strong&gt;: Authorizes certificate issuance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;issuewild&lt;/strong&gt;: Authorizes wildcard certificate issuance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iodef&lt;/strong&gt;: Specifies contact for policy violations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DNS-Based Authentication of Named Entities (DANE)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DANE&lt;/strong&gt; uses DNS to specify which certificates or CAs are valid for a domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_443._tcp.example.com. TLSA 3 1 1 [certificate hash]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Certificate Transparency Monitoring
&lt;/h3&gt;

&lt;p&gt;Domain owners can monitor CT logs to detect unauthorized certificate issuance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Facebook Certificate Transparency Monitoring&lt;/strong&gt;: Automated detection of certificates issued for Facebook domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Certificate Transparency API&lt;/strong&gt;: Allows programmatic monitoring of certificate issuance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Failures: The MyEtherWallet BGP Attack
&lt;/h2&gt;

&lt;p&gt;One of the most significant examples of how certificate vulnerabilities can be exploited for cryptocurrency theft occurred in April 2018 with the MyEtherWallet attack.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Attack Sequence
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1: BGP Hijacking&lt;/strong&gt;&lt;br&gt;
Attackers compromised Amazon's Route 53 DNS service through BGP hijacking, redirecting DNS queries for MyEtherWallet.com to attacker-controlled servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Certificate Acquisition&lt;/strong&gt;&lt;br&gt;
The attackers obtained a valid Let's Encrypt certificate for MyEtherWallet.com by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controlling the DNS responses during Let's Encrypt's domain validation&lt;/li&gt;
&lt;li&gt;Using the DNS-01 challenge method to prove domain ownership&lt;/li&gt;
&lt;li&gt;Receiving a legitimate certificate that browsers trusted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Phishing Execution&lt;/strong&gt;&lt;br&gt;
With a valid certificate, the attackers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Presented a convincing replica of MyEtherWallet&lt;/li&gt;
&lt;li&gt;Displayed the trusted padlock icon in browsers&lt;/li&gt;
&lt;li&gt;Harvested private keys from users attempting to access their wallets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Cryptocurrency Theft&lt;/strong&gt;&lt;br&gt;
The attackers used the harvested private keys to steal approximately $152,000 in cryptocurrency.&lt;/p&gt;
&lt;h3&gt;
  
  
  Technical Analysis
&lt;/h3&gt;

&lt;p&gt;This attack succeeded because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BGP lacks authentication&lt;/strong&gt;: Attackers could redirect traffic without cryptographic verification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS validation vulnerability&lt;/strong&gt;: Let's Encrypt's domain validation relied on DNS, which the attackers controlled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User trust in certificates&lt;/strong&gt;: Users trusted the valid certificate without additional verification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of HSTS preloading&lt;/strong&gt;: MyEtherWallet wasn't in the HSTS preload list, allowing the initial redirect&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;The MyEtherWallet attack highlighted several critical issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Certificate validation isn't sufficient&lt;/strong&gt;: Valid certificates don't guarantee legitimate websites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS security is crucial&lt;/strong&gt;: BGP and DNS vulnerabilities can undermine certificate security&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need for additional protections&lt;/strong&gt;: Certificate Transparency, CAA records, and HSTS provide additional layers of security&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The MCIP Initiative: Modernizing Certificate Infrastructure
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Multi-Perspective Certificate Issuance and Validation (MCIP)&lt;/strong&gt; initiative represents the latest effort to address fundamental weaknesses in certificate validation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Current Validation Problems
&lt;/h3&gt;

&lt;p&gt;Traditional certificate validation suffers from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single point of validation&lt;/strong&gt;: CAs typically validate domain control from a single network perspective&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BGP vulnerabilities&lt;/strong&gt;: Attackers can redirect validation traffic as in the MyEtherWallet case&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS poisoning&lt;/strong&gt;: Localized DNS attacks can fool validation processes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  MCIP Solution Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Multiple Validation Perspectives&lt;/strong&gt;: Instead of validating from a single location, CAs must validate domain control from multiple, geographically distributed vantage points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation Requirements&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimum of 3 validation perspectives&lt;/li&gt;
&lt;li&gt;Perspectives must be in different network locations&lt;/li&gt;
&lt;li&gt;Majority consensus required for certificate issuance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation Approaches&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Distributed validation infrastructure&lt;/strong&gt;: CAs deploy validation servers globally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party validation services&lt;/strong&gt;: Independent services provide validation perspectives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cooperative validation&lt;/strong&gt;: CAs share validation infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Technical Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DNS Validation Enhancement&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Traditional validation (vulnerable)
dig @8.8.8.8 _acme-challenge.example.com TXT

# MCIP validation (resilient)
dig @validator1.ca.com _acme-challenge.example.com TXT
dig @validator2.ca.com _acme-challenge.example.com TXT  
dig @validator3.ca.com _acme-challenge.example.com TXT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HTTP Validation Enhancement&lt;/strong&gt;:&lt;br&gt;
Multiple perspectives attempt to retrieve validation tokens from different network locations, making BGP hijacking attacks much more difficult.&lt;/p&gt;
&lt;h3&gt;
  
  
  Industry Adoption
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Let's Encrypt Implementation&lt;/strong&gt;: Let's Encrypt has begun implementing multi-perspective validation, using multiple validation points for domain verification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CA/Browser Forum Requirements&lt;/strong&gt;: The Forum is developing requirements for multi-perspective validation as part of the Baseline Requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser Support&lt;/strong&gt;: Major browsers are encouraging CA adoption of MCIP through root store policies.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Reality of PKI Failures
&lt;/h2&gt;

&lt;p&gt;Despite the theoretical benefits of PKI, real-world implementation reveals significant problems that affect users daily.&lt;/p&gt;
&lt;h3&gt;
  
  
  Certificate Expiration Incidents
&lt;/h3&gt;

&lt;p&gt;The Spotify outage mentioned in recent reports exemplifies a pervasive problem: &lt;strong&gt;certificate expiration causing service disruptions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Expiration Scenarios&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgotten renewals&lt;/strong&gt;: Organizations fail to track certificate expiration dates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex renewal processes&lt;/strong&gt;: Multi-step validation requirements delay renewals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coordination failures&lt;/strong&gt;: Multiple teams must coordinate for certificate updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing gaps&lt;/strong&gt;: Renewed certificates aren't properly tested before deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Impact Scale&lt;/strong&gt;: Certificate expiration affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Major websites and services&lt;/li&gt;
&lt;li&gt;Internal corporate systems&lt;/li&gt;
&lt;li&gt;API endpoints and microservices&lt;/li&gt;
&lt;li&gt;Mobile applications and IoT devices&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Historical CA Failures
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DigiNotar (2011)&lt;/strong&gt;: Complete compromise of a Dutch CA led to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fraudulent certificates for major websites (Google, Facebook, Yahoo)&lt;/li&gt;
&lt;li&gt;Complete removal from all browser trust stores&lt;/li&gt;
&lt;li&gt;Bankruptcy of the CA company&lt;/li&gt;
&lt;li&gt;Demonstrated that WebTrust certification doesn't guarantee security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Symantec Issues (2017)&lt;/strong&gt;: Improper certificate issuance practices resulted in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google's decision to distrust Symantec certificates&lt;/li&gt;
&lt;li&gt;Forced sale of Symantec's CA business to DigiCert&lt;/li&gt;
&lt;li&gt;Massive certificate replacement efforts across the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Comodo Attacks (2011)&lt;/strong&gt;: Attackers obtained fraudulent certificates for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gmail, Yahoo, Hotmail&lt;/li&gt;
&lt;li&gt;Skype, Mozilla, WordPress&lt;/li&gt;
&lt;li&gt;Demonstrated vulnerability of domain validation processes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Trust Paradox
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WebTrust Certification Limitations&lt;/strong&gt;: As noted in the DigiNotar case, WebTrust certification doesn't guarantee security. This creates a false sense of security where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certified CAs can still be compromised&lt;/li&gt;
&lt;li&gt;Audit processes may miss critical vulnerabilities&lt;/li&gt;
&lt;li&gt;Users have no way to assess actual CA security levels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Validation Inconsistencies&lt;/strong&gt;: Different CAs use different validation methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain Validation (DV)&lt;/strong&gt;: Minimal validation, only proves domain control&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization Validation (OV)&lt;/strong&gt;: Verifies organization identity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extended Validation (EV)&lt;/strong&gt;: Rigorous identity verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users cannot easily determine validation levels, creating confusion about certificate trustworthiness.&lt;/p&gt;
&lt;h2&gt;
  
  
  Mechanisms for Domain Control
&lt;/h2&gt;
&lt;h3&gt;
  
  
  DNS CAA Records in Practice
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Implementation Example&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issue "digicert.com"
example.com. CAA 0 issuewild ";"
example.com. CAA 0 iodef "mailto:security@example.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adoption rates&lt;/strong&gt;: Many domains don't implement CAA records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS security&lt;/strong&gt;: CAA records are only as secure as DNS itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CA compliance&lt;/strong&gt;: Not all CAs properly check CAA records&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Certificate Transparency as a Control Mechanism
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Monitoring Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;monitor_certificates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ct_api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://crt.sh/?q={}&amp;amp;output=json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;certificates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cert&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;certificates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Certificate ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Issuer: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;issuer_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not Before: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;not_before&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not After: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;not_after&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real-World Monitoring&lt;/strong&gt;: Organizations like Facebook and Google operate sophisticated CT monitoring systems that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect unauthorized certificate issuance within minutes&lt;/li&gt;
&lt;li&gt;Automatically alert security teams&lt;/li&gt;
&lt;li&gt;Trigger incident response procedures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Warranty Problem: Who Pays When PKI Fails?
&lt;/h2&gt;

&lt;p&gt;One of the most significant issues with current PKI is the lack of meaningful warranties or liability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Certificate Authority Liability Limitations
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Typical CA Terms&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Liability limited to certificate cost (often $0 for DV certificates)&lt;/li&gt;
&lt;li&gt;No warranties beyond technical compliance&lt;/li&gt;
&lt;li&gt;Exclusions for consequential damages&lt;/li&gt;
&lt;li&gt;Dispute resolution through arbitration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-World Impact&lt;/strong&gt;: When certificate failures cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service outages costing millions in revenue&lt;/li&gt;
&lt;li&gt;Security breaches exposing customer data&lt;/li&gt;
&lt;li&gt;Cryptocurrency theft (as in MyEtherWallet)&lt;/li&gt;
&lt;li&gt;Reputation damage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Affected parties have little recourse against CAs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Race to the Bottom
&lt;/h3&gt;

&lt;p&gt;As Ian Grigg noted, the lack of meaningful liability creates a "race to the bottom" where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CAs compete on price rather than security&lt;/li&gt;
&lt;li&gt;Validation processes are minimized to reduce costs&lt;/li&gt;
&lt;li&gt;Security investments are seen as unnecessary expenses&lt;/li&gt;
&lt;li&gt;Market forces don't reward better security practices&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usability Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User Understanding
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Certificate Validation Complexity&lt;/strong&gt;: Users face challenges in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding certificate validation levels&lt;/li&gt;
&lt;li&gt;Recognizing legitimate vs. fraudulent certificates&lt;/li&gt;
&lt;li&gt;Knowing when to be concerned about certificate warnings&lt;/li&gt;
&lt;li&gt;Distinguishing between different types of certificate errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Professional Challenges&lt;/strong&gt;: Even security professionals struggle with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certificate chain validation&lt;/li&gt;
&lt;li&gt;Proper certificate deployment&lt;/li&gt;
&lt;li&gt;Understanding CA policy differences&lt;/li&gt;
&lt;li&gt;Implementing certificate monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operational Difficulties
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Certificate Management&lt;/strong&gt;: Organizations face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex renewal processes&lt;/li&gt;
&lt;li&gt;Coordination across multiple teams&lt;/li&gt;
&lt;li&gt;Testing and deployment challenges&lt;/li&gt;
&lt;li&gt;Inventory management for thousands of certificates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Automation Limitations&lt;/strong&gt;: While ACME has improved automation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many CAs don't support automated processes&lt;/li&gt;
&lt;li&gt;Complex validation requirements prevent automation&lt;/li&gt;
&lt;li&gt;Legacy systems can't integrate with modern certificate management&lt;/li&gt;
&lt;li&gt;Organizational processes haven't adapted to shorter certificate lifespans&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Future of Certificate Trust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Emerging Solutions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Certificate Transparency Evolution&lt;/strong&gt;: CT is expanding beyond just logging to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time monitoring and alerting&lt;/li&gt;
&lt;li&gt;Automated response to suspicious certificates&lt;/li&gt;
&lt;li&gt;Integration with threat intelligence platforms&lt;/li&gt;
&lt;li&gt;Policy enforcement based on CT data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DANE and DNS Security&lt;/strong&gt;: Improvements in DNS security through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNSSEC adoption&lt;/li&gt;
&lt;li&gt;DNS over HTTPS (DoH) and DNS over TLS (DoT)&lt;/li&gt;
&lt;li&gt;Authenticated DNS responses&lt;/li&gt;
&lt;li&gt;Integration with certificate validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Blockchain and Distributed Trust&lt;/strong&gt;: Experimental approaches include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blockchain-based certificate authorities&lt;/li&gt;
&lt;li&gt;Distributed consensus for certificate validation&lt;/li&gt;
&lt;li&gt;Cryptocurrency-based incentive models for security&lt;/li&gt;
&lt;li&gt;Decentralized identity systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Regulatory Developments
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;European Union eIDAS Regulation&lt;/strong&gt;: New EU regulations may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mandate specific CA security requirements&lt;/li&gt;
&lt;li&gt;Create liability frameworks for certificate failures&lt;/li&gt;
&lt;li&gt;Establish government oversight of CAs&lt;/li&gt;
&lt;li&gt;Require specific validation procedures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Industry Standards Evolution&lt;/strong&gt;: The CA/Browser Forum continues developing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shorter certificate lifespans (potentially 90 days)&lt;/li&gt;
&lt;li&gt;Stricter validation requirements&lt;/li&gt;
&lt;li&gt;Enhanced monitoring and reporting requirements&lt;/li&gt;
&lt;li&gt;Improved incident response procedures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: The Paradox of PKI
&lt;/h2&gt;

&lt;p&gt;The Public Key Infrastructure represents both the foundation of internet security and one of its greatest vulnerabilities. While PKI enables secure communications at massive scale, it also creates systemic risks and single points of failure that affect global internet security.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fundamental Tensions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Security vs. Usability&lt;/strong&gt;: Stronger security measures often make certificates more difficult to obtain and manage, potentially driving users toward less secure alternatives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralization vs. Decentralization&lt;/strong&gt;: While centralized CAs provide scalability and consistency, they also create systemic risks and power imbalances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market Forces vs. Security&lt;/strong&gt;: The competitive certificate market often rewards lower prices over better security, creating perverse incentives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Browser Power&lt;/strong&gt;: Web browsers, particularly Chrome, hold ultimate power over certificate policy, often overriding CA/Browser Forum consensus.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>x509</category>
      <category>rootca</category>
      <category>cybersecurity</category>
      <category>identity</category>
    </item>
    <item>
      <title>AI Coding Pitfalls and Solutions: A Practical Guide</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Mon, 27 Jan 2025 13:18:01 +0000</pubDate>
      <link>https://dev.to/discernible-io/ai-coding-pitfalls-and-solutions-a-practical-guide-j7b</link>
      <guid>https://dev.to/discernible-io/ai-coding-pitfalls-and-solutions-a-practical-guide-j7b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Most developers, if not all, are using AI by now. This is helping both newbies and highly experienced professionals.&lt;/p&gt;

&lt;p&gt;Unfortunately, like any other tool, AI coding can be less than helpful. Do you recall stories about people who end up in a lake following a GPS map application blindly? Something similar happens frequently to developers while using AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Default Pessimism
&lt;/h3&gt;

&lt;p&gt;The AI not only misses the context you don't share with it, it will not ask for more context, assuming you are telling it everything that needs to be told. For example, if you don't say you have access to the production server, it will try to solve the issue assuming there isn't access.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Know-it-all Syndrome
&lt;/h3&gt;

&lt;p&gt;The AI will give you a long list of all the things you can check and all the things you can try, like it had the magical bullet for your issue. Good luck working your way through.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Just Plaster It!
&lt;/h3&gt;

&lt;p&gt;The AI knows nothing of root causes. Presented with an issue it will try to solve that one issue ONLY, without checking why the issue is there in the first place. It tries to solve symptoms, not problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Goldberg Machine Patch
&lt;/h3&gt;

&lt;p&gt;The AI tries to give you a solution that will solve this issue and any other possible ever present in any system ever, and check and log everything under the sun. The solution seems to be bulletproof at first sight, but it is so complex it creates issues on its own that may be harder to fix than the original issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Dude Comparisons
&lt;/h3&gt;

&lt;p&gt;The AI will compare what you need to compare, but will miss essential components, for example overall number of items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions and Examples
&lt;/h2&gt;

&lt;p&gt;It is not hard to avoid these issues if you remember that you are a driver, not a passenger, in the coding process. Here are the solutions you can use to avoid each issue:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Default Pessimism - Solution
&lt;/h3&gt;

&lt;p&gt;Share most of the context, and instruct it to request more context whenever necessary. Provide working similar samples if available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bad Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How can I check if users are active in my system?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;AI's Limited Response:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_user_activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Assumes only local database access
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_logs.txt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Better Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to check if users are active in my system. We have:
- PostgreSQL database with user_sessions table
- Access to Redis cache
- Cloudwatch logs
- User activity tracked in NewRelic
Please ask if you need more context about any of these systems.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;AI's Comprehensive Response:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_user_activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Check Redis cache first for performance
&lt;/span&gt;    &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_activity:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check database for recent sessions
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            SELECT last_active_at 
            FROM user_sessions 
            WHERE user_id = %s
            ORDER BY last_active_at DESC 
            LIMIT 1
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Know-it-all Syndrome - Solution
&lt;/h3&gt;

&lt;p&gt;Request the AI to take only one step at a time, checking the result of each step before proceeding with the next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bad Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My API endpoints are slow. How can I improve performance?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Better Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My /users endpoint is taking 2.5s to respond. Let's start by profiling the database queries.
Here's the current code:

def get_users():
    users = User.query.all()
    return jsonify([user.to_dict() for user in users])

What's the first step to identify the bottleneck?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Just Plaster It! - Solution
&lt;/h3&gt;

&lt;p&gt;Ask the AI to explain how that solution is going to solve the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bad Code Issue:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Original problem
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;process_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payment failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Bad Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How do I fix this payment error?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Better Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We're seeing payment failures in production. Here's the code:

try:
    process_payment(amount)
except Exception:
    return "Payment failed"

Before implementing a fix, can you help me understand:
1. What types of exceptions might occur here?
2. How would each exception impact our payment flow?
3. What logging would help us identify the root cause?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Goldberg Machine Patch - Solution
&lt;/h3&gt;

&lt;p&gt;Ask the AI if this is a standard, best practice way to solve the issue, and if there is a simpler solution that will solve it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Problem:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Bad Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How can I make this user save function more robust?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;AI's Overcomplicated Response:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Ultra-robust user saving with extensive validation and logging
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;transaction_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting user save operation &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Pre-save validation
&lt;/span&gt;        &lt;span class="n"&gt;validation_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validate_user_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;validation_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Schema validation failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;validation_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user.save.validation_error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validation_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Backup current state
&lt;/span&gt;        &lt;span class="n"&gt;existing_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_one&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;existing_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;backup_collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_one&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_backup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existing_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="c1"&gt;# Complex retry logic
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;exponential_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_attempts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Post-save validation
&lt;/span&gt;        &lt;span class="n"&gt;saved_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_one&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inserted_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;saved_user&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Save verification failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="c1"&gt;# Extensive logging
&lt;/span&gt;        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User save successful &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user.save.success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inserted_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User save failed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user.save.error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert_team&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User save failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Better Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to add basic error handling and validation to this user save function.
What's the minimal change that would catch common issues?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;AI's Simpler Response:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Save user with basic validation and error handling
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing required fields: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;DuplicateKeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User already exists: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Dude Comparisons - Solution
&lt;/h3&gt;

&lt;p&gt;Ask the AI to perform a bijective comparison of items. This guarantees each and every item is compared with a peer only once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bad Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compare these two API response formats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Better Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can you do a field-by-field comparison of these two API response formats,
ensuring every field in both formats is addressed:

Format A:
{
    "user_id": "string",
    "name": "string",
    "roles": ["string"]
}

Format B:
{
    "id": "string",
    "full_name": "string",
    "permissions": ["string"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;By following these guidelines and remembering that you are the driver in the development process, you can effectively leverage AI as a powerful tool while avoiding its common pitfalls. The key is to be specific, provide context, and guide the AI step-by-step towards the solution you need.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>HashiCorp Vault Setup Guide for NEAR Protocol Accounts</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Tue, 14 Jan 2025 15:41:20 +0000</pubDate>
      <link>https://dev.to/discernible-io/hashicorp-vault-setup-guide-for-near-protocol-accounts-3ade</link>
      <guid>https://dev.to/discernible-io/hashicorp-vault-setup-guide-for-near-protocol-accounts-3ade</guid>
      <description>&lt;h1&gt;
  
  
  HashiCorp Vault Setup Guide for NEAR Protocol Accounts
&lt;/h1&gt;

&lt;p&gt;This guide walks you through setting up a HashiCorp Vault server to securely store NEAR Protocol accounts. Before starting, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A server with Ubuntu/Debian&lt;/li&gt;
&lt;li&gt;Domain name configured&lt;/li&gt;
&lt;li&gt;SSL certificates ready&lt;/li&gt;
&lt;li&gt;Root or sudo access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Initial Setup and Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install Vault
&lt;/h3&gt;

&lt;p&gt;First, add the HashiCorp repository and install Vault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add HashiCorp GPG key&lt;/span&gt;
wget &lt;span class="nt"&gt;-O-&lt;/span&gt; https://apt.releases.hashicorp.com/gpg | gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /usr/share/keyrings/hashicorp-archive-keyring.gpg

&lt;span class="c"&gt;# Add HashiCorp repository&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
    https://apt.releases.hashicorp.com &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;lsb_release &lt;span class="nt"&gt;-cs&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; main"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/hashicorp.list

&lt;span class="c"&gt;# Install Vault&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;vault
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure Vault Server
&lt;/h3&gt;

&lt;p&gt;Create the Vault configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/vault.d/vault.hcl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
ui = true
disable_mlock = true

storage "file" {
  path = "/opt/vault/data"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "/etc/vault.d/vault.crt"
  tls_key_file  = "/etc/vault.d/vault.key"
}

api_addr = "https://your-vault-domain:8200"
cluster_addr = "https://your-vault-domain:8201"

telemetry {
  disable_hostname = true
  prometheus_retention_time = "24h"
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. SSL/TLS Configuration
&lt;/h3&gt;

&lt;p&gt;Place your SSL certificates in &lt;code&gt;/etc/vault.d/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vault.crt&lt;/code&gt;: Your SSL certificate&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vault.key&lt;/code&gt;: Your private key&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you need to generate certificates, follow our guide on &lt;a href="https://dev.to/rodit-org/generate-your-lets-encrypt-digital-certificates-for-all-your-domains-using-apache-a13"&gt;generating Let's Encrypt certificates&lt;/a&gt;. Ensure your DNS is properly configured and your &lt;a href="https://dev.to/rodit-org/creating-a-new-developer-server-in-digital-ocean-h69"&gt;server is set up correctly&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. Set File Permissions
&lt;/h3&gt;

&lt;p&gt;Configure proper ownership and permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set ownership&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;vault:vault /etc/vault.d/vault.hcl
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;vault:vault /etc/vault.d/vault.key
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;vault:vault /etc/vault.d/vault.crt

&lt;span class="c"&gt;# Set permissions&lt;/span&gt;
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;640 /etc/vault.d/vault.hcl
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;640 /etc/vault.d/vault.key
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;640 /etc/vault.d/vault.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Create Systemd Service
&lt;/h3&gt;

&lt;p&gt;Set up Vault as a system service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/systemd/system/vault.service &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
[Unit]
Description="HashiCorp Vault - A tool for managing secrets"
Documentation=https://www.vaultproject.io/docs/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/vault.d/vault.hcl

[Service]
User=vault
Group=vault
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
Capabilities=CAP_IPC_LOCK+ep
CapabilityBoundingSet=CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill --signal HUP &lt;/span&gt;&lt;span class="nv"&gt;$MAINPID&lt;/span&gt;&lt;span class="sh"&gt;
KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
LimitNOFILE=65536
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vault Initialization and Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6. Initialize and Unseal
&lt;/h3&gt;

&lt;p&gt;Start the Vault service and perform initial setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Vault service&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;vault
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start vault

&lt;span class="c"&gt;# Configure Vault address&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'https://your-vault-domain:8200'&lt;/span&gt;

&lt;span class="c"&gt;# Initialize Vault&lt;/span&gt;
vault operator init

&lt;span class="c"&gt;# Unseal Vault (requires 3 of 5 keys)&lt;/span&gt;
vault operator unseal  &lt;span class="c"&gt;# First key&lt;/span&gt;
vault operator unseal  &lt;span class="c"&gt;# Second key&lt;/span&gt;
vault operator unseal  &lt;span class="c"&gt;# Third key&lt;/span&gt;

&lt;span class="c"&gt;# Verify status&lt;/span&gt;
vault status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Configure Access Policies
&lt;/h3&gt;

&lt;p&gt;Set up the following policies for different access levels:&lt;/p&gt;

&lt;h4&gt;
  
  
  Admin Policy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee &lt;/span&gt;signing-admin-policy.hcl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
path "sys/auth/*" {
  capabilities = ["create", "update", "delete", "sudo"]
}

path "sys/auth" {
  capabilities = ["read"]
}

path "auth/approle/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Operator Policy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee &lt;/span&gt;signing-operator-policy.hcl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
path "secret/data/signing-keys/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
  allowed_parameters = {
    "data" = []
    "options" = []
  }
}
path "secret/metadata/signing-keys/*" {
  capabilities = ["read", "list"]
}
path "secret/metadata/signing-keys" {
  capabilities = ["read", "list"]
}
path "secret/data/signing-keys" {
  capabilities = ["create", "read", "update", "list"]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  General Signing Policy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee &lt;/span&gt;signing-policy.hcl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
# Allow managing auth methods
path "sys/auth/*" {
  capabilities = ["create", "update", "delete", "sudo"]
}

# Allow listing auth methods
path "sys/auth" {
  capabilities = ["read"]
}

# Allow managing roles
path "auth/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

# Existing podman-keys permissions
path "secret/data/signing-keys/*" {
  capabilities = ["create", "read", "update", "delete"]
}

# Allow listing secrets
path "secret/metadata/*" {
  capabilities = ["list"]
}

# Allow managing AppRole auth configuration
path "auth/approle/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Reader Policy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tee &lt;/span&gt;signing-reader-policy.hcl &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
path "secret/data/signing-keys/*" {
  capabilities = ["read"]
}
path "secret/metadata/signing-keys/*" {
  capabilities = ["read", "list"]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply all policies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault policy write signing-admin-policy signing-admin-policy.hcl
vault policy write signing-operator-policy signing-operator-policy.hcl
vault policy write signing-policy signing-policy.hcl
vault policy write signing-reader-policy signing-reader-policy.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Enable Key-Value Store
&lt;/h3&gt;

&lt;p&gt;Enable the KV secrets engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault secrets &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret kv-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Configure AppRole Authentication
&lt;/h3&gt;

&lt;p&gt;Set up authentication for automated access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable AppRole&lt;/span&gt;
vault auth &lt;span class="nb"&gt;enable &lt;/span&gt;approle

&lt;span class="c"&gt;# Create role&lt;/span&gt;
vault write auth/approle/role/NEAR-MANAGER-ROLE &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_policies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"near-operator-policy"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_max_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;token_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"service"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"768h"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieve role credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get Role ID&lt;/span&gt;
vault &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json auth/approle/role/NEAR-MANAGER-ROLE/role-id | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data.role_id'&lt;/span&gt;

&lt;span class="c"&gt;# Get Secret ID&lt;/span&gt;
vault write &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json auth/approle/role/NEAR-MANAGER-ROLE/secret-id | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data.secret_id'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10. Store NEAR Protocol Accounts
&lt;/h3&gt;

&lt;p&gt;On each server that needs to access the Vault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set Vault address&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'VAULT_SERVER_URL'&lt;/span&gt;

&lt;span class="c"&gt;# Configure credentials&lt;/span&gt;
&lt;span class="nv"&gt;ROLE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-role-id'&lt;/span&gt;
&lt;span class="nv"&gt;SECRET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-secret-id'&lt;/span&gt;

&lt;span class="c"&gt;# Login&lt;/span&gt;
vault write auth/approle/login &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;role_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ROLE_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;secret_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SECRET_ID&lt;/span&gt;

&lt;span class="c"&gt;# Store NEAR account&lt;/span&gt;
vault kv put &lt;span class="nt"&gt;-mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret near-accounts/my-account &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;account_json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@/path/to/near-credentials/mainnet/account.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unsealing Process
&lt;/h3&gt;

&lt;p&gt;The Vault uses a threshold unsealing process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires 3 of 5 keys by default&lt;/li&gt;
&lt;li&gt;Vault starts in a sealed state&lt;/li&gt;
&lt;li&gt;Cannot decrypt storage until unsealed&lt;/li&gt;
&lt;li&gt;Multiple operators must provide keys&lt;/li&gt;
&lt;li&gt;Never store unseal keys on the Vault server&lt;/li&gt;
&lt;li&gt;Unsealing required after maintenance/restarts&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vault</category>
      <category>nearprotocol</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>Closing the PKIX Working Group is, apparently, not news</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Tue, 14 Jan 2025 12:23:32 +0000</pubDate>
      <link>https://dev.to/discernible-io/closing-the-pkix-working-group-is-apparently-not-news-3a3f</link>
      <guid>https://dev.to/discernible-io/closing-the-pkix-working-group-is-apparently-not-news-3a3f</guid>
      <description>&lt;p&gt;PKI is perfect, isn't it?&lt;/p&gt;

&lt;p&gt;The PKIX Working Group was of the digital certificates standards, among them X.509, that enable various applications such as secure email, web security (SSL/TLS), and digital signatures. It officially concluded its operations... more than ten years ago (31 October 2013) .. Coincidentally, more or less at the same time Bitcoin was created.&lt;/p&gt;

&lt;p&gt;The closure can only mean that PKI is perfect (many beg to disagree), or that the companies that sponsor work in PKI have zero interest in evolving the technology as their interests are well served with the current one.&lt;/p&gt;

&lt;p&gt;PKI, despite years of development and refinement still has challenges of around certificate management, trust hierarchies, and the susceptibility of certificate authorities to breaches and mismanagement.&lt;/p&gt;

&lt;p&gt;In order to manage some of the flaws in PKI, the main players created a system called Certificate Transparency (CT), a framework and set of standards aimed at tackling the vulnerabilities in the lifecycle of digital certificates used in public key infrastructures (PKI). CT provides a layer of security by enabling the detection of misissued or malicious certificates through publicly auditable logs. The core components of Certificate Transparency are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Public Logs: These are append-only logs where certificates are recorded. Each log entry is cryptographically secured to prevent tampering. Logs are operated by various organizations and are designed to be publicly accessible and verifiable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitors: Entities that observe and verify the entries in CT logs. Monitors can detect suspicious certificates and alert domain owners if an unauthorized certificate is issued for their domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auditors: These are entities that check the consistency and integrity of CT logs. Auditors ensure that logs are functioning correctly and have not been tampered with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Merkle Trees: A data structure used by CT logs to provide a cryptographic guarantee of the log's integrity. Merkle trees allow efficient and secure verification of individual log entries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CT has several flaws, among them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The reliance on a limited number of public logs. If a log operator is compromised or goes offline, it could disrupt the CT ecosystem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing and maintaining CT requires additional effort and resources from certificate authorities, website operators, and auditors. This complexity can be a barrier, particularly for smaller organizations with limited technical capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As the number of certificates grows, the size and management of CT logs can become challenging. The logs must handle large volumes of data efficiently while maintaining performance and integrity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CT alone does not solve all issues related to PKI and digital certificates. While it adds a layer of transparency and detection, it does not prevent misissuance or replace the need for robust security practices.&lt;/p&gt;

&lt;p&gt;So we are using a blockchain to mitigate the risks that arise form a system that was designed in the late 80s early 90s, with the requirement of being able to operate off-line.&lt;/p&gt;

&lt;p&gt;Why not evolve the technology and use self-issued blockchain based digitally signed tokens, and cut the middleman?&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptocurrency</category>
      <category>blockchain</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Generate your Let's Encrypt Digital Certificates for all your domains using Apache</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Mon, 13 Jan 2025 12:59:04 +0000</pubDate>
      <link>https://dev.to/discernible-io/generate-your-lets-encrypt-digital-certificates-for-all-your-domains-using-apache-a13</link>
      <guid>https://dev.to/discernible-io/generate-your-lets-encrypt-digital-certificates-for-all-your-domains-using-apache-a13</guid>
      <description>&lt;p&gt;As someone who's dealt with their fair share of digital certificate  headaches, I'm sharing a comprehensive guide to setting up and managing SSL/TLS certificates with Apache. You may actually use a different web server, but Apache seems to be the easiest way to achieve this. Once you are done, you just have to copy the generated certificates to the right directories in your web server of choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial DNS Setup
&lt;/h2&gt;

&lt;p&gt;First, ensure all your domains point to your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create A records for each domain&lt;/span&gt;
domain1.com -&amp;gt; server_ip
www.domain1.com -&amp;gt; server_ip
domain2.com -&amp;gt; server_ip
www.domain2.com -&amp;gt; server_ip
domain3.com -&amp;gt; server_ip
www.domain3.com -&amp;gt; server_ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;Create an organized directory structure that scales with multiple domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create base directories&lt;/span&gt;
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/www/domains
&lt;span class="c"&gt;# Create individual domain directories&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="k"&gt;in &lt;/span&gt;domain1.com domain2.com domain3.com&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/www/domains/&lt;span class="nv"&gt;$domain&lt;/span&gt;/public_html
    &lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/www/domains/&lt;span class="nv"&gt;$domain&lt;/span&gt;/logs
    &lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$USER&lt;/span&gt; /var/www/domains/&lt;span class="nv"&gt;$domain&lt;/span&gt;
    &lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 755 /var/www/domains/&lt;span class="nv"&gt;$domain&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Virtual Host Configuration
&lt;/h2&gt;

&lt;p&gt;Create separate virtual host files for each domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create configuration files&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="k"&gt;in &lt;/span&gt;domain1.com domain2.com domain3.com&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;sudo touch&lt;/span&gt; /etc/apache2/sites-available/&lt;span class="nv"&gt;$domain&lt;/span&gt;.conf
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Template for each domain's virtual host (example for domain1.com):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="sr"&gt; *:80&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;ServerAdmin&lt;/span&gt; webmaster@domain1.com
    &lt;span class="nc"&gt;ServerName&lt;/span&gt; domain1.com
    &lt;span class="nc"&gt;ServerAlias&lt;/span&gt; www.domain1.com
    &lt;span class="nc"&gt;DocumentRoot&lt;/span&gt; /var/www/domains/domain1.com/public_html
    &lt;span class="nc"&gt;ErrorLog&lt;/span&gt; /var/www/domains/domain1.com/logs/error.log
    &lt;span class="nc"&gt;CustomLog&lt;/span&gt; /var/www/domains/domain1.com/logs/access.log combined

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;Directory&lt;/span&gt;&lt;span class="sr"&gt; /var/www/domains/domain1.com/public_html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="nc"&gt;Options&lt;/span&gt; &lt;span class="ss"&gt;Indexes&lt;/span&gt; &lt;span class="ss"&gt;FollowSymLinks&lt;/span&gt;
        &lt;span class="nc"&gt;AllowOverride&lt;/span&gt; &lt;span class="ss"&gt;All&lt;/span&gt;
        &lt;span class="nc"&gt;Require&lt;/span&gt; &lt;span class="ss"&gt;all&lt;/span&gt; granted
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Batch Certificate Management
&lt;/h2&gt;

&lt;p&gt;Here's how to efficiently manage certificates for multiple domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Certbot&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-apache

&lt;span class="c"&gt;# Create a domains list file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"domain1.com www.domain1.com"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; domains.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"domain2.com www.domain2.com"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; domains.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"domain3.com www.domain3.com"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; domains.txt

&lt;span class="c"&gt;# Obtain certificates for all domains in one command&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--apache&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;domains.txt | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automated Renewal Management
&lt;/h2&gt;

&lt;p&gt;Create a renewal management script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# /usr/local/bin/cert-renew-manager.sh&lt;/span&gt;

&lt;span class="c"&gt;# Renew all certificates&lt;/span&gt;
certbot renew

&lt;span class="c"&gt;# Check renewal status for each domain&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="k"&gt;in &lt;/span&gt;domain1.com domain2.com domain3.com&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;cert_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/letsencrypt/live/&lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="s2"&gt;/fullchain.pem"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cert_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nv"&gt;expiry_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl x509 &lt;span class="nt"&gt;-enddate&lt;/span&gt; &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cert_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Domain: &lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="s2"&gt; - Certificate expires: &lt;/span&gt;&lt;span class="nv"&gt;$expiry_date&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Warning: No certificate found for &lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Batch Security Configuration
&lt;/h2&gt;

&lt;p&gt;Apply security headers to all domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a common security configuration&lt;/span&gt;
&lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apache2/conf-available/security-headers.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Enable for all sites&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enconf security-headers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring and Maintenance
&lt;/h2&gt;

&lt;p&gt;Create a monitoring script for multiple domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# /usr/local/bin/cert-monitor.sh&lt;/span&gt;

&lt;span class="nv"&gt;domains&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"domain1.com"&lt;/span&gt; &lt;span class="s2"&gt;"domain2.com"&lt;/span&gt; &lt;span class="s2"&gt;"domain3.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;notification_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"admin@yourdomain.com"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;expiry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;/dev/null | openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-enddate&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;expiry_epoch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expiry&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;current_epoch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;days_left&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expiry_epoch&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$current_epoch&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;86400&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$days_left&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 30 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Warning: Certificate for &lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="s2"&gt; expires in &lt;/span&gt;&lt;span class="nv"&gt;$days_left&lt;/span&gt;&lt;span class="s2"&gt; days"&lt;/span&gt; | mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"Certificate Expiry Warning"&lt;/span&gt; &lt;span class="nv"&gt;$notification_email&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Batch Testing
&lt;/h2&gt;

&lt;p&gt;Create a comprehensive test script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# /usr/local/bin/cert-test.sh&lt;/span&gt;

&lt;span class="c"&gt;# Test Apache configuration&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apache2ctl configtest

&lt;span class="c"&gt;# Test SSL configuration for each domain&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;domain &lt;span class="k"&gt;in &lt;/span&gt;domain1.com domain2.com domain3.com&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Testing SSL configuration for &lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://&lt;span class="nv"&gt;$domain&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
    openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;/dev/null | openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-dates&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recovery Procedures
&lt;/h2&gt;

&lt;p&gt;Create a backup script for all certificates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# /usr/local/bin/cert-backup.sh&lt;/span&gt;

&lt;span class="nv"&gt;backup_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/cert-backups/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;

&lt;span class="c"&gt;# Backup all certificates and configurations&lt;/span&gt;
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; /etc/letsencrypt &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;/
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; /etc/apache2/sites-available &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;/

&lt;span class="c"&gt;# Archive the backup&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-czf&lt;/span&gt; &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;.tar.gz &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$backup_dir&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Managing multiple domains requires more automation and organization, but with these scripts and structures in place, you can efficiently manage dozens of domains without increasing administrative overhead. Remember to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep domain lists updated&lt;/li&gt;
&lt;li&gt;Run regular batch tests&lt;/li&gt;
&lt;li&gt;Maintain comprehensive backups&lt;/li&gt;
&lt;li&gt;Monitor all domains systematically&lt;/li&gt;
&lt;li&gt;Document any domain-specific configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach scales well whether you're managing a handful of domains or hundreds, while keeping your certificate management process clean and maintainable.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>webdev</category>
      <category>ssl</category>
    </item>
    <item>
      <title>IP Whitelisting, the silent killer</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Mon, 13 Jan 2025 09:36:08 +0000</pubDate>
      <link>https://dev.to/discernible-io/ip-whitelisting-the-silent-killer-39mo</link>
      <guid>https://dev.to/discernible-io/ip-whitelisting-the-silent-killer-39mo</guid>
      <description>&lt;p&gt;All systems in the same network can communicate with each other freely, from the lowest layers of sending frames and packets, to RPC calls, etc. This implies that we have the same trust in all systems, for example, they are all managed by the same IT team. Sometimes you have systems in the same network that mostly don't trust each other, for example, system interfaces that are Internet facing. So you create rules using firewalls, proxies, VPNs, API calls authenticated with API keys, etc, to enable trusted communication among the systems and applications that your either manage, or you decide to use. IP whitelisting, which should be better called IP allow listing, is very widely used. This is bad news, for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is an inflexible system. When something changes you have to synchronize the changes on both sides of any pair. This makes moving any system to a business continuity mode very unreliable, complicated and slow.&lt;/li&gt;
&lt;li&gt;It is obscure. Only administrators with access to privileged operations understand what has been configured, why an how.&lt;/li&gt;
&lt;li&gt;It is often poorly documented or undocumented. When there is any kind of incident, it makes troubleshooting complicated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probably the two main unnecessary reasons companies face expensive incidents that take several days to fix are expired digital certificates and brittle architectures resulting from using IP whitelising. There are many solutions depending on what you are trying to achieve with IP whitelisting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An ethernet cable for systems that have free interfaces and are close to each other.&lt;/li&gt;
&lt;li&gt;A point to point VPN for systems that you manage but need to cross untrusted networks to communicate.&lt;/li&gt;
&lt;li&gt;API keys for authentication of services outside your network.&lt;/li&gt;
&lt;li&gt;Among others…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The silver lining is: If you change jobs every couple of year, it will be someone else who will have to fix the mess. Yupee!&lt;/p&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>networking</category>
      <category>architecture</category>
    </item>
    <item>
      <title>You May Prefer to Know Less About PKI Flaws but Now Is Too Late</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Mon, 13 Jan 2025 09:16:45 +0000</pubDate>
      <link>https://dev.to/discernible-io/rant-i-would-prefer-to-know-less-about-pki-flaws-but-now-is-too-late-1ljo</link>
      <guid>https://dev.to/discernible-io/rant-i-would-prefer-to-know-less-about-pki-flaws-but-now-is-too-late-1ljo</guid>
      <description>&lt;p&gt;While you thought it was here to help all along, things like this happen all the time: &lt;a href="https://www.npr.org/2022/05/31/1102320291/a-spotify-publisher-was-down-monday-night-the-culprit-a-lapsed-security-certific" rel="noopener noreferrer"&gt;A Spotify publisher was down Monday night. The culprit? A lapsed security certificate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Public Key Infrastructure is pervasive and some would say it brings great benefits and makes the internet better. You can't disagree that being able to encrypt our connections with the websites and services we use has security and privacy benefits, but while the concept of PKI sounds good on paper, it seems to be a solution that has many issues, and has created some issues of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  One: PKIs Behaving Badly
&lt;/h2&gt;

&lt;p&gt;You are supposed to trust PKIs. But can you really trust them? What if a PKI authority fails to verify if someone owns a domain (CertStar 2008), creates intentionally certificates for domains without the knowledge of the owner (ANSSI 2013), or it is plainly hacked and abused (Diginotar 2011). Well, apparently there is a certification for Certificate Authorities that should guarantee that they take appropriate security measures, WebTrust CA. All Certificate Authorities that are certified should be secure, right?&lt;/p&gt;

&lt;p&gt;Diginotar, as far as you can check, was WebTrust CA certified! This means that any Certificate Authority being certified does not mean being secure. This either means that WebTrust certificate is useless or our trust in a Certificate Authority is disconnected to it being certified or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two: Who can create a CA?
&lt;/h2&gt;

&lt;p&gt;Anyone! The only gatekeeper for the creation of Certificate Authorities is the pre-installed root list that comes with the most popular operating systems and browsers. If you get included in the list, the user does not need to install your root certificate, which is complicated for many users. Misbehaving CAs are so problematic that a patch was necessary, Certificate Transparency.&lt;/p&gt;

&lt;p&gt;Recent developments in EU Law will not make this problem neither better, nor worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three: Who owns the digital certificate, Jekyll or Hyde?
&lt;/h2&gt;

&lt;p&gt;The methods used to validate who owns an ID are different between different Certificate Authorities, an ID can be a URL, an email or any other identifier. So the level of assurance of a certificate issued by different CAs is not only different, but the final non specialist user has no way to determine what level it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four: Warranty aka Responsibility
&lt;/h2&gt;

&lt;p&gt;So anyone with enough money and influence can create a CA, secure it to unknown levels of security, and finally implement inconsistent methods of validation of IDs. So what degree of trust does a user get from this setup? None. No user has ever received compensation for any damage caused by a unreliable or bogus certificate. Certificate Authorities do not provide any warranty on the certificates they issue beyond being compliant with technical standards. As Ian Grigg notes, this creates a race to the bottom in certificate quality between CAs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five: Lack of Usability
&lt;/h2&gt;

&lt;p&gt;Users should be able to check if a website is authentic, and current. But how do users, including professionals, check if they are connecting to the right website? Doing a search in a search engine, not checking the digital certificate.&lt;/p&gt;

&lt;p&gt;Can you improve your security rotating your key more often? No, it is hardcoded by CA and industry practices. Can you rotate your key less often as your environment is low security and does not need it? Again, no you can't, and many companies suffer incidents related to certificate renewal.&lt;/p&gt;

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

&lt;p&gt;PKI does not deliver hardly any of the benefits it is supposed to. But there is no current alternative so we are stuck with it. Why are most issues identified in PKI Problems Draft RFC version 0 gone in version 5? Are the issues solved, or perhaps there is an interest to keep them muted?&lt;/p&gt;

&lt;p&gt;Sometimes one wonders if PKI was a clever way to prevent public key cryptography from being widely deployed to final users…. ever notice how client server side certificates are almost never used due to the many implementation hurdles?&lt;/p&gt;

&lt;p&gt;Final note: The PKIX workgroup that publishes Digital Certificates standards has been closed for 10 years now. Are they perfect now?&lt;/p&gt;

&lt;h3&gt;
  
  
  Sources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/draft-housley-web-pki-problems" rel="noopener noreferrer"&gt;PKI Problems Draft RFC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.schneier.com/wp-content/uploads/2016/02/paper-pki.pdf" rel="noopener noreferrer"&gt;Carl Ellison and Bruce Schneier's Ten Risks of PKI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sslmate.com/resources/certificate_authority_failures" rel="noopener noreferrer"&gt;List of Certificate Authority Failures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.iang.org/ssl/pki_considered_harmful.PDF" rel="noopener noreferrer"&gt;Ian Grigg's PKI considered harmful&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>ssl</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Creating a new Developer Server in Digital Ocean</title>
      <dc:creator>discernible-io</dc:creator>
      <pubDate>Fri, 10 Jan 2025 15:05:11 +0000</pubDate>
      <link>https://dev.to/discernible-io/creating-a-new-developer-server-in-digital-ocean-h69</link>
      <guid>https://dev.to/discernible-io/creating-a-new-developer-server-in-digital-ocean-h69</guid>
      <description>&lt;p&gt;This guide will walk you through the process step by step, from creating your droplet to adding some essential development tools for Rust and Javascript.&lt;/p&gt;

&lt;p&gt;Note: Picture by &lt;a href="https://unsplash.com/photos/a-macbook-with-lines-of-code-on-its-screen-on-a-busy-desk-m_HRfLhgABo" rel="noopener noreferrer"&gt;Christopher Gower's&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A DigitalOcean account&lt;/li&gt;
&lt;li&gt;Basic command line knowledge&lt;/li&gt;
&lt;li&gt;SSH client installed on your local machine&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Creating Your Droplet
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log into your DigitalOcean account and click "Create Droplet"&lt;/li&gt;
&lt;li&gt;Choose your region

&lt;ul&gt;
&lt;li&gt;Note: All resources in this datacenter will be part of the same VPC network&lt;/li&gt;
&lt;li&gt;They can communicate securely over their Private IP addresses&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Select Ubuntu (latest version)&lt;/li&gt;
&lt;li&gt;Choose NVMe SSD for storage&lt;/li&gt;
&lt;li&gt;Select the basic plan:

&lt;ul&gt;
&lt;li&gt;2GB RAM&lt;/li&gt;
&lt;li&gt;25GB Disk&lt;/li&gt;
&lt;li&gt;1TB transfer&lt;/li&gt;
&lt;li&gt;Approximately $12/month&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  SSH Key Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal and navigate to SSH directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd&lt;/span&gt; ~/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Generate a new SSH key:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;p&gt;When prompted, save the key as &lt;code&gt;id_NEWSERVERNAME&lt;/code&gt; (replace NEWSERVERNAME with your server name)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Skip the passphrase by pressing Enter twice&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify the key creation:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; ~/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Display your public key:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_NEWSERVERNAME.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Copy the output and paste it into the "SSH KEY CONTENT" field on DigitalOcean&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill in the hostname field with your server name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click "Create Droplet"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Initial Server Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  First Login and Updates
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in as root using your SSH key&lt;/li&gt;
&lt;li&gt;Update the system:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get dist-upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User Account Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new user:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Grant administrative privileges:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; admin USERNAMEOFYOURCHOICE
   usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;USERNAMEOFYOURCHOICE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Swap File Configuration
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check current swap:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;swapon &lt;span class="nt"&gt;--show&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create and configure swap file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;fallocate &lt;span class="nt"&gt;-l&lt;/span&gt; 1G /swapfile
   &lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 /swapfile
   &lt;span class="nb"&gt;sudo &lt;/span&gt;mkswap /swapfile
   &lt;span class="nb"&gt;sudo &lt;/span&gt;swapon /swapfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Make swap permanent by adding to fstab:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'/swapfile none swap sw 0 0'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Essential Tools Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;mc btop ncdu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  System Reboot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;shutdown &lt;span class="nt"&gt;-r&lt;/span&gt; now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Development Environment Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bash Customization
&lt;/h3&gt;

&lt;p&gt;Login as your new user and edit &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;force_color_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes
&lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${debian_chroot:+($debian_chroot)}\[\033[0;36m\]\u@\h\[\033[00m\]:\[\033[0;34m\]\w\[\033[00m\]\$ '&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Available colors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Black: &lt;code&gt;\[\033[0;30m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Red: &lt;code&gt;\[\033[0;31m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Green: &lt;code&gt;\[\033[0;32m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Yellow: &lt;code&gt;\[\033[0;33m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Blue: &lt;code&gt;\[\033[0;34m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Magenta: &lt;code&gt;\[\033[0;35m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cyan: &lt;code&gt;\[\033[0;36m\]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;White: &lt;code&gt;\[\033[0;37m\]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development Tools Installation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install essential build tools:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;build-essential
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure Git:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"YOUR.EMAIL@EXAMPLE.COM"&lt;/span&gt;
   git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"YOUR_GITHUB_USERNAME"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install Rust:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
   &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.cargo/env"&lt;/span&gt;
   rustc &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install additional development dependencies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pkg-config xdg-utils httpie libssl-dev net-tools openssh-server &lt;span class="se"&gt;\&lt;/span&gt;
   debhelper-compat clang-tools libudev-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Security Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Firewall Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Configure UFW:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 22/tcp
   &lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/tcp
   &lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSH Configuration
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set up SSH access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On your local machine:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_NEWSERVERNAME.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Copy the output and add it to &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; on the server&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Your development server is now ready for use! You have a secure, well-configured environment with essential development tools installed. The server includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A non-root user with sudo privileges&lt;/li&gt;
&lt;li&gt;Configured swap space&lt;/li&gt;
&lt;li&gt;Essential development tools and utilities&lt;/li&gt;
&lt;li&gt;Basic security settings with UFW&lt;/li&gt;
&lt;li&gt;Rust programming environment&lt;/li&gt;
&lt;li&gt;Various development dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember to regularly update your system and monitor resource usage with the installed tools (btop, ncdu).&lt;/p&gt;

&lt;p&gt;If you use Visual Code, for example you can now configure your IDE following these instructions: (&lt;a href="https://code.visualstudio.com/docs/remote/ssh?WT.mc_id=netbc-meetup-antchu" rel="noopener noreferrer"&gt;https://code.visualstudio.com/docs/remote/ssh?WT.mc_id=netbc-meetup-antchu&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.digitalocean.com" rel="noopener noreferrer"&gt;DigitalOcean Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ubuntu.com/server/docs" rel="noopener noreferrer"&gt;Ubuntu Server Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.ubuntu.com/community/UFW" rel="noopener noreferrer"&gt;UFW Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>development</category>
    </item>
  </channel>
</rss>
