← Back to list

Ansible ve Terraform İle ELK Stack Kurulumu

Terraform

Faruk · 2025-07-25 11:09 · 1 claps · 14.8 min read
#elasticsearch #kibana #terraform #ansibl #elk
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Ansible ve Terraform İle ELK Stack Kurulumu

Terraform

main.tf

1. Terraform Sağlayıcı ve Provider Tanımı

terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.45"
    }
  }
}

Bu blok, Hetzner Cloud için gerekli Terraform sağlayıcısını (hcloud) tanımlar. Versiyon sabitlemesi ile hem kararlılık hem de ileri uyumsuzlukların önüne geçilmiş olur.

provider "hcloud" {
  token = var.hcloud_token
}

Hetzner API’sine erişim sağlayan hcloud provider’ı burada tanımlanıyor. Token dışarıdan değişken olarak alınıyor ve hassas bilgilerin versiyon kontrolüne girmemesi sağlanıyor.

2. Özel Ağ (Private Network) Oluşturulması

resource "hcloud_network" "private_net" {
  name     = "elastic-network"
  ip_range = "192.168.122.0/24"
}

Bu kaynak, sunucuların bağlanacağı özel bir ağ tanımlar. Bu ağ sadece Hetzner içi özel IP trafiği için kullanılacak, böylece güvenli ve izole bir iletişim kanalı sağlanmış olur.

resource "hcloud_network_subnet" "subnet" {
  network_id   = hcloud_network.private_net.id
  type         = "server"
  network_zone = "eu-central"
  ip_range     = "192.168.122.0/24"
}

hcloud_network_subnet ile ağın aktif olarak kullanılabilmesi için bir subnet tanımlanır. Hetzner Cloud’da özel ağlar bu şekilde subnet üzerinden sunuculara atanır.

3. Sunucu Bilgilerinin Tanımlanması (Local Variables)

locals {
  servers = [
    { name = "es-node-1", ip = "192.168.122.10" },
    { name = "es-node-2", ip = "192.168.122.11" },
    { name = "es-node-3", ip = "192.168.122.12" },
    { name = "kibana", ip = "192.168.122.13" },
  ]
}

Bu blok, sunucuların isim ve özel IP adreslerini içeren bir liste tanımlar. Bu yapı sayesinde dinamik sunucu oluşturma mümkün olur. Sabit IP ataması, Ansible ile yapılacak yapılandırmaların deterministik olması açısından önemlidir.

4. Dinamik Sunucu Oluşturma

resource "hcloud_server" "nodes" {
  for_each = { for s in local.servers : s.name => s }
  name        = each.value.name
  image       = "ubuntu-24.04"
  server_type = "cpx11"
  ssh_keys    = [var.ssh_key]
  • for_each kullanılarak listedeki her sunucu ayrı bir kaynak gibi yönetilir.
  • Ubuntu 24.04 imajı, uzun vadeli destek (LTS) ve en son güncellemeler için tercih edilir.
  • cpx11 tipi Hetzner’de küçük ve uygun fiyatlı bir sunucu türüdür, test ve küçük üretim ortamları için yeterlidir.
public_net {
    ipv6_enabled = false
    ipv4_enabled = true
  }

IPv6 devre dışı bırakılmış; IPv4 ile dış erişim sağlanıyor. Bu ayar, güvenlik duvarı ve ağ yapılandırmasını sadeleştirir.

network {
    network_id = hcloud_network.private_net.id
    ip         = each.value.ip
  }
}

Her sunucu, daha önce tanımlanan elastic-network isimli özel ağa atanıyor. IP adresi statik verildiği için Ansible yapılandırmaları ya da güvenlik kuralları doğrudan bu adreslere göre ayarlanabilir.

Genel Değerlendirme

Bu main.tf dosyası ile:

  • Bir özel ağ ve subnet oluşturuluyor
  • Dört adet sunucu (3 Elasticsearch, 1 Kibana) bu özel ağa atanmış şekilde kuruluyor
  • Statik özel IP adresleri, konfigürasyon ve servis içi iletişimde kararlılığı garantiliyor
  • Tüm sunucular Hetzner Cloud üzerinde otomatik olarak provision ediliyor

variables.tf

1. hcloud_token

variable "hcloud_token" {
  type    = string
  default = "API-KEY"
}
  • Hetzner Cloud API erişimi için gerekli olan güvenlik anahtarıdır.
  • default olarak örnek bir API anahtarı ("API-KEY") verilmiş olsa da, bu gerçek ortamlarda genellikle .tfvars dosyasıyla ya da ortam değişkeni (environment variable) ile geçilmelidir.
  • Hassas bilgi olduğu için sensitive = true parametresi eklenerek Terraform çıktılarında gizlenmesi önerilir (örnek geliştirmelerde bu eksik).

Güvenlik Tavsiyesi:

variable "hcloud_token" {
  type      = string
  sensitive = true
}

2. ssh_key

variable "ssh_key" {
  type    = string
  default = "faruk"
}
  • Hetzner Cloud sunucularına erişim için önceden Hetzner hesabına yüklenmiş olan SSH anahtarının adı burada tanımlanır.
  • Bu ad, hcloud_server kaynaklarında ssh_keys = [var.ssh_key] şeklinde kullanılarak sunuculara otomatik olarak yetkilendirilmiş SSH erişimi sağlar.

Not:

Bu anahtarın Hetzner Cloud kontrol panelinde SSH Keys bölümünde mevcut olması gerekir. Aksi takdirde Terraform hata verir.

3. server_type

variable "server_type" {
  type    = string
  default = "cpx11"
}
  • Hetzner Cloud’da kullanılacak sunucu tipi belirlenir.
  • cpx11, düşük kaynaklı ama fiyat-performans açısından uygun bir sunucu tipidir (2 vCPU, 2 GB RAM).
  • Bu değişkenin tanımlanması, sunucu kaynak tipini merkezî şekilde yönetmeyi sağlar. Gerektiğinde daha yüksek kapasiteli örneklerle değiştirmek çok kolaylaşır (örneğin cx21 ya da cpx31)

Ansible

inventory.ini

Genel Yapı

[elasticsearch_master]

[elasticsearch_master]
x.x.x.x node_name=es-node-1
  • Bu grup, Elasticsearch cluster’ında ilk başlatılacak ve diğer node’ların bağlanacağı ana (master) düğümü tanımlar.
  • node_name=es-node-1 değişkeni, elasticsearch.yml yapılandırmasında node.name olarak kullanılır.

Ayrıca:

  • Token üretimi (elasticsearch-create-enrollment-token)
  • Sertifika üretimi
  • Servis token oluşturma gibi işlemler de bu host üzerinden yapılır.

[elasticsearch_nodes]

[elasticsearch_nodes]
x.x.x.x node_name=es-node-2
x.x.x.x node_name=es-node-3
  • Bu grup, veri taşıyan (data node) Elasticsearch düğümleridir.
  • Master tarafından oluşturulan cluster’a enrollment token ile bağlanırlar.
  • node_name her biri için farklı olarak atanmalı ve elasticsearch.yml içinde kullanılır.

🎯 Bu ayrım, cluster mimarisinde yönetim ve veri taşıma işlevlerini birbirinden ayırmak için önemlidir.

[kibana]

[kibana]
x.x.x.x node_name=kibana
  • Web tabanlı arayüz sunucusudur.
  • Elasticsearch ile bağlantısını service account token üzerinden sağlar.
  • Aynı zamanda kendi TLS sertifikası ile kullanıcıya HTTPS arayüz sunar.
  • kibana.yml ve kibana-keystore konfigürasyonları burada çalıştırılır.

[loadbalancer]

[loadbalancer]
x.x.x.x
  • Elasticsearch için gelen istekleri TLS destekli olarak yönlendiren ters proxy (Nginx) sunucusudur.
  • Jinja2 ile oluşturulan nginx.conf içindeki upstream bloğu bu grubun IP’lerine göre otomatik yazılır.

Teknik Detay ve Uyum Notları

  • inventory_hostname Ansible'da her zaman host'un tanımlı IP'sidir → hostvars[host]['inventory_hostname'] gibi kullanımlarla dinamik şablonlar oluşturulmuştur.
  • node_name değişkeni özellikle elasticsearch-configure.yml gibi playbook’larda lineinfile modülü ile kullanılmaktadır.
  • groups['kibana'][0], groups['elasticsearch_nodes'] gibi ifadeler ile diğer node’lara delegate_to ve hostvars üzerinden erişim sağlanmıştır.
  • IP adresleri x.x.x.x olarak örnek bırakılmış ama gerçek ortamda her sunucuya ait özel veya genel IP adresi ile doldurulmalıdır.

elasticsearch-installation.yml

✅ Genel Amaç

Elasticsearch sunucularını Hetzner Cloud üzerinde dağıttıktan sonra, bu playbook ile hem elasticsearch_master hem de elasticsearch_nodes host gruplarında:

  • Gerekli bağımlılıkların kurulması
  • Elasticsearch paketinin indirilmesi
  • Paketin kurulumu

adımları gerçekleştirilir.

📍 Hedef Hostlar

hosts: elasticsearch_master:elasticsearch_nodes
  • : operatörü Ansible’da union (birleşim) anlamına gelir.
  • Bu sayede hem master hem de data node’lar aynı kurulumdan geçer.
  • Elasticsearch kurulumu tüm düğümlerde benzer olduğu için doğru bir stratejidir.

⚙️ Vars Tanımları

vars:
  elasticsearch_deb_url: "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-9.0.3-amd64.deb"
  elasticsearch_deb_file: "/tmp/elasticsearch.deb"
  • Versiyon sabitlenmiş şekilde Elastic’in resmi deposundan .deb dosyası indiriliyor.
  • vars bloğu ile parametrik yapı kurulmuş; bu dosya başka versiyonlara uyarlanabilir hale getirilmiş.
  • İyi bir pratik olarak bu değişkenler ayrı bir group_vars/elasticsearch_nodes.yml dosyasına alınabilir.

🔧 Tasks Analizi

1. Ensure dependencies are installed

- name: Ensure dependencies are installed
  apt:
    name: wget
    state: present
    update_cache: true
  • wget Elasticsearch paketini indirmek için gereklidir.
  • update_cache: true ile APT cache’i taze tutulur, bu da hata riskini azaltır.

2. Download Elasticsearch .deb package

- name: Download Elasticsearch .deb package
  get_url:
    url: "{{ elasticsearch_deb_url }}"
    dest: "{{ elasticsearch_deb_file }}"
    mode: '0644'
  • get_url modülü, uzak URL’den paket indirir.
  • Dosya /tmp klasörüne kaydedilir.
  • mode: '0644' ile erişim izinleri sistem gerekliliklerine uygun hale getirilmiş.

3. Install Elasticsearch .deb package

- name: Install Elasticsearch .deb package
  apt:
    deb: "{{ elasticsearch_deb_file }}"
    state: present
  • .deb dosyasını sistemde kurmak için apt modülünün deb: parametresi kullanılmış.
  • Bu yöntem, doğrudan dpkg -i yerine daha güvenlidir çünkü bağımlılık yönetimi APT tarafından yapılır.

elasticsearch-configure.yml

Genel Amaç

Bu playbook, tüm Elasticsearch düğümlerinde aşağıdaki yapılandırmaları gerçekleştirir:

  • Cluster adı
  • Node adı
  • Dinleme IP’si (network.host)
  • HTTP portu (http.port)

Bu yapılandırma, Elasticsearch node’larının birbirleriyle haberleşmesini ve dışarıdan erişilebilir olmasını sağlar.

Hedef Hostlar

hosts: elasticsearch_master:elasticsearch_nodes
  • Tüm Elasticsearch node’larını hedefler.
  • node_name değişkeninin dinamik olarak farklı olması gerektiği varsayılıyor (örneğin inventory.ini içinde her hosta özel olarak tanımlanmış).

Vars Tanımları

vars:
  network_host: "0.0.0.0"
  http_port: "9200"
  cluster_name: "es-cluster"
  • network_host: 0.0.0.0: Tüm arayüzlerden erişim sağlar. Dış erişim gerektiren durumlarda bu ayar zorunludur. Güvenlik duvarı veya Nginx ile sınırlanmalıdır.
  • http_port: Varsayılan Elasticsearch HTTP portudur. İstenirse değiştirilebilir.
  • cluster_name: Elasticsearch node'larının aynı cluster’a ait olduğunu belirtir.

⚠️ node_name değişkeni vars olarak burada tanımlanmamış. Bunun Ansible inventory.ini dosyasında host bazında tanımlı olması beklenir:

[elasticsearch_nodes]
es-node-1 node_name=es-node-1
es-node-2 node_name=es-node-2

Görev: Konfigürasyon Satırlarını Ayarlama

- name: Set multiple config lines
  ansible.builtin.lineinfile:
    path: /etc/elasticsearch/elasticsearch.yml
    regexp: "^#?{{ item.key }}:"
    line: "{{ item.key }}: {{ item.value }}"
    backrefs: true 
  loop:
    - { key: 'cluster.name', value: '{{ cluster_name }}' }
    - { key: 'node.name', value: '{{ node_name }}' }
    - { key: 'network.host', value: '{{ network_host }}' }
    - { key: 'http.port', value: '{{ http_port }}' }
  • lineinfile modülü ile elasticsearch.yml dosyası satır satır düzenleniyor.
  • regexp: İlgili ayar satırı varsa onu bulur.
  • ^#?{{ item.key }}: ifadesi hem aktif hem de yorum satırı olan ayarları hedef alır.
  • line: Ayarın yeni değeri yazılır.
  • backrefs: true: regexp'in eşleşmesini güncelleme işlemiyle bağlar.

elasticsearch-create-master.yml

Genel Amaç

  • Elasticsearch master node’un servisini başlatmak
  • elastic sistem kullanıcısının şifresini sıfırlamak (non-interaktif)
  • Servisin başarılı bir şekilde HTTPS üzerinden ayakta olduğunu doğrulamak

hedef Host

hosts: elasticsearch_master
  • Sadece master node üzerinde çalışır.
  • Elasticsearch’te kullanıcı kimlik doğrulaması ve güvenlik ayarları yalnızca master üzerinden başlatılır, bu da doğru bir tercihtir.

Vars Tanımları

vars:
  elastic_password: "elastic"
  elastic_port: "9200"
  elastic_host: "localhost"
  • elastic_password: elastic sistem kullanıcısı için atanacak şifre (geliştirme ortamında sabitlenmiş, üretim ortamında vars dosyasına veya vault’a alınmalı).
  • elastic_host ve elastic_port: Sağlık kontrolü için uri modülünde kullanılıyor.

Görevler

1. Elasticsearch Servisini Başlatma

- name: Start elasticsearch 
  ansible.builtin.systemd:
    name: elasticsearch
    state: started
    enabled: true
  • Servis başlatılır ve sistem yeniden başlatıldığında otomatik açılması sağlanır.

2. Elastic Kullanıcısının Parolasını Sıfırlama

- name: Reset elastic user password non-interactively
  become: true
  ansible.builtin.shell: |
    printf "{{ elastic_password }}\n{{ elastic_password }}\n" | /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -s -b -i
  args:
    executable: /bin/bash
  • Elasticsearch 8.x/9.x ile birlikte gelen elasticsearch-reset-password aracı, parola sıfırlamada kullanılır.

Bu komut:

  • -s: sistem kullanıcı parolasını sıfırlamak için
  • -b: batch mode (non-interaktif)
  • -i: kullanıcıdan tekrar onay istemesi için
  • printf komutu ile parolanın iki kez girilmesi simüle edilir.

3. Servisin Durumunu Tekrar Doğrulama

- name: Ensure Elasticsearch is running
  systemd:
    name: elasticsearch
    state: started
    enabled: true
  • Önceki task’e ek olarak servis kontrolü bir daha yapılıyor.
  • Gereksiz tekrar gibi görünebilir, ama parola sıfırlama sonrası servisin çökme ihtimali varsa bu adım güvenliği artırır.

4. Elasticsearch Sağlık Kontrolü (HTTPS ile)

- name: Wait for Elasticsearch to start with HTTPS (skip SSL verification)
  uri:
    url: "https://{{ elastic_host }}:{{ elastic_port }}"
    method: GET
    status_code: 200
    validate_certs: false
    url_username: elastic
    url_password: "{{ elastic_password }}"
  • uri modülü ile Elasticsearch arayüzüne HTTPS üzerinden bağlanılır.
  • validate_certs: false: SSL henüz yapılandırılmadıysa geçici olarak devre dışı bırakılır.
  • Kullanıcı adı ve parola ile temel doğrulama (basic auth) yapılır.
  • status_code: 200 ile servis sağlığı kontrol edilir.

elasticsearch-join-each-node.yml

Genel Amaç

  • Worker node’ları, master node’un oluşturduğu cluster’a token üzerinden otomatik olarak bağlamak
  • Süreç içinde Elasticsearch servisini geçici olarak durdurup yeniden başlatmak
  • Yapının kurulum aşamasında deterministik bir şekilde işlemesini sağlamak

Hedef Hostlar

hosts: elasticsearch_nodes
  • Sadece veri taşıyacak olan worker node’lara uygulanır.
  • Master node dışındaki tüm Elasticsearch sunucularını kapsar.

Vars Tanımı

vars:
  es_bin_dir: "/usr/share/elasticsearch/bin"
  • Elasticsearch CLI araçlarının bulunduğu dizin.
  • Hem master’da token üretmek, hem node üzerinde reconfigure işlemi yapmak için bu klasör kullanılır.

Görevler

1. Token Üretimi (Master Node Üzerinden)

- name: Generate token from master for this node
  args:
    chdir: "{{ es_bin_dir }}" 
  delegate_to: "{{ groups['elasticsearch_master'][0] }}"
  command: ./elasticsearch-create-enrollment-token -s node
  register: enrollment_token
  • delegate_to: Bu komut hedef worker node’da değil, master node’da çalıştırılır.
  • elasticsearch-create-enrollment-token -s node komutu, bir worker node’un cluster’a katılması için geçici, güvenli bir token üretir.
  • register ile token çıktısı alınır ve ileride kullanılmak üzere saklanır.

Her node için ayrı token üretildiği varsayılıyor. Tek token’la birden fazla node join edilemiyorsa bu yaklaşım doğru. Ancak tek token birden fazla node’a izin veriyorsa, token önceden generate edilip group_vars ile dağıtılabilir.

2. Token Debug

- name: Show token (debug)
  debug:
    var: enrollment_token.stdout
  • Token çıktısının kontrol amacıyla gösterilmesini sağlar.
  • Geliştirme ortamlarında faydalı; üretim ortamlarında no_log: true ile gizlenmelidir.

3. Elasticsearch Servisini Durdurma

- name: Stop Elasticsearch
  systemd:
    name: elasticsearch
    state: stopped
  • elasticsearch-reconfigure-node komutu servis kapalıyken çalışmalıdır.
  • Bu nedenle worker node üzerindeki servis geçici olarak durdurulur.

4. Cluster’a Katılım (Node Reconfigure)

- name: Join this node to cluster with token
  args:
    chdir: "{{ es_bin_dir }}" 
  command: printf "y\n" | ./elasticsearch-reconfigure-node --enrollment-token {{ enrollment_token.stdout }}
  • elasticsearch-reconfigure-node komutu, token ile node’u mevcut cluster’a bağlar.
  • Komut interaktif olarak “emin misin?” sorusu sorar. printf "y\n" ile bu soru cevaplanarak otomasyon tamamlanır.

5. Elasticsearch Servisini Başlatma

- name: Start Elasticsearch
  systemd:
    name: elasticsearch
    state: started
    enabled: true
  • Cluster’a katıldıktan sonra servis yeniden başlatılır ve sistem açılışında çalışacak şekilde etkinleştirilir.

6. Bekleme Süresi

- name: Pause for a sec 
  ansible.builtin.pause:
    minutes: 1
  • Elasticsearch yeniden başlarken zaman alabilir.
  • Burada sabit bir pause yerine wait_for modülü ile port kontrolü yapmak daha sağlam bir yaklaşımdır.
- name: Wait until Elasticsearch is available
  wait_for:
    port: 9200
    delay: 10
    timeout: 120

kibana-installation.yml

Genel Amaç

Kibana’nın:

  • Gerekli bağımlılıklar yüklenerek
  • Elastic’in resmi deposundan .deb paketi indirilerek
  • Paket kurulumu tamamlanarak

sunucuya eksiksiz bir şekilde yüklenmesini sağlamaktır.

Hedef Host

hosts: kibana
  • Sadece kibana grubundaki sunucular hedeflenir.
  • Bu grubun inventory.ini içerisinde node_name=kibana gibi tanımlanmış olması beklenir.

Vars Tanımları

vars:
  kibana_deb_url: "https://artifacts.elastic.co/downloads/kibana/kibana-9.0.3-amd64.deb"
  kibana_deb_file: "/tmp/kibana.deb"
  • Elastic’in resmi sitesinden indirilecek .deb dosyasının URL’si ve hedef dizini tanımlanır.
  • Versiyon kontrolü burada sabit; farklı versiyonlar için playbook yeniden kullanılabilir olacak şekilde parametrik yapılmış.

Gelişmiş yapılandırmalarda bu değişkenlerin group_vars/kibana.yml içine alınması önerilir.

Tasks Analizi

1. wget Bağımlılığının Kurulması

- name: Ensure dependencies are installed
  apt:
    name: wget
    state: present
    update_cache: true
  • wget komutu bazı sistemlerde yüklü gelmez, .deb dosyasını indirmeden önce sistemin hazırlandığı bir adımdır.
  • update_cache: true ile APT önbelleği güncellenerek olası paket çözümleme hataları engellenir.

Alternatif olarak curl kullanılabilir, ancak get_url modülü Ansible’ın kendi iç yapısıyla daha uyumludur.

2. Kibana Paketinin İndirilmesi

- name: Download Kibana .deb package
  get_url:
    url: "{{ kibana_deb_url }}"
    dest: "{{ kibana_deb_file }}"
    mode: '0644'
  • get_url modülü ile doğrudan Elastic’in CDN’inden .deb paketi indirilir.
  • mode: '0644' ile dosyanın erişim izinleri uygun şekilde ayarlanır.
  • Böylece apt tarafından okunabilir olur.

3. Paket Kurulumu

- name: Install Kibana .deb package
  apt:
    deb: "{{ kibana_deb_file }}"
    state: present
  • .deb paketi sistem üzerinde kurulurken, apt modülünün deb: parametresi ile çalışması tercih edilmiş.
  • Bu yöntem:
  • dpkg -i gibi komutlara göre bağımlılıkları daha iyi çözer
  • Sistemdeki apt ekosistemiyle uyumlu çalışır

kibana-configuration.yml

Genel Amaç

Bu playbook ile Kibana:

  • HTTPS üzerinden çalışacak şekilde yapılandırılır
  • Elasticsearch ile bağlantısı güvenli hale getirilir
  • Service account token kullanarak kimlik doğrulaması yapılır
  • kibana.yml konfigürasyonu otomatikleştirilir

Hedef Host

hosts: kibana
  • Sadece kibana grubuna ait node hedeflenir.
  • Elasticsearch cluster’a bağlanmak için gerekli yapılandırmalar tek sunucuya uygulanır.

Vars Tanımları

vars:
  elastic_ip: "https://{{ hostvars[groups['loadbalancer'][0]]['inventory_hostname'] }}:9200"
  token_api_endpoint: "_security/service/elastic/kibana/credential/token/kibana_token"
  elastic_password: "elastic"
  • elastic_ip: Kibana'nın Elasticsearch ile konuşacağı adres (bir load balancer varsayılmış).
  • token_api_endpoint: Elasticsearch REST API üzerinden servis account token oluşturma uç noktası.
  • elastic_password: İlk kurulum sonrası elastic kullanıcısı ile erişim sağlanır.

Gelişmiş senaryolarda bu şifre Vault ile şifrelenmeli ya da no_log: true ile maskelenmelidir.

Görevler

1. kibana.yml İçin Temel Ayarları Yapılandırma

- name: Set multiple config lines
  lineinfile:
    path: /etc/kibana/kibana.yml
    ...
  loop: [...]

Bu görev Kibana’nın çekirdek ayarlarını yapılandırır:

  • server.host, server.port: Kibana'nın hangi arayüzden yayın yapacağı belirlenir.
  • server.publicBaseUrl: Genelde ters proxy kullanıldığında dışarıya ilan edilen URL’dir.
  • server.ssl.*: Kibana ile kullanıcı arayüzü arasında HTTPS kullanımı sağlanır.
  • elasticsearch.ssl.*: Kibana’nın Elasticsearch’e bağlanırken güvenli TLS doğrulaması yapmasını sağlar.

🎯 Bu yapılandırma sayesinde hem dış kullanıcı arayüzü, hem backend güvenliği sağlanmış olur.

2. elasticsearch.hosts Bloğunu Tanımlama

- name: Elasticsearch host listesini ayarla
  blockinfile:
    path: /etc/kibana/kibana.yml
    marker: "# {mark} ANSIBLE MANAGED BLOCK elasticsearch.hosts"
    block: |
      elasticsearch.hosts:
      {% for host in groups['loadbalancer'] %}
        - https://{{ host }}:9200
      {% endfor %}
  • blockinfile ile elasticsearch.hosts parametresi toplu halde yazılır.
  • Burada Jinja2 döngüsü kullanılarak birden fazla load balancer veya ES endpoint’ine bağlanma imkanı sağlanmış.
  • marker etiketi ile Ansible’ın bu bloğu tekrar çalıştırdığında nereden başlayıp nerede bitireceği bellidir.

3. jq Paketini Yükleme

- name: Install jq
  apt:
    name: jq
    ...
  • jq, JSON çıktılarından sadece token.value gibi alanları almak için kullanılır.
  • Bu komut olmadan curl çıktısı işlenemez, dolayısıyla bir ön koşul olarak yüklenmiştir.

4. Elasticsearch Üzerinden Service Token Alma

- name: Get Kibana service account token
  shell: >
    curl -XPOST -k -u elastic:"{{ elastic_password }}" "{{ elastic_ip }}/{{ token_api_endpoint }}" | jq .token.value -r
  register: kibana_token
  • Elasticsearch REST API ile elastic kullanıcısı aracılığıyla yeni bir kibana_token oluşturulur.
  • jq .token.value -r: sadece token değerini döndürür (çıktıyı sadeleştirir).
  • -k: SSL sertifikası henüz tam doğrulanmadığı için geçici olarak devre dışı bırakılmıştır.

Bu token, Kibana’nın Elasticsearch’e güvenli bir şekilde bağlanmasını sağlayan kimlik bilgisidir

5. Token’ı Kibana Keystore’a Eklemek

- name: Add token to kibana keystore
  shell: >
    echo "{{ kibana_token.stdout }}" | ./kibana-keystore add elasticsearch.serviceAccountToken -x
  args:
    chdir: /usr/share/kibana/bin
  • kibana-keystore, Kibana’da gizli bilgileri şifreli olarak saklayan bir sistemdir.
  • Bu token oraya elasticsearch.serviceAccountToken anahtarıyla yazılır.
  • -x: stdin üzerinden gelen veriyi okur (non-interaktif kullanım için gereklidir).

kibana-generate-ssl-certificates.yml

Genel Amaç

  • Elasticsearch master node üzerinde, Kibana için SSL sertifikası üretmek
  • Üretilen sertifika dosyalarını Kibana sunucusuna kopyalamak
  • /etc/kibana/certs/ dizinine sertifikaları yerleştirip yetkilendirmek

Play 1: Elasticsearch Master Üzerinde Sertifika Oluşturulması

- name: SSL certificate preparation and distribution for Kibana
  hosts: elasticsearch_master

1. Keystore’dan Şifre Çekme

- name: Show secure password from keystore
  command: "{{ es_bin_path }}/elasticsearch-keystore show xpack.security.http.ssl.keystore.secure_password"
  register: keystore_password
  • Mevcut http.p12 sertifika paketini açabilmek için keystore’daki SSL şifresi alınır.
  • stdout değeri openssl komutunda kullanılmak üzere saklanır.

Gelişmiş kullanımda no_log: true ile şifre çıktısı gizlenmelidir.

2. CA Private Key Çıkarılması

- name: Extract CA private key from p12
  command: "openssl pkcs12 -in {{ certs_path }}/http.p12 -nocerts -nodes -out {{ certs_path }}/http_ca.key -passin pass:{{ keystore_password.stdout }}"
  • .p12 paketi içerisindeki CA private key çıkarılır ve http_ca.key olarak kaydedilir.
  • Bu key, Kibana için yeni bir sertifika üretiminde kullanılacaktır.

3. Kibana Sertifikasının Üretilmesi

- name: Generate PEM certificate for Kibana using its IP
  command: >
    {{ es_bin_path }}/elasticsearch-certutil cert --pem
    --ca-cert {{ certs_path }}/http_ca.crt
    --ca-key {{ certs_path }}/http_ca.key
    --ip {{ hostvars[groups['kibana'][0]]['inventory_hostname'] }}
    --out {{ output_path }}/kibana.zip -s
  • elasticsearch-certutil ile .crt ve .key dosyalarını içeren PEM formatında bir sertifika paketi (kibana.zip) oluşturulur.
  • --ip: Kibana’nın özel IP’si kullanılarak IP bazlı sertifika oluşturulur.
  • -s: interaktif sorular devre dışı bırakılır.

Play 2: Kibana Üzerinde Sertifikaların Kurulması

- name: Configure Kibana with certificates
  hosts: kibana

1. Sertifika Paketini Kopyalama (kibana.zip)

- name: Copy kibana.zip to host 
  synchronize:
    src: "{{ output_path }}/kibana.zip"
    dest: "{{ output_path }}/kibana.zip"
  delegate_to: "{{ groups['elasticsearch_master'][0] }}"
  • synchronize modülü, rsync benzeri bir şekilde Elasticsearch master’dan Kibana sunucusuna kibana.zip paketini taşır.
  • delegate_to: işlem aslında Kibana üzerinde çalışırken, dosya master’dan alınır.

2. CA Sertifikasının Kopyalanması (http_ca.crt)

- name: Copy http_ca.crt to host 
  copy:
    src: "{{ certs_path }}/http_ca.crt"
    dest: "{{ output_path }}/http_ca.crt"
  delegate_to: "{{ groups['elasticsearch_master'][0] }}"
  • Elasticsearch’in kök sertifikası Kibana’ya manuel olarak taşınır.
  • Bu sertifika sayesinde Kibana, Elasticsearch’in HTTPS bağlantısını doğrulayabilir.

3. Kibana Sertifika Dizininin Oluşturulması

- name: Ensure /etc/kibana/certs directory exists
  file:
    path: /etc/kibana/certs
    state: directory
    ...
  • Sertifikaların kalıcı olarak tutulacağı dizin yaratılır.
  • Gerekli sahiplik (kibana:kibana) ve izinler (0755) atanır.

4. kibana.zip Arşivinin Açılması

- name: Unzip kibana.zip to /etc/kibana/certs
  unarchive:
    src: /tmp/kibana.zip
    dest: /etc/kibana/certs
    remote_src: true
    ...
  • kibana.zip içeriği /etc/kibana/certs/ dizinine açılır.
  • İçerisinde instance.crt ve instance.key dosyaları yer alır.

5–6. CA Sertifikasının Taşınması ve Yetkilendirilmesi

- name: Move http_ca.crt to /etc/kibana/certs
  command: mv /tmp/http_ca.crt /etc/kibana/certs/http_ca.crt
- name: Set ownership and permissions on http_ca.crt
  file:
    path: /etc/kibana/certs/http_ca.crt
    owner: kibana
    group: kibana
    mode: '0774'
  • http_ca.crt dizine taşınır ve doğru kullanıcı/izin ayarları yapılır.
  • Bu dosya kibana.yml'de elasticsearch.ssl.certificateAuthorities parametresine karşılık gelir.

kibana-sync-ssl-certificates.yml

Genel Amaç

  • Master node’dan sertifikaları kontrol makinesine çekmek
  • Kontrol makinesinden Kibana sunucusuna yüklemek
  • Kibana üzerinde /etc/kibana/certs dizininde bu dosyaları hazır hale getirmek

Teknik Analiz

1. kibana.zip Dosyasını Kontrol Makinesine Alma

- name: Fetch kibana.zip to control machine
  fetch:
    src: "{{ output_path }}/kibana.zip"
    dest: "/tmp/kibana.zip"
    flat: true
  delegate_to: "{{ groups['elasticsearch_master'][0] }}"
  • fetch: Uzak host’tan dosyayı kontrol makinesine indirir.
  • delegate_to: Elasticsearch master node üzerinde çalışır.
  • flat: true: Dosya hedef dizine alt klasör yaratmadan direkt olarak /tmp'ye kopyalanır.

2. kibana.zip Dosyasını Kibana Sunucusuna Kopyalama

- name: Copy kibana.zip to Kibana host
  copy:
    src: "/tmp/kibana.zip"
    dest: "{{ output_path }}/kibana.zip"
  • Bu adımda kontrol makinesindeki kibana.zip, Kibana sunucusuna kopyalanır.
  • Burada fetch → copy modeli izlenmiştir (push–pull ayrımı).

3. http_ca.crt Sertifikasını Fetch Etme

- name: Fetch http_ca.crt to control machine
  fetch:
    src: "{{ certs_path }}/http_ca.crt"
    dest: "/tmp/http_ca.crt"
    flat: true
  delegate_to: "{{ groups['elasticsearch_master'][0] }}"
  • CA sertifikası da aynı yöntemle Elasticsearch master’dan alınır.

4. CA Sertifikasını Kibana Sunucusuna Kopyalama

- name: Copy http_ca.crt to Kibana host
  copy:
    src: "{{ output_path }}/http_ca.crt"
    dest: "/etc/kibana/certs/http_ca.crt"
  • Bu dosya, Kibana’nın Elasticsearch’e bağlanırken SSL doğrulaması yapmasını sağlar.

5. unzip Paketini Yükleme

- name: Install unzip
  apt:
    name: unzip
    state: present
  • kibana.zip dosyasını açmak için gerekli bağımlılık kurulmuş.
  • Bazı dağıtımlarda ön yüklü gelmeyebilir, bu nedenle iyi bir güvenlik önlemidir.

6. kibana.zip Arşivini Açma

- name: Extract kibana.zip
  unarchive:
    src: /tmp/kibana.zip
    dest: /etc/kibana/certs
    remote_src: true
  • kibana.zip içinde instance.crt ve instance.key dosyaları yer alır.
  • remote_src: true → ZIP dosyasının zaten uzak sistemde bulunduğunu belirtir.
  • /etc/kibana/certs dizinine çıkarılır.

⚠️ Sertifikaların izin ve sahiplikleri burada eksik kalmış. file modülüyle owner: kibana, mode: '0640' gibi ayarlar yapılmalıdır.

Yöntemsel Karşılaştırma

Yöntem Açıklama delegate_to + synchronize Daha hızlıdır, doğrudan node’dan node’a aktarım yapılır (rsync) fetch + copy Daha kontrollüdür, kontrol makinesinde log tutma ve dışa aktarma mümkündür. Bazı güvenlik senaryolarında tek opsiyondur

Her iki yöntem de doğru kullanım senaryosuna göre geçerlidir.

kibana-start-service.yml

Genel Amaç

  • Kibana servisini başlatmak (started)
  • Her sistem boot’unda servisin otomatik çalışmasını sağlamak (enabled)

Hedef Host

hosts: kibana
  • Kibana rolüne sahip node’ları hedefler.
  • Bu playbook, genellikle konfigürasyon ve sertifika işlemlerinden sonra çalıştırılır.

Görev Analizi

- name: Start Kibana Service
  systemd:
    name: kibana
    state: started
    enabled: true
  • systemd modülü kullanılarak Kibana servisi yönetilir.
  • state: started: Servis anlık olarak başlatılır.
  • enabled: true: Sistem yeniden başlasa bile servis otomatik olarak başlatılır.

Eğer servis çalışmazsa, bu noktada muhtemel hata logları /var/log/kibana/ altında incelenmelidir.

Loadbalancer

es-loadbalancer.yml – Ansible Playbook Analizi

Amaç

  • Nginx’in yüklenmesi
  • Jinja2 şablon dosyasının /etc/nginx/conf.d/ altına yerleştirilmesi
  • Nginx’in yapılandırmayı uygulayacak şekilde yeniden yüklenmesi

Görevler

  1. Nginx Kurulumu
- name: Ensure Nginx is installed
  apt:
    name: nginx
    state: present
    update_cache: true
  • Yük dengeleyici servisi olan Nginx kuruluyor.
  • update_cache: true ile APT önbelleği güncellenerek en güncel paketlerin kullanılması sağlanıyor.
  1. Nginx Yapılandırmasının Dağıtılması
- name: Deploy Nginx load balancer configuration
  template:
    src: nginx-loadbalancer.conf.j2
    dest: "{{ nginx_conf_path }}"
    owner: root
    group: root
    mode: '0644'
  • template modülü ile dinamik bir Jinja2 şablonu hedef sisteme işlenerek yazılıyor.
  • Bu sayede Elasticsearch node’larının IP adresleri envantere göre otomatik olarak yerleştirilebiliyor.
  1. Nginx Servisinin Yeniden Yüklenmesi
- name: Reload Nginx to apply new configuration
  systemd:
    name: nginx
    state: reloaded
    enabled: true
  • Nginx servis dosyası reload ediliyor.
  • enabled: true ile sistem yeniden başladığında aktif kalması sağlanıyor.

nginx-loadbalancer.conf.j2 – Jinja2 Tabanlı Nginx Şablon Analizi

Yapı

server {
    listen 9200 ssl;
    server_name _;
    ssl_certificate     /etc/kibana/certs/instance/instance.crt;
    ssl_certificate_key /etc/kibana/certs/instance/instance.key;
  • Nginx burada 9200 portunu dinliyor (Elasticsearch’in default portu).
  • TLS ile güvenli bağlantı kuruluyor.
  • Sertifikalar Kibana’nın /etc/kibana/certs/ dizininden kullanılıyor. (Bunlar genellikle instance.crt/.key olarak sertifika üretim aşamasında elde edilir.)
  • Bu yaklaşımda TLS termination Load Balancer’da gerçekleşiyor.

Proxy Ayarları

location / {
        proxy_pass https://es_backends;
        proxy_ssl_verify off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
  • proxy_pass: Gelen istekler es_backends upstream bloğuna yönlendirilir.
  • proxy_ssl_verify off: Elasticsearch backend'lerinin sertifikası doğrulanmaz (geliştirme ortamları için makul ama üretim için önerilmez).
  • Header bilgileri preserve edilir.

Upstream Tanımı (Dinamik Olarak Inventory’den)

upstream es_backends {
    {% for host in groups['elasticsearch_master'] + groups['elasticsearch_nodes'] %}
    server {{ hostvars[host]['inventory_hostname'] }}:9200;
    {% endfor %}
}
  • Elasticsearch master ve node’lar birlikte load balancer arkasına ekleniyor.
  • IP’ler inventory_hostname ile çekiliyor.
  • Bu yapı sayesinde Ansible inventory dosyasını güncellemek, Nginx backend listesini otomatik olarak güncellemek anlamına gelir.

Kibana Reverse Proxy

kibana-reverse-proxy.yml – Ansible Playbook Analizi

Amaç

  • Nginx yüklenir
  • /etc/nginx/conf.d/kibana.conf dosyası deploy edilir
  • Servis yeniden yüklenerek aktif hale getirilir

Görevler

  1. Nginx’in Kurulumu
- name: Ensure Nginx is installed
  apt:
    name: nginx
    state: present
    update_cache: true
  • Nginx henüz kurulu değilse yüklenir
  • Reverse proxy altyapısının temelini oluşturur
  1. Şablon Dosyasının Dağıtılması
- name: Deploy Nginx Reverse-Proxy
  template:
    src: kibana.conf.j2
    dest: "{{ nginx_conf_path }}"
  • kibana.conf.j2 şablonu /etc/nginx/conf.d/kibana.conf olarak yerleştirilir.
  • Tüm değişiklikler Ansible üzerinden merkezi olarak yönetilir.
  1. Nginx Servisinin Yeniden Yüklenmesi
- name: Reload Nginx to apply new configuration
  systemd:
    name: nginx
    state: reloaded
    enabled: true
  • Nginx yapılandırmasını yeniden yükler.
  • Sistem başlatıldığında Nginx’in otomatik olarak başlatılmasını sağlar.

kibana.conf.j2 – Nginx Reverse Proxy Şablon Dosyası Analizi

HTTP’den HTTPS’ye Yönlendirme

server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}
  • 80 portuna gelen HTTP istekleri, 443 portuna yönlendirilir
  • 301 Moved Permanently ile kalıcı HTTPS yönlendirmesi yapılır
  • SEO ve kullanıcı deneyimi açısından önemlidir

HTTPS Reverse Proxy (TLS)

server {
    listen 443 ssl;
    server_name _;
    ssl_certificate     /etc/kibana/certs/instance/instance.crt;
    ssl_certificate_key /etc/kibana/certs/instance/instance.key;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
  • Kibana arayüzü artık TLS (HTTPS) üzerinden sunulur
  • Sertifikalar daha önce oluşturulup /etc/kibana/certs/ dizinine yerleştirilmişti
  • TLS 1.2 ve 1.3 protokolleri destekleniyor (güncel güvenlik standardı)
  • Güvenli şifreleme algoritmaları belirlenmiş

Proxy Ayarları

location / {
        proxy_pass         https://localhost:5601;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection 'upgrade';
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
    }
  • proxy_pass: Kibana servisine (localhost:5601) trafik yönlendirilir
  • Upgrade ve Connection başlıkları, WebSocket bağlantılarını desteklemek için gereklidir (Kibana buna ihtiyaç duyar)
  • proxy_cache_bypass: Cache sistemlerinin Upgrade başlığına göre baypas edilmesini sağlar

Proje Github repositorysine adresten ulaşabilirsiniz https://github.com/farukerdem34/es-ansible/


메타데이터
post_id
724c14e8af86
slug
ansible-ve-terraform-i̇le-elk-stack-kurulumu-724c14e8af86
url
https://medium.com/@faruk3rdem/ansible-ve-terraform-i%CC%87le-elk-stack-kurulumu-724c14e8af86
canonical_url
https://medium.com/@faruk3rdem/ansible-ve-terraform-i%CC%87le-elk-stack-kurulumu-724c14e8af86
author_url
https://medium.com/@faruk3rdem
status
ok
fetched_at
2026-07-18 17:48:23