<?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: Anthony Owens</title>
    <description>The latest articles on DEV Community by Anthony Owens (@tonedefdev).</description>
    <link>https://dev.to/tonedefdev</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%2F3948129%2F0874796c-a3ed-4920-b901-bc3968cda0bc.png</url>
      <title>DEV Community: Anthony Owens</title>
      <link>https://dev.to/tonedefdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tonedefdev"/>
    <language>en</language>
    <item>
      <title>I got tired of paying JFrog for a secure OpenTofu / Terraform registry so I built my own</title>
      <dc:creator>Anthony Owens</dc:creator>
      <pubDate>Tue, 26 May 2026 12:00:00 +0000</pubDate>
      <link>https://dev.to/tonedefdev/i-got-tired-of-paying-jfrog-for-a-secure-opentofu-terraform-registry-so-i-built-my-own-5egp</link>
      <guid>https://dev.to/tonedefdev/i-got-tired-of-paying-jfrog-for-a-secure-opentofu-terraform-registry-so-i-built-my-own-5egp</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/tonedefdev/opendepot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a tale as old as time — you want to implement a secure, centralized storage system to easily distribute these awesome IaC modules that your team has developed, but you quickly find that enterprise-grade comes with an enterprise price. You could stick with the good ol' GitHub refs, but you soon realize this doesn't scale well. Delivering critical security updates to developers becomes a tedious process. You then think to yourself "if only I could use OpenTofu version constraints!" Those constraints, like the pessimistic version constraint &lt;code&gt;~&amp;gt; v1.0.0&lt;/code&gt; for modules, make delivering security patches at scale significantly less challenging, however, you only get access to them through the registry protocol.&lt;/p&gt;

&lt;p&gt;So you spend late-nights scouring GitHub and Reddit looking for open-source registry projects hoping that you don't have to "pay the piper." Before you know it, you've spent months implementing several different open-source systems only to find each one either had a painful deployment process, no turn-key migration path, missing key features, or inconsistent authentication. You feel defeated — you have deadlines, after all, so you decide to "pony up" and "pay the man" just for peace of mind so you can mark your feature done.&lt;/p&gt;

&lt;p&gt;I, for one, hate surrendering to the corporate SaaS overlords in this manner! From that painful journey I put my poor team through, and the lessons I learned along the way, I realized this was an opportunity to give back to the open-source community. That's when I first came up with the idea for OpenDepot!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;OpenDepot is an enterprise-grade OpenTofu / Terraform module and provider registry built entirely to be Kubernetes native. OpenDepot uses first-class Kubernetes primitives like Custom Resource Definitions and operators to streamline and modernize the module and provider pipeline. Instead of "pushing and praying" like I had to do with other registries, especially enterprise-grade solutions like Artifactory, OpenDepot is entirely declarative and offers administrators complete control over their supply chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GitOps Way
&lt;/h2&gt;

&lt;p&gt;The preferred method to deliver a new module version is by using GitOps with ArgoCD / Flux. This allows you to keep your registry manifest in the same repo as the module itself. When it's time to update or add new features to your module, the same pull request process you already use for module code is now tied-in with its release process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform-aws-eks/
└── opendepot/
    └── terraform-aws-eks.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  OpenDepot Module
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot.defdev.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Module&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;moduleConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
    &lt;span class="na"&gt;repoOwner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-org&lt;/span&gt;
    &lt;span class="na"&gt;repoUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/my-org/terraform-aws-eks&lt;/span&gt;
    &lt;span class="na"&gt;fileFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zip&lt;/span&gt;
    &lt;span class="na"&gt;immutable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-org-opendepot-modules&lt;/span&gt;
        &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
    &lt;span class="na"&gt;githubClientConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;useAuthenticatedClient&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.10.1"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.11.0"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.12.0"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.13.0"&lt;/span&gt;   &lt;span class="c1"&gt;# added in PR #42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ArgoCD Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/my-org/terraform-aws-eks&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-system&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The release workflow then looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A developer opens a PR against their OpenTofu module repository with the code changes&lt;/li&gt;
&lt;li&gt;The same PR includes an update to the OpenDepot Module manifest, adding the new version to &lt;code&gt;spec.versions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The team reviews both the module code and the registry manifest in a single PR&lt;/li&gt;
&lt;li&gt;On approval and merge, Argo CD detects the change and syncs the &lt;code&gt;Module&lt;/code&gt; resource to the cluster&lt;/li&gt;
&lt;li&gt;OpenDepot takes over — the Module controller creates a &lt;code&gt;Version&lt;/code&gt; resource, and the Version controller fetches the archive from GitHub and uploads it to storage. Once completed, a SHA256 checksum of the archive is stored in the &lt;code&gt;status&lt;/code&gt; field before marking the Version as synced.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You can also use a centralized repo that hosts all your OpenDepot manifests, with a single ArgoCD application that gives you a visual overview of your entire registry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Storage Configuration
&lt;/h2&gt;

&lt;p&gt;OpenDepot supports all three major cloud provider storage backends as well as local filesystem storage:&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS S3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-modules&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Azure Blob
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;azureBlob&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;accountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepotmodules&lt;/span&gt;
    &lt;span class="na"&gt;accountUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://opendepotmodules.blob.core.windows.net&lt;/span&gt;
    &lt;span class="na"&gt;subscriptionID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;
    &lt;span class="na"&gt;resourceGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-rg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Google Cloud
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gcs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-modules&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filesystem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data/opendepot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extensible by design:&lt;/strong&gt; I designed OpenDepot to leverage a Go interface for storage. Adding and testing new providers is straightforward — provide a concrete implementation for the interface, update the API, regenerate new CRDs, and you're ready to start testing. See &lt;a href="https://github.com/tonedefdev/opendepot/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Pre-signed URLs&lt;/strong&gt; allow you to offload large egress costs (AWS providers can be ~700MB) by redirecting clients to pull directly from cloud storage instead of proxying through your infrastructure. Configure per-module, per-provider, or globally through the Depot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-providers&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
  &lt;span class="na"&gt;presign&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15m"&lt;/span&gt;
    &lt;span class="na"&gt;fallbackToProxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fallback behavior:&lt;/strong&gt; When &lt;code&gt;fallbackToProxy&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, if a pre-signed URL cannot be generated the server proxies the download itself. Set it to &lt;code&gt;false&lt;/code&gt; to enforce that all downloads always use pre-signed URLs and never pass through your infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Filesystem storage&lt;/strong&gt; is backed by a Kubernetes Persistent Volume with any &lt;code&gt;StorageClass&lt;/code&gt; that supports &lt;code&gt;ReadWriteMany&lt;/code&gt;. The Version controller needs to write artifacts to the same volume the Server serves them from — hence the &lt;code&gt;ReadWriteMany&lt;/code&gt; requirement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Init container privileges:&lt;/strong&gt; On startup, an init container runs as root to &lt;code&gt;chown&lt;/code&gt;/&lt;code&gt;chgrp&lt;/code&gt; the directory mount so that user/group &lt;code&gt;65532&lt;/code&gt; (the user the containers run as) can read/write to it. This is the only point where elevated privileges are required — otherwise, OpenDepot runs as non-root across the board.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Depot (Pull-Based)
&lt;/h2&gt;

&lt;p&gt;If you don't follow a GitOps process, no worries! The Depot resource allows you to pull down modules and providers using version constraints, creating a private mirror for public providers with a fully defined release process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot.defdev.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Depot&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-team-depot&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;githubClientConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;useAuthenticatedClient&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;moduleConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fileFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zip&lt;/span&gt;
      &lt;span class="na"&gt;immutable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-registry&lt;/span&gt;
        &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
  &lt;span class="na"&gt;moduleConfigs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
      &lt;span class="na"&gt;repoOwner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-modules&lt;/span&gt;
      &lt;span class="na"&gt;versionConstraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;21.10.1,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;21.13.0"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-azurerm-aks&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azurerm&lt;/span&gt;
      &lt;span class="na"&gt;repoOwner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure&lt;/span&gt;
      &lt;span class="na"&gt;versionConstraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10.0.0"&lt;/span&gt;
  &lt;span class="na"&gt;providerConfigs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
      &lt;span class="na"&gt;operatingSystems&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;darwin&lt;/span&gt;
      &lt;span class="na"&gt;architectures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;amd64&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arm64&lt;/span&gt;
      &lt;span class="na"&gt;versionConstraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5.80.0,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;6.0.0"&lt;/span&gt;
      &lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-registry&lt;/span&gt;
          &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
  &lt;span class="na"&gt;pollingIntervalMinutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Depot will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the &lt;code&gt;terraform-aws-modules/terraform-aws-eks&lt;/code&gt; and &lt;code&gt;azure/terraform-azurerm-aks&lt;/code&gt; GitHub repositories for releases&lt;/li&gt;
&lt;li&gt;Filter releases matching the version constraints and create &lt;code&gt;Module&lt;/code&gt; resources&lt;/li&gt;
&lt;li&gt;Query the HashiCorp Releases API for the &lt;code&gt;aws&lt;/code&gt; provider and create a &lt;code&gt;Provider&lt;/code&gt; resource for matching versions&lt;/li&gt;
&lt;li&gt;The Module and Provider controllers create &lt;code&gt;Version&lt;/code&gt; resources for each discovered version and OS/architecture&lt;/li&gt;
&lt;li&gt;The Version controller fetches archives from GitHub (modules) or HashiCorp (providers) and uploads them to the S3 bucket&lt;/li&gt;
&lt;li&gt;Re-check for new releases every 60 minutes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since your registry configuration is codified via the Depot, it now follows the same review process as other services in your stack!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Migrating from an existing registry:&lt;/strong&gt; The Depot is a very handy migration tool. Point it at your GitHub repos with a version constraint that covers your existing versions, let it ingest everything, then delete the Depot. Removing the Depot resource does &lt;strong&gt;not&lt;/strong&gt; delete any Modules or Providers — it's simply a centralized interface to ingest multiple artifacts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The CI/CD Workflow (Push-based)
&lt;/h2&gt;

&lt;p&gt;You also have the option for an entirely push-based CI/CD workflow:&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenDepot Manifest
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot.defdev.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Module&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;moduleConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-eks&lt;/span&gt;
    &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
    &lt;span class="na"&gt;repoOwner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-aws-modules&lt;/span&gt;
    &lt;span class="na"&gt;repoUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/terraform-aws-modules/terraform-aws-eks&lt;/span&gt;
    &lt;span class="na"&gt;fileFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zip&lt;/span&gt;
    &lt;span class="na"&gt;immutable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;storageConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;s3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-modules&lt;/span&gt;
        &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;
    &lt;span class="na"&gt;githubClientConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;useAuthenticatedClient&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.10.1"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.11.0"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.12.0"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;21.13.0"&lt;/span&gt;  &lt;span class="c1"&gt;# added in PR #42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub Actions Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish Module Version&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/opendepot-github-actions-role&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup kubeconfig&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws eks update-kubeconfig --name my-cluster --region us-west-2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish module version&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;kubectl apply -f "opendepot/terraform-aws-eks.yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Checksum Validation Every Reconcile
&lt;/h3&gt;

&lt;p&gt;Kubernetes operators constantly reconcile resources and act on changes to any resources they manage. When a module version is being added, all previous versions are also reconciled. To ensure OpenDepot is not re-downloading providers or modules every reconciliation loop, the Version resource stores a &lt;code&gt;status.checksum&lt;/code&gt; of each archive.&lt;/p&gt;

&lt;p&gt;If the checksum metadata in storage doesn't match this field, the controller first attempts to pull it from source and revalidate the checksum. If the checksum from source is still not a match, the controller stops reconciling and emits errors.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tamper protection:&lt;/strong&gt; The Server will not serve any modules whose checksums do not match. The Version controller continuously reconciles storage so that any tampered archive is re-fetched and restored to its known-good state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  GPG Keys
&lt;/h3&gt;

&lt;p&gt;OpenDepot supports GPG signing for providers. When serving provider binaries, the registry protocol requires that each binary is accompanied by a SHA256 checksum file and a GPG signature so that OpenTofu and Terraform can verify the integrity of what they download. Configure OpenDepot with your GPG key via a Kubernetes Secret referenced by &lt;code&gt;server.gpg.secretName&lt;/code&gt; in the Helm chart. Once set, the Server automatically signs provider checksum files on the fly with your private key. Clients that have your public key in their trust store can verify every provider binary they pull is untampered and came from your registry.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trivy Vulnerability Scans
&lt;/h3&gt;

&lt;p&gt;OpenDepot has the option to perform security scans using a separate Version controller image that comes bundled with Trivy. Trivy will perform a configuration scan of modules and store findings in the &lt;code&gt;module.status&lt;/code&gt; field. For providers, Trivy will scan the binary for each operating system and architecture, and OpenDepot will attempt to find and scan the source code, deduplicate findings, then store each in the &lt;code&gt;provider.status&lt;/code&gt; field.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Blocking policy:&lt;/strong&gt; You can configure OpenDepot to block &lt;code&gt;CRITICAL&lt;/code&gt; and &lt;code&gt;HIGH&lt;/code&gt; vulnerabilities to ensure that only modules and providers with a good security posture can be reconciled and stored in your registry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Dex OIDC Integration
&lt;/h3&gt;

&lt;p&gt;OpenDepot's Helm chart bundles &lt;a href="https://dexidp.io/" rel="noopener noreferrer"&gt;Dex&lt;/a&gt; as a subchart to handle OIDC authentication with an upstream IdP like Entra ID, GitHub, Okta, and many more. This is the recommended authentication method since it doesn't require cluster access or expose endpoints used to modify resources.&lt;/p&gt;

&lt;p&gt;With OIDC enabled you can leverage fine-grained access control through &lt;code&gt;GroupBinding&lt;/code&gt; custom resources. Use the &lt;a href="https://expr-lang.org/" rel="noopener noreferrer"&gt;Expr&lt;/a&gt; language to bind the &lt;code&gt;groups&lt;/code&gt; claim in a user's JWT to specific modules or providers. The &lt;code&gt;moduleResources&lt;/code&gt; field also supports glob patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot.defdev.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupBinding&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;01-aws-platform-team"&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opendepot-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;"aws-platform-team"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;groups'&lt;/span&gt;
  &lt;span class="na"&gt;moduleResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform-aws-*"&lt;/span&gt;
  &lt;span class="na"&gt;providerResources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aws"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Native &lt;code&gt;tofu login&lt;/code&gt; support:&lt;/strong&gt; OIDC with Dex is the &lt;strong&gt;only&lt;/strong&gt; method that supports the native &lt;code&gt;tofu login opendepot.defdev.io&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Other Authentication Methods
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes service account token&lt;/strong&gt; — Use Kubernetes RBAC permissions to control access per module or provider. Bypasses GroupBinding in favor of native Kubernetes RBAC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base64-encoded kubeconfig&lt;/strong&gt; — Convenient for local kind clusters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anonymous auth&lt;/strong&gt; — Enable via a single Helm chart flag to host a public registry. The Server's own Service Account is used for fetching, and clients don't need an access token.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kubeconfig - local use only:&lt;/strong&gt; A base64-encoded Kubernetes kubeconfig should &lt;strong&gt;never&lt;/strong&gt; be used in production. It is convenient for local &lt;code&gt;kind&lt;/code&gt; cluster testing only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fetching Artifacts
&lt;/h2&gt;

&lt;p&gt;The Server implements both the Module and Provider Registry protocols so that OpenTofu and Terraform can use OpenDepot as a drop-in registry. Crucially, the Server is &lt;strong&gt;completely read-only&lt;/strong&gt; — it provides no endpoints that allow modifications. All changes to resources require strict Kubernetes access.&lt;/p&gt;

&lt;p&gt;Reference your modules and providers in code, then run &lt;code&gt;tofu init&lt;/code&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Module
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"opendepot.defdev.io/opendepot-system/terraform-aws-key-pair/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 21.0.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Provider
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"opendepot.defdev.io/opendepot-system/aws"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 5.80"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;azurerm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"opendepot.defdev.io/opendepot-system/azurerm"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 4.0.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure your &lt;code&gt;.tofurc&lt;/code&gt; to point at OpenDepot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="s2"&gt;"opendepot.defdev.io"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;services&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"modules.v1"&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://opendepot.defdev.io/opendepot/modules/v1/"&lt;/span&gt;
    &lt;span class="s2"&gt;"providers.v1"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://opendepot.defdev.io/opendepot/providers/v1/"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Dex configured, the full &lt;code&gt;tofu login&lt;/code&gt; + &lt;code&gt;tofu init&lt;/code&gt; flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tofu login opendepot.defdev.io
$ tofu init

Initializing the backend...
Initializing modules...
Downloading opendepot.defdev.io/opendepot-system/terraform-aws-key-pair/aws 2.0.3 for key_pair...
- key_pair in .terraform/modules/key_pair

Initializing provider plugins...

OpenTofu has been successfully initialized!

You may now begin working with OpenTofu. Try running "tofu plan" to see
any changes that are required for your infrastructure. All OpenTofu commands
should now work.

If you ever set or change modules or backend configuration for OpenTofu,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all there is to it on the consuming side! It's simple and easy to get started with OpenDepot! I ask that you try it today and share your experiences. If you have any questions, see any issues, or just want to talk about Cloud Native tooling in general — feel free to reach out to me anytime!&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tonedefdev.github.io/opendepot/" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt; - Everything you need to get set up, configured, and running your own registry.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonedefdev.github.io/opendepot/getting-started/quickstart/" rel="noopener noreferrer"&gt;Local Quickstart&lt;/a&gt; - Run a fully functional registry on your laptop with kind in minutes, no cloud account needed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonedefdev.github.io/opendepot/getting-started/installation/" rel="noopener noreferrer"&gt;Installation Guide&lt;/a&gt; - Deploy OpenDepot to your cluster with Helm.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>terraform</category>
      <category>opensource</category>
      <category>go</category>
    </item>
  </channel>
</rss>
