{"id":51405298,"url":"https://github.com/lyuk98/opentofu-kubernetes","last_synced_at":"2026-07-04T10:31:43.259Z","repository":{"id":352411893,"uuid":"1158321187","full_name":"lyuk98/opentofu-kubernetes","owner":"lyuk98","description":"OpenTofu configurations (Kubernetes cluster)","archived":false,"fork":false,"pushed_at":"2026-04-19T12:20:42.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-19T14:27:14.460Z","etag":null,"topics":["helm","kubernetes","opentofu","talos-linux"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lyuk98.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-15T06:45:31.000Z","updated_at":"2026-04-19T12:20:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lyuk98/opentofu-kubernetes","commit_stats":null,"previous_names":["lyuk98/opentofu-kubernetes"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/lyuk98/opentofu-kubernetes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyuk98%2Fopentofu-kubernetes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyuk98%2Fopentofu-kubernetes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyuk98%2Fopentofu-kubernetes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyuk98%2Fopentofu-kubernetes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lyuk98","download_url":"https://codeload.github.com/lyuk98/opentofu-kubernetes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyuk98%2Fopentofu-kubernetes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35118970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["helm","kubernetes","opentofu","talos-linux"],"created_at":"2026-07-04T10:31:42.709Z","updated_at":"2026-07-04T10:31:43.248Z","avatar_url":"https://github.com/lyuk98.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenTofu configurations\n\nThis repository contains OpenTofu configuration for my personal Kubernetes cluster.\n\n## Providers used\n\n```mermaid\nflowchart RL\n  %% Resource/data source declaration\n\n  %% argocd.tf\n  kubernetes_namespace_v1.argocd\n  helm_release.argocd\n  helm_release.argocd_project\n  helm_release.argocd_application\n\n  %% cert-manager.tf\n  kubernetes_namespace_v1.cert_manager\n  helm_release.cert_manager\n  helm_release.argocd_cert_manager\n\n  %% cilium.tf\n  data.kustomization_build.gateway_api([data.kustomization_build.gateway_api])\n  kustomization_resource.gateway_api_p0\n  kustomization_resource.gateway_api_p1\n  kustomization_resource.gateway_api_p2\n  helm_release.cilium\n\n  %% cloudflare.tf\n  data.cloudflare_zone.default([data.cloudflare_zone.default])\n  time_sleep.dns_ready\n  terraform_data.dns_ready\n  cloudflare_dns_record.xps13_a\n  cloudflare_dns_record.xps13_aaaa\n\n  %% external-dns.tf\n  kubernetes_namespace_v1.external_dns\n  kubernetes_secret_v1.cloudflare_api_token\n  helm_release.external_dns\n\n  %% tailscale.tf\n  kubernetes_namespace_v1.tailscale\n  helm_release.tailscale_operator\n  helm_release.argocd_tailscale\n  tailscale_oauth_client.kubernetes_operator\n\n  %% talos-controlplane.tf\n  data.talos_machine_configuration.controlplane([data.talos_machine_configuration.controlplane])\n\n  %% talos-xps13.tf\n  talos_machine_configuration_apply.xps13\n  talos_machine_bootstrap.xps13\n  random_password.talos_encryption_passphrase_xps13\n  talos_image_factory_schematic.xps13\n  data.talos_image_factory_urls.xps13([data.talos_image_factory_urls.xps13])\n  tailscale_oauth_client.xps13\n  data.tailscale_device.xps13([data.tailscale_device.xps13])\n\n  %% talos.tf\n  talos_machine_secrets.kubernetes\n  data.talos_client_configuration.kubernetes([data.talos_client_configuration.kubernetes])\n  talos_cluster_kubeconfig.kubernetes\n  local_sensitive_file.talosconfig\n  local_sensitive_file.kubeconfig\n\n  %% Relation declaration\n\n  %% argocd.tf\n  helm_release.argocd-- depends_on --\u003ekubernetes_namespace_v1.argocd\n  helm_release.argocd-- depends_on --\u003ehelm_release.cilium\n  helm_release.argocd-- name --\u003edata.cloudflare_zone.default\n  helm_release.argocd_project-- depends_on --\u003ekubernetes_namespace_v1.cert_manager\n  helm_release.argocd_project-- depends_on --\u003ekubernetes_namespace_v1.tailscale\n  helm_release.argocd_project-- depends_on --\u003ehelm_release.argocd\n  helm_release.argocd_application-- depends_on --\u003ehelm_release.argocd_tailscale\n  helm_release.argocd_application-- name --\u003edata.cloudflare_zone.default\n\n  %% cert-manager.tf\n  helm_release.cert_manager-- depends_on --\u003ekubernetes_namespace_v1.cert_manager\n  helm_release.cert_manager-- depends_on --\u003ehelm_release.cilium\n  helm_release.argocd_cert_manager-- depends_on --\u003ehelm_release.argocd_project\n  helm_release.argocd_cert_manager-- depends_on --\u003ekubernetes_secret_v1.cloudflare_api_token\n\n  %% cilium.tf\n  kustomization_resource.gateway_api_p0-- ids_prio --\u003edata.kustomization_build.gateway_api\n  kustomization_resource.gateway_api_p1-- depends_on --\u003ekustomization_resource.gateway_api_p0\n  kustomization_resource.gateway_api_p1-- ids_prio --\u003edata.kustomization_build.gateway_api\n  kustomization_resource.gateway_api_p2-- depends_on --\u003ekustomization_resource.gateway_api_p1\n  kustomization_resource.gateway_api_p2-- ids_prio --\u003edata.kustomization_build.gateway_api\n  helm_release.cilium-- depends_on --\u003ekustomization_resource.gateway_api_p2\n\n  %% cloudflare.tf\n  time_sleep.dns_ready-- content --\u003ecloudflare_dns_record.xps13_a\n  time_sleep.dns_ready-- content --\u003ecloudflare_dns_record.xps13_aaaa\n  terraform_data.dns_ready-- triggers_replace --\u003etime_sleep.dns_ready\n  terraform_data.dns_ready-- name --\u003edata.cloudflare_zone.default\n  terraform_data.dns_ready-- triggers --\u003etime_sleep.dns_ready\n  cloudflare_dns_record.xps13_a-- addresses --\u003edata.tailscale_device.xps13\n  cloudflare_dns_record.xps13_aaaa-- addresses --\u003edata.tailscale_device.xps13\n\n  %% external-dns.tf\n  kubernetes_secret_v1.cloudflare_api_token-- depends_on --\u003ekubernetes_namespace_v1.cert_manager\n  kubernetes_secret_v1.cloudflare_api_token-- depends_on --\u003ekubernetes_namespace_v1.external_dns\n  helm_release.external_dns-- depends_on --\u003ekubernetes_secret_v1.cloudflare_api_token\n  helm_release.external_dns-- depends_on --\u003ehelm_release.cilium\n  helm_release.external_dns-- name --\u003edata.cloudflare_zone.default\n\n  %% tailscale.tf\n  helm_release.tailscale_operator-- depends_on --\u003ekubernetes_namespace_v1.tailscale\n  helm_release.tailscale_operator-- depends_on --\u003ehelm_release.cilium\n  helm_release.tailscale_operator-- id --\u003etailscale_oauth_client.kubernetes_operator\n  helm_release.tailscale_operator-- key --\u003etailscale_oauth_client.kubernetes_operator\n  helm_release.argocd_tailscale-- depends_on --\u003ehelm_release.argocd_cert_manager\n  helm_release.argocd_tailscale-- depends_on --\u003ehelm_release.tailscale_operator\n  helm_release.argocd_tailscale-- depends_on --\u003ehelm_release.external_dns\n  helm_release.argocd_tailscale-- name --\u003edata.cloudflare_zone.default\n\n  %% talos-controlplane.tf\n  data.talos_machine_configuration.controlplane-- name --\u003edata.cloudflare_zone.default\n  data.talos_machine_configuration.controlplane-- machine_secrets --\u003etalos_machine_secrets.kubernetes\n\n  %% talos-xps13.tf\n  talos_machine_configuration_apply.xps13-- client_configuration --\u003etalos_machine_secrets.kubernetes\n  talos_machine_configuration_apply.xps13-- machine_configuration --\u003edata.talos_machine_configuration.controlplane\n  talos_machine_configuration_apply.xps13-- urls --\u003edata.talos_image_factory_urls.xps13\n  talos_machine_configuration_apply.xps13-- key --\u003etailscale_oauth_client.xps13\n  talos_machine_configuration_apply.xps13-- tags --\u003etailscale_oauth_client.xps13\n  talos_machine_configuration_apply.xps13-- result --\u003erandom_password.talos_encryption_passphrase_xps13\n  talos_machine_bootstrap.xps13-- depends_on --\u003edata.tailscale_device.xps13\n  talos_machine_bootstrap.xps13-- replace_triggered_by --\u003etalos_machine_configuration_apply.xps13\n  talos_machine_bootstrap.xps13-- client_configuration --\u003etalos_machine_secrets.kubernetes\n  data.talos_image_factory_urls.xps13-- id --\u003etalos_image_factory_schematic.xps13\n  tailscale_device.xps13-- depends_on --\u003etalos_machine_configuration_apply.xps13\n\n  %% talos.tf\n  data.talos_client_configuration.kubernetes-- client_configuration --\u003etalos_machine_secrets.kubernetes\n  data.talos_client_configuration.kubernetes-- content --\u003ecloudflare_dns_record.xps13_a\n  talos_cluster_kubeconfig.kubernetes-- depends_on --\u003eterraform_data.dns_ready\n  talos_cluster_kubeconfig.kubernetes-- replace_triggered_by --\u003etalos_machine_secrets.kubernetes\n  talos_cluster_kubeconfig.kubernetes-- client_configuration --\u003etalos_machine_secrets.kubernetes\n  talos_cluster_kubeconfig.kubernetes-- content --\u003ecloudflare_dns_record.xps13_a\n  local_sensitive_file.talosconfig-- talos_config --\u003edata.talos_client_configuration.kubernetes\n  local_sensitive_file.kubeconfig-- kubeconfig_raw --\u003etalos_cluster_kubeconfig.kubernetes\n```\n\n### Talos Linux\n\n- Machine secrets for the cluster (`talos_machine_secrets`)\n- Machine configuration for nodes (`talos_machine_configuration`)\n- Schematic from [Image Factory](https://factory.talos.dev/) (`talos_image_factory_schematic`)\n- Generated password for disk encryption (`random_password`)\n- Installation and bootstrapping of nodes (`talos_machine_configuration_apply` and `talos_machine_bootstrap`)\n- `kubeconfig` generated by Talos Linux (`talos_cluster_kubeconfig`)\n\n### Tailscale\n\n- Trust credentials for nodes and [Tailscale Kubernetes Operator](https://tailscale.com/docs/features/kubernetes-operator) (`tailscale_oauth_client`)\n\n### Cloudflare\n\n- `A` and `AAAA` records for control plane nodes (`cloudflare_dns_record`)\n- Delayed creation of resource to wait for DNS propagation (`time_sleep`)\n- Execution of [Python script](./scripts/check_dns.py) to check for DNS propagation (`terraform_data` with `local-exec`)\n\n### Kubernetes\n\n- Namespace declaration (`kubernetes_namespace_v1`)\n- Secret provisioning (`kubernetes_secret_v1`)\n\n### Kustomize\n\n- Kustomization resource application (`kustomization_resource`)\n\n### Helm\n\n- Helm charts for: (`helm_release`)\n  - [Cilium](https://cilium.io/)\n  - [Tailscale Kubernetes Operator](https://tailscale.com/docs/features/kubernetes-operator)\n  - [cert-manager](https://cert-manager.io/ \"cert-manager\")\n  - [ExternalDNS](https://kubernetes-sigs.github.io/external-dns/ \"external-dns\")\n  - [Argo CD](https://argoproj.github.io/cd/ \"Argo CD | Argo\") and its applications\n\n## Applying the configuration\n\nOpenTofu is required due to the usage of [state and plan encryption](https://opentofu.org/docs/language/state/encryption/); using Terraform without it may work, but it has not been tested. Python 3 is also required for local script execution.\n\nIf the system uses [Nix](https://nixos.org/), running the following command, at the root directory of the cloned project, starts an interactive shell with required packages:\n\n```sh\nnix-shell --pure\n```\n\n### Environment variables\n\nThis configuration assumes that some environment variables are set prior to the following steps.\n\n#### `s3` backend\n\nBackblaze B2 is used for storing the state.\n\n- `AWS_SECRET_ACCESS_KEY`: the application key to access the bucket with. The following capabilities are required: `deleteFiles`, `listBuckets`, `listFiles`, `readFiles`, and `writeFiles`\n- `AWS_ACCESS_KEY_ID`: the ID of the abovementioned application key\n- `AWS_ENDPOINT_URL_S3`: S3 API endpoint, such as `https://s3.us-west-002.backblazeb2.com`\n\n#### `tailscale` provider\n\n- `TAILSCALE_OAUTH_CLIENT_SECRET`: the OAuth client used for deployment; this setup assumes that the scopes `devices:core`, `auth_keys`, `oauth_keys`, and `services` are assigned with tags either:\n  - `tag:k8s-operator` and `tag:k8s-control-plane` themselves, or\n  - one that owns the above\n- `TAILSCALE_OAUTH_CLIENT_ID`: the ID of the abovementioned OAuth client\n\n### Input variables\n\nAccepted input variables are defined at [`variables.tf`](./variables.tf). The following do not have default values and thus need to be manually set:\n\n- `state_passphrase`: the passphrase used for encrypting and decrypting state and plan data\n- `cloudflare_zone_id`: Cloudflare zone ID\n- `cloudflare_api_token`: Cloudflare API token with permissions to edit zone DNS\n- `acme_email`: Email for ACME ClusterIssuer configuration\n\n### Backend configuration\n\nDuring initialisation, the name of the bucket for storing the state needs to be provided. It can be done interactively, or by manually providing the configuration.\n\n```sh\n# Initialise backend interactively\ntofu init\n\n# Initialise backend with configuration\ntofu init -backend-config=\"bucket=\u003cbucket-name\u003e\"\n```\n\n### `plan` and `apply`\n\nWhen the backend is ready, run the following to apply the configuration:\n\n```sh\ntofu plan -out=tfplan\ntofu apply tfplan\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyuk98%2Fopentofu-kubernetes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flyuk98%2Fopentofu-kubernetes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyuk98%2Fopentofu-kubernetes/lists"}