--- # ============================================================================= # ELK Stack on Kubernetes (Minikube) — Main Deployment Playbook # ============================================================================= # Usage: # ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml # # Tags: # --tags prereqs Install system dependencies # --tags certs Generate TLS certificates # --tags minikube Start/configure Minikube # --tags namespaces Create K8s namespaces # --tags secrets Create TLS secrets in K8s # --tags mysql Deploy MySQL # --tags elasticsearch Deploy Elasticsearch # --tags es-setup Run Elasticsearch post-setup # --tags kibana Deploy Kibana # --tags logstash Deploy Logstash # --tags nginx Deploy NGINX proxy # --tags authentik Deploy Authentik SSO # --tags dns Configure /etc/hosts # ============================================================================= - name: Deploy ELK Stack on Kubernetes hosts: localhost connection: local gather_facts: true tasks: # ======================================================================= # PHASE 1 — Prerequisites # ======================================================================= - name: Install system prerequisites tags: [prereqs] block: - name: Update apt cache become: true ansible.builtin.apt: update_cache: true cache_valid_time: 3600 - name: Install required packages become: true ansible.builtin.apt: name: - curl - apt-transport-https - ca-certificates - gnupg - lsb-release - openssl - docker.io - conntrack state: present - name: Ensure Docker service is running become: true ansible.builtin.systemd: name: docker state: started enabled: true - name: Add current user to docker group become: true ansible.builtin.user: name: "{{ ansible_user_id }}" groups: docker append: true - name: Install kubectl become: true ansible.builtin.shell: | if ! command -v kubectl &>/dev/null; then curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl rm -f kubectl fi args: creates: /usr/local/bin/kubectl - name: Install minikube become: true ansible.builtin.shell: | if ! command -v minikube &>/dev/null; then curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 install minikube-linux-amd64 /usr/local/bin/minikube rm -f minikube-linux-amd64 fi args: creates: /usr/local/bin/minikube # ======================================================================= # PHASE 2 — TLS Certificates # ======================================================================= - name: Generate TLS certificates tags: [certs] block: - name: Create certs directory ansible.builtin.file: path: "{{ certs_dir }}" state: directory mode: "0755" - name: Run certificate generation script ansible.builtin.command: cmd: bash "{{ scripts_dir }}/generate-certs.sh" "{{ certs_dir }}" creates: "{{ certs_dir }}/ca.crt" # ======================================================================= # PHASE 3 — Minikube # ======================================================================= - name: Start and configure Minikube tags: [minikube] block: - name: Check if Minikube is running ansible.builtin.command: minikube status --format='{{.Host}}' register: minikube_status ignore_errors: true changed_when: false - name: Start Minikube ansible.builtin.command: > minikube start --cpus={{ minikube_cpus }} --memory={{ minikube_memory }} --disk-size={{ minikube_disk_size }} --driver={{ minikube_driver }} --addons=default-storageclass,storage-provisioner when: minikube_status.rc != 0 or 'Running' not in minikube_status.stdout - name: Enable ingress addon ansible.builtin.command: minikube addons enable ingress changed_when: false # ======================================================================= # PHASE 4 — Kubernetes Namespaces # ======================================================================= - name: Create Kubernetes namespaces tags: [namespaces] ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/namespaces/namespaces.yaml" changed_when: false # ======================================================================= # PHASE 5 — TLS Secrets in Kubernetes # ======================================================================= - name: Create TLS secrets tags: [secrets] block: - name: Delete existing elk-certificates secret (if any) ansible.builtin.command: kubectl delete secret elk-certificates -n elk --ignore-not-found changed_when: false - name: Create elk-certificates secret in elk namespace ansible.builtin.command: > kubectl create secret generic elk-certificates -n elk --from-file=ca.crt={{ certs_dir }}/ca.crt --from-file=ca.key={{ certs_dir }}/ca.key --from-file=elasticsearch.crt={{ certs_dir }}/elasticsearch.crt --from-file=elasticsearch.key={{ certs_dir }}/elasticsearch.key --from-file=elasticsearch.p12={{ certs_dir }}/elasticsearch.p12 --from-file=http.p12={{ certs_dir }}/elastic-http.p12 --from-file=kibana.crt={{ certs_dir }}/kibana.crt --from-file=kibana.key={{ certs_dir }}/kibana.key --from-file=logstash.crt={{ certs_dir }}/logstash.crt --from-file=logstash.key={{ certs_dir }}/logstash.key --from-file=nginx.crt={{ certs_dir }}/nginx.crt --from-file=nginx.key={{ certs_dir }}/nginx.key --from-file=authentik.crt={{ certs_dir }}/authentik.crt --from-file=authentik.key={{ certs_dir }}/authentik.key # ======================================================================= # PHASE 6 — MySQL (database namespace) # ======================================================================= - name: Deploy MySQL tags: [mysql] block: - name: Apply MySQL manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/mysql/" changed_when: false - name: Wait for MySQL to be ready ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=mysql -n database --timeout=180s changed_when: false # ======================================================================= # PHASE 7 — Elasticsearch # ======================================================================= - name: Deploy Elasticsearch tags: [elasticsearch] block: - name: Apply Elasticsearch manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/elasticsearch/elasticsearch.yaml" changed_when: false - name: Wait for Elasticsearch to be ready ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=elasticsearch -n elk --timeout=300s changed_when: false # ======================================================================= # PHASE 8 — Elasticsearch post-setup # ======================================================================= - name: Run Elasticsearch setup job tags: [es-setup] block: - name: Delete previous setup job (if any) ansible.builtin.command: kubectl delete job elasticsearch-setup -n elk --ignore-not-found changed_when: false - name: Apply setup job ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/elasticsearch/setup-job.yaml" changed_when: false - name: Wait for setup job completion ansible.builtin.command: > kubectl wait --for=condition=complete job/elasticsearch-setup -n elk --timeout=120s changed_when: false # ======================================================================= # PHASE 9 — Authentik SSO # ======================================================================= - name: Deploy Authentik SSO tags: [authentik] block: - name: Apply Authentik manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/authentik/" changed_when: false - name: Wait for Authentik PostgreSQL ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=authentik-postgresql -n elk --timeout=120s changed_when: false - name: Wait for Authentik Redis ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=authentik-redis -n elk --timeout=60s changed_when: false - name: Wait for Authentik Server ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=authentik-server -n elk --timeout=180s changed_when: false # ======================================================================= # PHASE 10 — Kibana # ======================================================================= - name: Deploy Kibana tags: [kibana] block: - name: Apply Kibana manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/kibana/" changed_when: false - name: Wait for Kibana to be ready ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=kibana -n elk --timeout=300s changed_when: false # ======================================================================= # PHASE 11 — Logstash # ======================================================================= - name: Deploy Logstash tags: [logstash] block: - name: Apply Logstash manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/logstash/" changed_when: false - name: Wait for Logstash to be ready ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=logstash -n elk --timeout=180s changed_when: false # ======================================================================= # PHASE 12 — NGINX Proxy # ======================================================================= - name: Deploy NGINX reverse proxy tags: [nginx] block: - name: Apply NGINX manifests ansible.builtin.command: kubectl apply -f "{{ k8s_manifests_dir }}/nginx/" changed_when: false - name: Wait for NGINX to be ready ansible.builtin.command: > kubectl wait --for=condition=ready pod -l app=nginx -n elk --timeout=60s changed_when: false # ======================================================================= # PHASE 13 — DNS / /etc/hosts # ======================================================================= - name: Configure local DNS tags: [dns] block: - name: Get Minikube IP ansible.builtin.command: minikube ip register: minikube_ip changed_when: false - name: Add kibana.elk.local to /etc/hosts become: true ansible.builtin.lineinfile: path: /etc/hosts regexp: '.*kibana\.elk\.local.*' line: "{{ minikube_ip.stdout }} kibana.elk.local authentik.elk.local" state: present # ======================================================================= # FINAL — Summary # ======================================================================= - name: Deployment summary tags: [always] block: - name: Get Minikube IP for summary ansible.builtin.command: minikube ip register: minikube_ip_final changed_when: false ignore_errors: true - name: Print access information ansible.builtin.debug: msg: | ╔══════════════════════════════════════════════════════════════╗ ║ ELK Stack Deployment Complete! ║ ╠══════════════════════════════════════════════════════════════╣ ║ ║ ║ Minikube IP: {{ minikube_ip_final.stdout | default('N/A') }} ║ ║ ║ Kibana (NGINX proxy): ║ ║ https://kibana.elk.local:30443 ║ ║ User: elastic / ElasticP@ss2024! ║ ║ ║ ║ Authentik Admin: ║ ║ https://authentik.elk.local:30944 ║ ║ User: akadmin / AdminP@ss2024! ║ ║ ║ ║ Elasticsearch: ║ ║ kubectl port-forward svc/elasticsearch 9200:9200 -n elk ║ ║ User: elastic / ElasticP@ss2024! ║ ║ ║ ╚══════════════════════════════════════════════════════════════╝