## HashiCorp Vault with Banzaicloud Vault Operator
## HA Vault кластер с Kubernetes auto-unseal

# Include common variables and functions
include common/Makefile

# Vault configuration
# Using common namespace variables from common/Makefile
HELMFILE_OPERATOR := vault/helmfile-operator.yaml

.PHONY: vault-help
vault-help:
	@echo ""
	@echo "$(COLOR_BOLD)HashiCorp Vault Commands:$(COLOR_RESET)"
	@echo "  make vault-install-operator   - Install Bank-Vaults Vault Operator"
	@echo "  make vault-update-operator    - Update Bank-Vaults Vault Operator"
	@echo "  make vault-uninstall-operator - Uninstall operator (keeps instances)"
	@echo "  make vault-create-rbac        - Create RBAC resources for Vault"
	@echo "  make vault-create-instance    - Create HA Vault instance (vault-tech)"
	@echo "  make vault-update-instance    - Update Vault instance configuration"
	@echo "  make vault-delete-instance    - Delete Vault instance (keeps operator)"
	@echo "  make vault-status             - Check Vault operator and instance status"
	@echo "  make vault-unseal-keys        - Display root token and unseal keys"
	@echo "  make vault-label-namespace    - Label namespace for secret injection (use NS=name)"
	@echo "  make vault-raft-peers         - List Raft cluster peers"
	@echo "  make vault-recreate           - Delete and recreate Vault instance (clean install)"
	@echo "  make vault-uninstall          - Uninstall Vault operator and instances"
	@echo "  make vault-configure          - Configure policies and auth methods"
	@echo "  make vault-sync-envs          - Sync environment variables from JSON files to Vault"
	@echo "  make vault-sync-policies      - Sync policies and Kubernetes auth roles to Vault"
	@echo ""
	@echo "$(COLOR_YELLOW)Note:$(COLOR_RESET) Before installing, prepare nodes:"
	@echo "  cd ../.. && make k8s-prepare-nodes"

.PHONY: vault-install-operator
vault-install-operator: install-namespaces
	$(call print_info,Creating Vault namespaces...)
	@$(KUBECTL) apply -f vault/manifests/tech-vault-operator.yaml
	@$(KUBECTL) apply -f vault/manifests/tech-vault-instances.yaml
	$(call print_info,Applying Vault resource policies...)
	@$(KUBECTL) apply -f vault/manifests/limitrange.yaml
	@$(KUBECTL) apply -f vault/manifests/resourcequota.yaml
	@$(KUBECTL) apply -f vault/manifests/vault/vault-networkpolicy.yaml
	$(call print_info,Installing Bank-Vaults Vault Operator from OCI registry via helmfile...)
ifeq ($(DETECTED_OS),Windows)
	@powershell -NoProfile -Command "$$curDir = [System.IO.Directory]::GetCurrentDirectory(); $$kubeconfig = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, '$(KUBECONFIG_REL)')); $$helmfilePath = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, 'vault', 'helmfile-operator.yaml')); Write-Host 'Using helmfile: ' $$helmfilePath; if (-not (Test-Path $$helmfilePath)) { Write-Host 'Error: Helmfile not found at: ' $$helmfilePath; exit 1 }; $$content = Get-Content $$helmfilePath -Raw; if ($$content -notmatch 'vault-operator') { Write-Host 'Error: Wrong helmfile content! Expected vault-operator but found:'; Get-Content $$helmfilePath | Select-Object -First 3; exit 1 }; $$env:KUBECONFIG = $$kubeconfig; helmfile -f \"$$helmfilePath\" sync"
else
	$(call run_helmfile,$(HELMFILE_OPERATOR),sync)
endif
	$(call print_info,Waiting for operator and webhook to be ready...)
	@$(KUBECTL) -n $(VAULT_OPERATOR_NAMESPACE) rollout status deployment/vault-operator --timeout=3m || true
	@$(KUBECTL) -n $(VAULT_OPERATOR_NAMESPACE) rollout status deployment/vault-secrets-webhook --timeout=3m || true
	$(call print_success,Vault Operator and Webhook installed!)

.PHONY: vault-update-operator
vault-update-operator:
	$(call print_info,Updating Bank-Vaults Vault Operator via helmfile...)
ifeq ($(DETECTED_OS),Windows)
	@powershell -NoProfile -Command "$$curDir = [System.IO.Directory]::GetCurrentDirectory(); $$kubeconfig = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, '$(KUBECONFIG_REL)')); $$helmfilePath = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, 'vault', 'helmfile-operator.yaml')); if (-not (Test-Path $$helmfilePath)) { Write-Host 'Error: Helmfile not found at: ' $$helmfilePath; exit 1 }; $$env:KUBECONFIG = $$kubeconfig; helmfile -f \"$$helmfilePath\" sync"
else
	$(call run_helmfile,$(HELMFILE_OPERATOR),sync)
endif
	$(call print_info,Updating Vault resource policies...)
	@$(KUBECTL) apply -f vault/manifests/limitrange.yaml
	@$(KUBECTL) apply -f vault/manifests/resourcequota.yaml
	@$(KUBECTL) apply -f vault/manifests/vault/vault-networkpolicy.yaml
	$(call print_info,Waiting for operator and webhook to be ready...)
	@$(KUBECTL) -n $(VAULT_OPERATOR_NAMESPACE) rollout status deployment/vault-operator --timeout=3m || true
	@$(KUBECTL) -n $(VAULT_OPERATOR_NAMESPACE) rollout status deployment/vault-secrets-webhook --timeout=3m || true
	$(call print_success,Vault Operator and Webhook updated!)

.PHONY: vault-uninstall-operator
vault-uninstall-operator:
	$(call print_warning,This will uninstall Vault Operator!)
	@echo "Note: Vault instances will NOT be deleted."
	@echo "Press Ctrl+C to cancel, or wait 10 seconds to continue..."
	$(call sleep_seconds,10)
	$(call print_info,Uninstalling operator...)
ifeq ($(DETECTED_OS),Windows)
	-@$(call run_helmfile,$(HELMFILE_OPERATOR),destroy) 2>nul || echo "Operator may already be uninstalled"
else
	-@$(call run_helmfile,$(HELMFILE_OPERATOR),destroy) || true
endif
	$(call print_success,Operator uninstalled. Instances remain.)

.PHONY: vault-create-rbac
vault-create-rbac:
	$(call print_info,Creating RBAC resources for Vault...)
	@$(KUBECTL) apply -f vault/manifests/vault/vault-rbac.yaml
	$(call print_success,RBAC resources created!)

.PHONY: vault-create-instance
vault-create-instance: vault-create-rbac
	$(call print_info,Applying Vault resource policies...)
	@$(KUBECTL) apply -f vault/manifests/default-deny-networkpolicy.yaml
	@$(KUBECTL) apply -f vault/manifests/limitrange.yaml
	@$(KUBECTL) apply -f vault/manifests/resourcequota.yaml
	$(call print_info,Creating StorageClass for Vault...)
	@$(KUBECTL) apply -f vault/manifests/storageclass.yaml
	$(call print_info,Applying Vault network policies...)
	@$(KUBECTL) apply -f vault/manifests/vault/vault-networkpolicy.yaml
	$(call print_info,Creating security resources...)
	@$(KUBECTL) apply -f vault/manifests/vault/vault-pdb.yaml
	$(call print_info,Creating Vault instance vault-tech...)
	@$(KUBECTL) apply -f vault/manifests/vault/vault-tech.yaml
	@echo ""
	@echo "$(COLOR_YELLOW)Waiting for Vault pods to be ready (this may take 2-3 minutes)...$(COLOR_RESET)"
	$(call sleep_seconds,60)
	@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) get pods -l app.kubernetes.io/name=vault -o wide || true
	@echo ""
	@echo "$(COLOR_YELLOW)Vault is using Kubernetes auto-unseal. No manual unsealing required.$(COLOR_RESET)"
	$(call print_success,Vault instance created!)

.PHONY: vault-update-instance
vault-update-instance:
	$(call print_info,Updating Vault resource policies...)
	@$(KUBECTL) apply -f vault/manifests/default-deny-networkpolicy.yaml
	@$(KUBECTL) apply -f vault/manifests/limitrange.yaml
	@$(KUBECTL) apply -f vault/manifests/resourcequota.yaml
	$(call print_info,Updating Vault instance vault-tech...)
	@$(KUBECTL) apply -f vault/manifests/vault/vault-tech.yaml
	@echo ""
	@echo "$(COLOR_YELLOW)Waiting for Vault pods to be ready (this may take 2-3 minutes)...$(COLOR_RESET)"
	$(call sleep_seconds,60)
	@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) get pods -l app.kubernetes.io/name=vault -o wide || true
	$(call print_success,Vault instance updated!)

.PHONY: vault-delete-instance
vault-delete-instance:
	$(call print_warning,This will delete the Vault instance and its data!)
	@echo "Press Ctrl+C to cancel, or wait 10 seconds to continue..."
	$(call sleep_seconds,10)
	$(call print_info,Deleting Vault instance...)
	-@$(KUBECTL) delete vaults.vault.banzaicloud.com --all -n $(VAULT_INSTANCES_NAMESPACE) || true
	$(call print_info,Deleting Vault secrets and PVCs...)
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete secret vault-unseal-keys || true
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete pvc -l app.kubernetes.io/name=vault || true
	$(call print_success,Vault instance deleted!)

.PHONY: vault-status
vault-status:
	@echo ""
	@echo "$(COLOR_BOLD)=== Vault Operator Status ===$(COLOR_RESET)"
	@$(KUBECTL) -n $(VAULT_OPERATOR_NAMESPACE) get pods,svc
	@echo ""
	@echo "$(COLOR_BOLD)=== Vault Instances ===$(COLOR_RESET)"
	@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) get vaults.vault.banzaicloud.com || echo "No vaults found"
	@echo ""
	@echo "$(COLOR_BOLD)=== vault-prod Pods ===$(COLOR_RESET)"
	@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) get pods -l app.kubernetes.io/name=vault -o wide || echo "Vault instance not created yet"
	@echo ""
	@echo "$(COLOR_BOLD)=== vault-prod Services ===$(COLOR_RESET)"
	@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) get svc -l app.kubernetes.io/name=vault || true
	@echo ""

.PHONY: vault-unseal-keys
vault-unseal-keys:
	@echo ""
	@echo "$(COLOR_BOLD)=== Vault Root Token and Unseal Keys ===$(COLOR_RESET)"
	@echo ""
	@echo "$(COLOR_YELLOW)Root token (use with caution):$(COLOR_RESET)"
ifeq ($(DETECTED_OS),Windows)
	@powershell -NoProfile -Command "$$curDir = [System.IO.Directory]::GetCurrentDirectory(); $$kubeconfig = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, '$(KUBECONFIG_REL)')); $$env:KUBECONFIG = $$kubeconfig; $$secret = kubectl -n $(VAULT_INSTANCES_NAMESPACE) get secret vault-unseal-keys -o jsonpath='{.data.vault-root}' 2>$$null; if ($$secret) { $$bytes = [Convert]::FromBase64String($$secret); [System.Text.Encoding]::UTF8.GetString($$bytes) } else { Write-Host 'Secret not found yet - Vault may still be initializing'; exit 0 }"
else
	@bash scripts/vault-get-root-token.sh $(VAULT_INSTANCES_NAMESPACE) $(KUBECONFIG) || \
		($(call print_warning,Secret not found yet - Vault may still be initializing) && exit 0)
endif
	@echo ""
	@echo ""
	@echo "$(COLOR_YELLOW)Note:$(COLOR_RESET) Vault uses Kubernetes auto-unseal."
	@echo "Unseal keys are stored in secret: vault-unseal-keys"
	@echo ""
	@echo "$(COLOR_YELLOW)To view all keys:$(COLOR_RESET)"
	@echo "  kubectl --kubeconfig=../../kubeconfig -n $(VAULT_INSTANCES_NAMESPACE) get secret vault-unseal-keys -o yaml"
	@echo ""

.PHONY: vault-label-namespace
vault-label-namespace:
	$(if $(NS),,$(error NS is not set. Usage: make vault-label-namespace NS=my-namespace))
	$(call print_info,Labeling namespace $(NS) for Vault injection...)
	@$(KUBECTL) label namespace $(NS) vault-injection=enabled --overwrite
	$(call print_success,Namespace $(NS) labeled!)

.PHONY: vault-raft-peers
vault-raft-peers:
	@echo ""
	@echo "$(COLOR_BOLD)=== Vault Raft Cluster Peers ===$(COLOR_RESET)"
	@echo ""
ifeq ($(DETECTED_OS),Windows)
	@powershell -NoProfile -Command "$$curDir = [System.IO.Directory]::GetCurrentDirectory(); $$kubeconfig = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($$curDir, '$(KUBECONFIG_REL)')); $$env:KUBECONFIG = $$kubeconfig; Write-Host 'Getting Vault pods...'; $$podsJson = kubectl -n $(VAULT_INSTANCES_NAMESPACE) get pods -l app.kubernetes.io/name=vault -o json 2>$$null | ConvertFrom-Json; if (-not $$podsJson -or $$podsJson.items.Count -eq 0) { Write-Host 'No Vault pods found'; exit 1 }; Write-Host ''; Write-Host 'Vault Raft Cluster Peers:'; Write-Host '=========================='; Write-Host ''; foreach ($$pod in $$podsJson.items) { Write-Host \"Pod: $$($$pod.metadata.name)\"; Write-Host '---'; kubectl -n $(VAULT_INSTANCES_NAMESPACE) exec $$($$pod.metadata.name) -- vault operator raft list-peers 2>$$null; if ($$LASTEXITCODE -ne 0) { Write-Host \"  Error: Could not get peers from pod $$($$pod.metadata.name)\" }; Write-Host '' }"
else
	@bash scripts/vault-raft-peers.sh $(VAULT_INSTANCES_NAMESPACE) $(KUBECONFIG) || \
		($(call print_warning,Error getting Raft peers. Make sure Vault pods are running.) && \
		 echo "$(COLOR_YELLOW)Fallback: Check manually with:$(COLOR_RESET)" && \
		 echo "  kubectl -n $(VAULT_INSTANCES_NAMESPACE) exec -it <vault-pod> -- vault operator raft list-peers")
endif
	@echo ""

.PHONY: vault-uninstall
vault-uninstall:
	$(call print_warning,This will delete ALL Vault instances and data!)
	@echo "Press Ctrl+C to cancel, or wait 10 seconds to continue..."
	$(call sleep_seconds,10)
	$(call print_info,Deleting Vault instances...)
	-@$(KUBECTL) delete vaults.vault.banzaicloud.com --all -n $(VAULT_INSTANCES_NAMESPACE) || true
	$(call print_info,Deleting Vault secrets and PVCs...)
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete secret vault-unseal-keys 2>/dev/null || true
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete pvc -l app.kubernetes.io/name=vault 2>/dev/null || true
	$(call print_info,Deleting security resources...)
	-@$(KUBECTL) delete -f vault/manifests/vault/vault-pdb.yaml 2>/dev/null || true
	$(call print_info,Uninstalling Vault Operator...)
ifeq ($(DETECTED_OS),Windows)
	-@$(call run_helmfile,$(HELMFILE_OPERATOR),destroy) 2>nul || echo "Operator may already be uninstalled"
else
	-@$(call run_helmfile,$(HELMFILE_OPERATOR),destroy) || true
endif
	$(call print_success,Vault uninstalled.)

.PHONY: vault-recreate
vault-recreate:
	$(call print_warning,This will delete the Vault instance and recreate it!)
	@echo "Press Ctrl+C to cancel, or wait 5 seconds to continue..."
	$(call sleep_seconds,5)
	$(call print_info,Deleting Vault instance...)
	-@$(KUBECTL) delete vaults.vault.banzaicloud.com vault -n $(VAULT_INSTANCES_NAMESPACE) || true
	$(call print_info,Deleting Vault secrets and PVCs...)
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete secret vault-unseal-keys || true
	-@$(KUBECTL) -n $(VAULT_INSTANCES_NAMESPACE) delete pvc -l app.kubernetes.io/name=vault || true
	$(call sleep_seconds,10)
	$(call print_info,Recreating Vault instance...)
	@$(MAKE) vault-create-instance
	$(call print_success,Vault recreated!)

.PHONY: vault-configure
vault-configure:
	$(call print_info,Configuring Vault policies and auth methods...)
	@python vault/scripts/configure-vault.py --kubeconfig $(KUBECONFIG_REL)
	$(call print_success,Vault configuration applied!)

.PHONY: vault-sync-envs
vault-sync-envs:
	$(call print_info,Syncing environment variables to Vault...)
	@python vault/scripts/sync-vault-envs.py --kubeconfig $(KUBECONFIG_REL) $(if $(SERVICE),--service $(SERVICE),)
	$(call print_success,Environment variables synced!)

.PHONY: vault-sync-policies
vault-sync-policies:
	$(call print_info,Syncing Vault policies and roles...)
	@python vault/scripts/sync-vault-policies.py --kubeconfig $(KUBECONFIG_REL) $(if $(SERVICE),--service $(SERVICE),)
	$(call print_success,Policies and roles synced!)
