← Kursa Dön
📄 Text · 35 min

Güvenlik — Authentication, Authorization, TLS

Giriş — Authentication, Authorization, TLS/SSL ve RBAC

Bir bankanın güvenlik sistemini düşün. Kapıdan girmek için kimlik gösterirsin (authentication — kim olduğunu kanıtla). İçeri girdikten sonra her yere gidemezsin — kasaya sadece yetkili personel girer, müdürün odasına sadece randevuyla girilir (authorization — neye erişebileceğin). Ve tüm iletişim şifreli — telefon dinlenmez, kameralar güvenli, belgeler kilitli kasada (TLS/SSL — iletişim güvenliği).

Elasticsearch güvenliği de aynı üç ayak üzerinde durur. Önceki versiyonlarda güvenlik opsiyoneldi (ve pahalı bir eklentiydi). Elasticsearch 8.x ile varsayılan olarak aktif. Artık production'da güvenliksiz Elasticsearch çalıştırmak kabul edilemez.


1. Elasticsearch Güvenlik Katmanları

KatmanAmaçTeknoloji
AuthenticationKim olduğunu doğrulaNative, LDAP, SAML, OIDC, API Key
AuthorizationNeye erişebileceğini belirleRBAC, Field/Document Level Security
Encryptionİletişimi şifreleTLS/SSL (node-to-node, client-to-node)
Audit LoggingKim ne yaptı?Audit trail
IP FilteringNereden erişebileceğini kısıtlaIP whitelist/blacklist

2. TLS/SSL — İletişim Güvenliği

Neden TLS?

Elasticsearch node'ları arasında ve client-node arasında giden veri şifrelenmezse, network'te dinleyen biri tüm verilerinizi görebilir — query'ler, response'lar, credential'lar dahil.

Sertifika Oluşturma

# 1. Certificate Authority (CA) oluştur
bin/elasticsearch-certutil ca --out elastic-stack-ca.p12

# 2. Node sertifikaları oluştur
bin/elasticsearch-certutil cert \
  --ca elastic-stack-ca.p12 \
  --out elastic-certificates.p12

# 3. PEM format (opsiyonel — bazı araçlar PEM ister)
bin/elasticsearch-certutil cert \
  --ca elastic-stack-ca.p12 \
  --out certs \
  --pem

# 4. HTTP sertifikası (client-to-node)
bin/elasticsearch-certutil http

elasticsearch.yml — TLS Konfigürasyonu

# Transport layer (node-to-node) — ZORUNLU
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.client_authentication: required
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12

# HTTP layer (client-to-node) — ÖNERİLEN
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: http.p12
xpack.security.http.ssl.truststore.path: http.p12

# PEM format kullanıyorsanız:
# xpack.security.transport.ssl.key: /etc/elasticsearch/certs/node.key
# xpack.security.transport.ssl.certificate: /etc/elasticsearch/certs/node.crt
# xpack.security.transport.ssl.certificate_authorities: /etc/elasticsearch/certs/ca.crt

Keystore'a Şifre Ekleme

# P12 keystore şifresi
bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password

3. Authentication — Kimlik Doğrulama

Built-in Users

Elasticsearch kurulduğunda otomatik oluşturulan kullanıcılar:

KullanıcıRolüKullanım
elasticSuperuserAdmin işlemleri
kibana_systemKibana internalKibana → ES bağlantısı
logstash_systemLogstash monitoringLogstash monitoring
beats_systemBeats monitoringBeats monitoring
apm_systemAPM monitoringAPM monitoring
remote_monitoring_userMonitoringMonitoring cluster

Şifre Ayarlama

# Tüm built-in kullanıcılara otomatik şifre ata
bin/elasticsearch-setup-passwords auto

# İnteraktif şifre belirleme
bin/elasticsearch-setup-passwords interactive

# Belirli kullanıcının şifresini değiştir (API)
POST _security/user/elastic/_password
{
  "password": "new-super-secret-password"
}

Native User Oluşturma

// Kullanıcı oluştur
POST _security/user/john_doe
{
  "password": "s3cr3tP@ssw0rd",
  "roles": ["log_reader", "dashboard_viewer"],
  "full_name": "John Doe",
  "email": "john@company.com",
  "metadata": {
    "department": "engineering",
    "team": "backend"
  }
}

// Kullanıcı güncelle
PUT _security/user/john_doe
{
  "roles": ["log_reader", "dashboard_viewer", "index_writer"],
  "full_name": "John Doe",
  "email": "john@company.com"
}

// Kullanıcı sil
DELETE _security/user/john_doe

// Kullanıcıları listele
GET _security/user

API Key Authentication

Servisler arası iletişim için kullanıcı adı/şifre yerine API key daha güvenli ve pratiktir:

// API Key oluştur
POST _security/api_key
{
  "name": "filebeat-key",
  "expiration": "365d",
  "role_descriptors": {
    "filebeat_writer": {
      "cluster": ["monitor", "manage_index_templates", "manage_ilm"],
      "indices": [
        {
          "names": ["filebeat-*", "logs-*"],
          "privileges": ["create_index", "create", "write", "manage"]
        }
      ]
    }
  }
}

// Yanıt:
{
  "id": "VuaCfGcBCdbkQm-e5aOx",
  "name": "filebeat-key",
  "api_key": "ui2lp2axTNmsyakw9tvNnw",
  "encoded": "VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw=="
}

API Key kullanımı:

# Authorization header ile
curl -H "Authorization: ApiKey VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==" \
  https://es:9200/_cluster/health

# Veya id:api_key base64 encode
# base64(VuaCfGcBCdbkQm-e5aOx:ui2lp2axTNmsyakw9tvNnw)
// API Key bilgilerini görüntüle
GET _security/api_key?name=filebeat-key

// API Key'i invalidate et (revoke)
DELETE _security/api_key
{
  "name": "filebeat-key"
}

// Tüm API Key'leri listele
GET _security/api_key

LDAP / Active Directory Entegrasyonu

# elasticsearch.yml — LDAP realm
xpack.security.authc.realms.ldap.ldap1:
  order: 1
  url: "ldaps://ldap.company.com:636"
  bind_dn: "cn=elasticsearch,ou=services,dc=company,dc=com"
  user_search:
    base_dn: "ou=users,dc=company,dc=com"
    filter: "(uid={0})"
  group_search:
    base_dn: "ou=groups,dc=company,dc=com"
  ssl:
    certificate_authorities: ["/etc/elasticsearch/certs/ldap-ca.crt"]
  files:
    role_mapping: "/etc/elasticsearch/role_mapping.yml"
# role_mapping.yml — LDAP grup → ES role mapping
developer:
  - "cn=developers,ou=groups,dc=company,dc=com"
admin:
  - "cn=sysadmins,ou=groups,dc=company,dc=com"
log_reader:
  - "cn=all-employees,ou=groups,dc=company,dc=com"

SAML / OIDC (SSO)

# elasticsearch.yml — SAML realm
xpack.security.authc.realms.saml.saml1:
  order: 2
  idp.metadata.path: "https://idp.company.com/metadata.xml"
  idp.entity_id: "https://idp.company.com"
  sp.entity_id: "https://kibana.company.com"
  sp.acs: "https://kibana.company.com/api/security/saml/callback"
  sp.logout: "https://kibana.company.com/logout"
  attributes.principal: "nameid"
  attributes.groups: "groups"

4. Authorization — Yetkilendirme (RBAC)

Role-Based Access Control

RBAC ile kullanıcılara roller atanır, roller ise izinleri tanımlar.

Role Oluşturma

// Log okuyucu — sadece logları okuyabilir
POST _security/role/log_reader
{
  "cluster": ["monitor"],
  "indices": [
    {
      "names": ["logs-*", "filebeat-*"],
      "privileges": ["read", "view_index_metadata"]
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": ["feature_discover.read", "feature_dashboard.read"],
      "resources": ["space:default"]
    }
  ]
}

// Index yöneticisi — index oluşturabilir, yazabilir
POST _security/role/index_manager
{
  "cluster": ["manage_index_templates", "manage_ilm", "monitor"],
  "indices": [
    {
      "names": ["*"],
      "privileges": ["create_index", "manage", "write", "read", "delete"]
    }
  ]
}

// Dashboard görüntüleyici
POST _security/role/dashboard_viewer
{
  "cluster": [],
  "indices": [
    {
      "names": ["logs-*", "metrics-*"],
      "privileges": ["read"]
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": ["feature_dashboard.read"],
      "resources": ["space:default"]
    }
  ]
}

// Superuser (tehlikeli — dikkatli kullan)
POST _security/role/custom_superuser
{
  "cluster": ["all"],
  "indices": [
    {
      "names": ["*"],
      "privileges": ["all"]
    }
  ],
  "run_as": ["*"]
}

Cluster Privileges

PrivilegeAçıklama
allTüm cluster işlemleri
monitorCluster health, stats okuma
manageCluster yönetimi
manage_securityKullanıcı/role yönetimi
manage_index_templatesIndex template yönetimi
manage_ilmILM yönetimi
manage_pipelineIngest pipeline yönetimi

Index Privileges

PrivilegeAçıklama
allTüm index işlemleri
readArama, get, mget, field caps
writeIndex, update, delete, bulk
createSadece create (yoksa oluştur)
create_indexIndex oluşturma
deleteDocument silme
delete_indexIndex silme
manageIndex ayarları, mapping, alias
view_index_metadataIndex metadata okuma
monitorIndex stats, recovery

5. Field-Level ve Document-Level Security

Field-Level Security (FLS)

Belirli field'lara erişimi kısıtlama:

POST _security/role/pii_restricted
{
  "indices": [
    {
      "names": ["users-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["name", "department", "role", "created_at"],
        "except": ["ssn", "salary", "phone", "address"]
      }
    }
  ]
}

// Bu role sahip kullanıcı users-* index'inden arama yaptığında:
// - name, department, role, created_at → görür
// - ssn, salary, phone, address → göremez

Document-Level Security (DLS)

Belirli document'lara erişimi kısıtlama:

// Sadece kendi departmanının verilerini görebilir
POST _security/role/department_reader
{
  "indices": [
    {
      "names": ["employees-*"],
      "privileges": ["read"],
      "query": {
        "bool": {
          "filter": [
            { "term": { "department": "engineering" } }
          ]
        }
      }
    }
  ]
}

// Bu role sahip kullanıcı employees-* index'inde arama yaptığında:
// Sadece department="engineering" olan document'ları görür

Birleşik FLS + DLS

POST _security/role/hr_restricted
{
  "indices": [
    {
      "names": ["employees-*"],
      "privileges": ["read"],
      "field_security": {
        "grant": ["name", "department", "title", "start_date"]
      },
      "query": {
        "bool": {
          "must_not": [
            { "term": { "department": "executive" } }
          ]
        }
      }
    }
  ]
}

// Executive departmanını göremez + salary/ssn gibi field'ları göremez

6. Audit Logging

Audit Log Etkinleştirme

# elasticsearch.yml
xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include:
  - access_denied
  - access_granted
  - anonymous_access_denied
  - authentication_failed
  - connection_denied
  - tampered_request
  - run_as_denied
  - run_as_granted
  - security_config_change

# Çok fazla log oluşmaması için filtreleme
xpack.security.audit.logfile.events.exclude:
  - access_granted

xpack.security.audit.logfile.events.emit_request_body: false

Audit Log Çıktısı

// /var/log/elasticsearch/<cluster-name>_audit.json
{
  "@timestamp": "2024-01-15T14:30:00.000Z",
  "event.action": "access_denied",
  "user.name": "john_doe",
  "user.roles": ["log_reader"],
  "origin.address": "10.0.1.50",
  "request.name": "DeleteIndexRequest",
  "indices": ["production-data"],
  "action": "indices:admin/delete"
}

7. IP Filtering

# elasticsearch.yml
xpack.security.transport.filter.allow: ["10.0.0.0/8", "192.168.0.0/16"]
xpack.security.transport.filter.deny: _all

xpack.security.http.filter.allow: ["10.0.0.0/8", "172.16.0.0/12"]
xpack.security.http.filter.deny: _all

Veya dinamik olarak:

PUT _cluster/settings
{
  "persistent": {
    "xpack.security.transport.filter.allow": "10.0.0.0/8",
    "xpack.security.transport.filter.deny": "_all"
  }
}

8. Java ile Güvenlik Konfigürasyonu

SSL ile Bağlantı

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;

import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;

public class SecureElasticsearchClient {

    public static ElasticsearchClient create() throws Exception {
        // SSL Context
        KeyStore trustStore = KeyStore.getInstance("pkcs12");
        try (InputStream is = Files.newInputStream(
                Path.of("/etc/app/certs/elastic-ca.p12"))) {
            trustStore.load(is, "changeme".toCharArray());
        }

        SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(trustStore, null)
            .build();

        // Credentials
        BasicCredentialsProvider credProvider = new BasicCredentialsProvider();
        credProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials("app_user", "s3cret")
        );

        // REST Client
        RestClient restClient = RestClient.builder(
                new HttpHost("es-node1", 9200, "https"),
                new HttpHost("es-node2", 9200, "https")
            )
            .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .setSSLContext(sslContext)
                .setDefaultCredentialsProvider(credProvider)
            )
            .build();

        // Elasticsearch Client
        ElasticsearchTransport transport = new RestClientTransport(
            restClient, new JacksonJsonpMapper());

        return new ElasticsearchClient(transport);
    }
}

API Key ile Bağlantı

import org.apache.http.Header;
import org.apache.http.message.BasicHeader;

public static ElasticsearchClient createWithApiKey(
        String apiKeyEncoded) throws Exception {

    RestClient restClient = RestClient.builder(
            new HttpHost("es-node1", 9200, "https")
        )
        .setDefaultHeaders(new Header[]{
            new BasicHeader("Authorization", "ApiKey " + apiKeyEncoded)
        })
        .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
            .setSSLContext(sslContext)
        )
        .build();

    ElasticsearchTransport transport = new RestClientTransport(
        restClient, new JacksonJsonpMapper());

    return new ElasticsearchClient(transport);
}

Spring Boot ile Güvenlik Konfigürasyonu

# application.yml
spring:
  elasticsearch:
    uris: https://es-node1:9200,https://es-node2:9200
    username: app_user
    password: ${ES_PASSWORD}
    socket-timeout: 30s
    connection-timeout: 10s
@Configuration
public class ElasticsearchConfig {

    @Bean
    public ElasticsearchClient elasticsearchClient() throws Exception {
        // SSL + API Key konfigürasyonu
        // (yukarıdaki SecureElasticsearchClient pattern'ı)
        return SecureElasticsearchClient.create();
    }
}

9. Best Practices

✅ Yap

KonuÖneri
TLSHem transport hem HTTP katmanında TLS etkinleştir
Minimum privilegeHer kullanıcı/servis sadece gereken izinlere sahip olsun
API KeyServisler için kullanıcı/şifre yerine API key kullan
Audit logProduction'da her zaman açık
Elastic şifresiİlk kurulumda hemen değiştir
Sertifika rotasyonuSertifikaları yıllık yenile, otomatize et
LDAP/SAMLBüyük organizasyonlarda SSO kullan

❌ Yapma

KonuNeden
Güvenliksiz productionHerkes her şeyi okuyabilir/silebilir
elastic kullanıcısıyla uygulamaSuperuser — tehlikeli. Uygulama-specific kullanıcı oluştur
Şifreleri config dosyasındaKeystore veya environment variable kullan
FLS/DLS olmadan PII verisiGDPR/KVKK ihlali riski
Self-signed cert production'daGeçerli CA sertifikası kullan

10. Yaygın Hatalar ve Çözümleri

Hata 1: "SSL Handshake Failed"

# Sorun: Node'lar birbirine bağlanamıyor
# Kontrol: Sertifikalar aynı CA'dan mı?
openssl x509 -in node.crt -text -noout | grep Issuer

# CA sertifikası tüm node'larda mevcut mu?
# Sertifika süresi dolmuş mu?
openssl x509 -in node.crt -enddate -noout

Hata 2: "Security Exception — action is unauthorized"

// Sorun: Kullanıcının yeterli yetkisi yok
// Kontrol: Kullanıcının rollerini kontrol et
GET _security/user/john_doe

// Rolün izinlerini kontrol et
GET _security/role/log_reader

// Çözüm: Eksik privilege'i ekle
PUT _security/role/log_reader
{
  "indices": [
    {
      "names": ["logs-*"],
      "privileges": ["read", "view_index_metadata"]
    }
  ]
}

Hata 3: "Cannot Connect — Connection Refused"

# HTTP SSL aktif ama client HTTP (SSL'siz) ile bağlanıyor
# Kontrol:
curl -k https://localhost:9200  # https ile dene
curl http://localhost:9200      # http → connection refused (doğru davranış)

# Sertifika doğrulama hatası varsa:
curl --cacert /etc/elasticsearch/certs/ca.crt https://localhost:9200

Özet

  1. TLS/SSL hem node-to-node (transport) hem client-to-node (HTTP) katmanında zorunludur — Elasticsearch 8.x'te varsayılan olarak aktif.

  2. Authentication kullanıcı kimliğini doğrular — Native users, LDAP, SAML, OIDC ve API Key desteklenir. Servisler için API Key tercih edin.

  3. RBAC ile roller tanımlanır ve kullanıcılara atanır — minimum privilege prensibi: her kullanıcı sadece gereken izinlere sahip olmalı.

  4. Field-Level Security ve Document-Level Security ile hassas verilere erişimi granüler kontrol edebilirsiniz — PII verisi içeren index'lerde zorunlu.

  5. Audit logging production'da her zaman açık olmalı — kim ne yaptı sorusuna cevap verir, güvenlik ihlallerini tespit eder.

  6. Elastic superuser ile uygulama çalıştırmayın — uygulama-specific kullanıcı ve API key oluşturun.