diff --git a/k8s/argocd/apps/0-minio.yaml b/k8s/argocd/apps/0-minio.yaml index 7b33729..3bd650c 100644 --- a/k8s/argocd/apps/0-minio.yaml +++ b/k8s/argocd/apps/0-minio.yaml @@ -1,28 +1,5 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: minio - namespace: argocd - annotations: - argocd.argoproj.io/sync-wave: "0" -spec: - project: homelab - source: - repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git - targetRevision: main - path: k8s/storage - directory: - recurse: false - destination: - server: https://kubernetes.default.svc - namespace: storage - syncPolicy: - automated: - prune: true - selfHeal: true - syncOptions: - - CreateNamespace=true ---- +# MinIO now managed by Terraform (terraform/minio.tf) via official minio/minio +# chart — removed from ArgoCD to avoid dual-controller conflict on storage NS. apiVersion: argoproj.io/v1alpha1 kind: Application metadata: diff --git a/terraform/argocd-bootstrap.tf b/terraform/argocd-bootstrap.tf index c472b14..b899175 100644 --- a/terraform/argocd-bootstrap.tf +++ b/terraform/argocd-bootstrap.tf @@ -8,6 +8,22 @@ resource "kubernetes_namespace" "argocd" { } } +# Copy homelab-ca-secret from cert-manager to argocd namespace +# (Required for repo-server pod to verify self-signed forgejo TLS) +resource "null_resource" "copy_ca_secret_to_argocd" { + provisioner "local-exec" { + command = <<-EOT + kubectl get secret homelab-ca-secret -n cert-manager -o yaml | \ + sed 's/namespace: cert-manager/namespace: argocd/' | \ + kubectl apply -f - + EOT + } + + depends_on = [ + kubernetes_namespace.argocd + ] +} + resource "helm_release" "argocd" { name = "argocd" repository = local.helm_repos["argo"] @@ -37,6 +53,14 @@ resource "helm_release" "argocd" { hosts = [ "argocd.${var.cluster_domain}" ] + annotations = { + "nginx.ingress.kubernetes.io/backend-protocol" = "HTTPS" + } + ingressClassName = "nginx" + } + service = { + type = "ClusterIP" + port = 80 } } repoServer = { @@ -44,6 +68,12 @@ resource "helm_release" "argocd" { enabled = true minReplicas = 2 } + env = [ + { + name = "GIT_SSL_CAINFO" + value = "/etc/ssl/certs/homelab-ca.crt" + } + ] volumes = [ { name = "homelab-ca" @@ -67,14 +97,12 @@ resource "helm_release" "argocd" { ] depends_on = [ - kubernetes_namespace.argocd + kubernetes_namespace.argocd, + null_resource.copy_ca_secret_to_argocd ] - lifecycle { - ignore_changes = [ - values - ] - } + # Note: lifecycle.ignore_changes removed to allow CA cert update + # This allows TF to inject the homelab-ca-secret for TLS verification } resource "kubernetes_manifest" "argocd_project" { diff --git a/terraform/bootstrap-certificates.tf b/terraform/bootstrap-certificates.tf deleted file mode 100644 index f6cbaa0..0000000 --- a/terraform/bootstrap-certificates.tf +++ /dev/null @@ -1,104 +0,0 @@ -resource "kubernetes_manifest" "selfsigned_bootstrap" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "ClusterIssuer" - metadata = { - name = "selfsigned-bootstrap" - } - spec = { - selfSigned = {} - } - } - - field_manager { - name = "terraform" - } -} - -resource "kubernetes_manifest" "homelab_ca_cert" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "Certificate" - metadata = { - name = "homelab-ca" - namespace = kubernetes_namespace.namespaces["cert-manager"].metadata[0].name - } - spec = { - secretName = "homelab-ca-secret" - commonName = "homelab-ca" - isCA = true - issuerRef = { - name = "selfsigned-bootstrap" - kind = "ClusterIssuer" - } - duration = "87600h" - renewBefore = "720h" - privateKey = { - algorithm = "ECDSA" - size = 256 - } - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.selfsigned_bootstrap - ] -} - -resource "kubernetes_manifest" "homelab_ca_issuer" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "ClusterIssuer" - metadata = { - name = "homelab-ca" - } - spec = { - ca = { - secretName = "homelab-ca-secret" - } - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.homelab_ca_cert - ] -} - -resource "kubernetes_manifest" "wildcard_cert" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "Certificate" - metadata = { - name = "homelab-tls" - namespace = kubernetes_namespace.namespaces["ingress-nginx"].metadata[0].name - } - spec = { - secretName = "homelab-tls" - commonName = "*.${var.cluster_domain}" - dnsNames = ["*.${var.cluster_domain}"] - issuerRef = { - name = "homelab-ca" - kind = "ClusterIssuer" - } - duration = "2160h" - renewBefore = "720h" - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.homelab_ca_issuer, - kubernetes_namespace.namespaces - ] -} diff --git a/terraform/minio.tf b/terraform/minio.tf new file mode 100644 index 0000000..e16046e --- /dev/null +++ b/terraform/minio.tf @@ -0,0 +1,90 @@ +# MinIO - Official minio/minio chart, direct Helm deployment (no operator) +# All-in-one: single helm_release + dedicated xfs StorageClass. +# Why xfs: default `longhorn` SC uses ext4 whose mkfs on 100Gi (~4.5min) +# exceeds kubelet mount timeout. xfs mkfs is near-instant. min.io chart has +# no persistence.fsType, so fsType must be set on the StorageClass. + +resource "kubernetes_storage_class" "longhorn_xfs" { + metadata { + name = "longhorn-xfs" + } + storage_provisioner = "driver.longhorn.io" + reclaim_policy = "Delete" + allow_volume_expansion = true + volume_binding_mode = "Immediate" + + parameters = { + numberOfReplicas = "2" + staleReplicaTimeout = "60" + fsType = "xfs" + dataLocality = "disabled" + } +} + +resource "helm_release" "minio" { + name = "minio" + repository = "https://charts.min.io/" + chart = "minio" + version = "5.4.0" + namespace = "storage" + upgrade_install = true + force_update = true + wait = true + timeout = 600 + + values = [ + yamlencode({ + mode = "standalone" + replicas = 1 + drivesPerNode = 1 + pools = 1 + + rootUser = "minioadmin" + rootPassword = var.minio_root_password + + persistence = { + enabled = true + size = "100Gi" + storageClass = kubernetes_storage_class.longhorn_xfs.metadata[0].name + accessMode = "ReadWriteOnce" + } + + resources = { + requests = { + memory = "512Mi" + } + } + + service = { + type = "ClusterIP" + port = "9000" + } + consoleService = { + type = "ClusterIP" + port = "9001" + } + + # Buckets auto-created on install (all-in-one, no post-hook needed) + buckets = [ + { name = "vault", policy = "none", purge = false }, + { name = "riotpiao-models", policy = "none", purge = false }, + ] + + environment = { + MINIO_IDENTITY_OPENID_CONFIG_URL = "https://authentik.riotpiao.homelab.com/application/o/minio/.well-known/openid-configuration" + MINIO_IDENTITY_OPENID_CLIENT_ID = "minio" + MINIO_IDENTITY_OPENID_CLIENT_SECRET = var.minio_oidc_client_secret + MINIO_IDENTITY_OPENID_CLAIM_NAME = "policy" + MINIO_IDENTITY_OPENID_SCOPES = "openid,profile,email,minio" + MINIO_IDENTITY_OPENID_REDIRECT_URI = "https://minio.riotpiao.homelab.com/oauth_callback" + MINIO_IDENTITY_OPENID_DISPLAY_NAME = "Authentik" + } + }) + ] +} + +variable "create_storage_namespace" { + description = "Create storage namespace if it doesn't exist" + type = bool + default = false +}