Skip to content
The last release, 0.1.0, predates this site: this is the documentation of main.

Overview

The socle turns one OpenTofu file into a managed Kubernetes cluster running a chosen set of platform modules, and keeps it converged. In one apply, OpenTofu creates the cluster and hands it its inputs; Flux, through the Flux Operator, then pulls a signed artifact and renders the catalog from them.

main.tf ──▶ tofu apply ──▶ foundations: network, cluster, nodes, identities
└──▶ bootstrap: [Cilium, CoreDNS, EKS add-ons], flux-operator,
flux-instance, envelope (inputs + socle-root)
│
ghcr.io/do-now-io/socle/flux-modules ───verified pull──▶ Flux ──▶ clusters/<cloud>
└▶ one ResourceSet per module
LayerWhat it isCodeOwned by
FoundationsOne module per cloud: network, cluster, the nodes the socle starts on, identitiesopentofu/aws, gcp, azure, scalewayOpenTofu
BootstrapCilium and CoreDNS where the cloud has none, the EKS add-ons, the Flux Operator and instance, the envelope of inputsopentofu/bootstrapOpenTofu, same apply
RootThe one apply: calls both, configures the providersopentofu/clusters/aws, gcpthe socle; your main.tf calls it
CatalogOne ResourceSet per module, one overlay per cloudoci/Flux, from the signed artifact
  • Your configuration lives in your Git, as OpenTofu: socle_version, <cloud> = {…}, kube = {…} (and cilium, coredns, eks_addons where they apply). Flux never syncs from your repository.
  • OpenTofu ships inputs only, through helm_release as an applier; the Flux Operator templates (The Flux catalog).
  • One apply, foundations and bootstrap in the same root. Two cases need more: When one apply is not enough.
  • socle_version pins both the module sources and the artifact tag (Distribution).
  • The signature is always checked by Flux, on every reconciliation.
  • A module carries its own cloud access, never the foundations (Module IAM).

After the apply, the cluster pulls the artifact every minute, verifies it, and each ResourceSet renders its module, or nothing when it is off. A change of kube is re-rendered within seconds of its apply.

Each foundations module outputs helm_kubernetes, so the root’s provider is one line on every cloud:

provider "helm" {
kubernetes = module.foundations.helm_kubernetes
}

It holds no token: an exec plugin gets a short-lived one from the runner’s ambient credentials.

Under the hood

The object is { host, cluster_ca_certificate, exec = { api_version, command, args } }.

CloudExecState
AWSaws eks get-token --cluster-name …works; the root applies with it on floci
GCPgke-gcloud-auth-plugin, host is the DNS endpointworks; the gcp root applies with it
Azurekubelogin get-token --login azurecli --server-id 6dae42f8-4368-4678-94ff-3960e28e3630needs Entra ID authentication, which opentofu/azure does not configure yet
Scalewaysh -c emitting an ExecCredential from SCW_SECRET_KEYoutput exists; no Scaleway root yet

No kubernetes provider exists in the chain. On aws the bootstrap does not depends_on the whole foundations module: Cilium follows the cluster alone (the nodes become Ready only once it runs), and everything else follows the node group through schedulable_nodes (Cilium before Flux).