Amazon Macie ile S3 Bucket'larında PII Avı

Merhabalar, bu yazımda AWS tarafında uzun süredir göz ucuyla baktığımız ama bir türlü sıra gelmeyen konulardan birine, Amazon Macie ile S3 bucket'larında PII (kişisel olarak tanımlanabilir bilgi) tespitine bakacağız. KVKK ya da GDPR ile uğraşmış olanlar bilir, kullanıcı verisinin nerede olduğu sorusu kâğıt üzerinde basit, pratikte ise sancılıdır. Veri ekibi bir export atar, geliştiriciler test için bir CSV bırakır, support ekibi bir PDF yedekler ve elinizde nereden çıktığı belli olmayan onlarca dosya birikir. Hadi başlayalım.

Macie nedir, ne işe yarar?

Amazon Macie, S3 üzerindeki nesneleri makine öğrenmesi ve regex tabanlı kalıplarla tarayıp içinde hassas veri olup olmadığını söyleyen bir servis. Yani siz bir bucket gösteriyorsunuz, o size 'şu dosyada 247 e-posta adresi, 12 kredi kartı numarası buldum' diyor. Yönetilen kimlik tanımlayıcılar (managed data identifiers) ile kredi kartı, IBAN, TC kimlik formatına benzeyen yapılar, e-posta, telefon ve daha onlarca tip kutudan çıkar çıkmaz hazır geliyor.

İşin güzel tarafı şu: Macie, bucket'ların içeriğini sizin hesabınıza kopyalamadan tarıyor; sadece bulguları (findings) çıkarıyor. Yani veri yerinde kalıyor, siz raporu alıyorsunuz.

Hedefli bir tarama job'u

Tüm hesabı baştan aşağı taramak hem yavaş hem de pahalı. Ben genelde önce 'müşteri verisi içerme ihtimali yüksek' bucket'ları işaretleyip sadece onlara odaklı bir job çalıştırırım. Aşağıdaki gibi bir komutla başlayabilirsiniz:

aws macie2 create-classification-job \
  --job-type ONE_TIME \
  --name 'pii-tarama-musteri-verisi' \
  --s3-job-definition '{
    "bucketDefinitions": [
      {
        "accountId": "123456789012",
        "buckets": ["customer-data", "user-uploads", "crm-exports"]
      }
    ],
    "scoping": {
      "includes": {
        "and": [{
          "simpleScopeTerm": {
            "comparator": "CONTAINS",
            "key": "OBJECT_EXTENSION",
            "values": ["csv", "json", "xlsx", "txt", "pdf"]
          }
        }]
      }
    }
  }' \
  --managed-data-identifier-selector INCLUDE \
  --managed-data-identifier-ids '["CREDIT_CARD_NUMBER","EMAIL_ADDRESS","PHONE_NUMBER","NAME","ADDRESS"]'

Burada iki noktanın altını çizmek istiyorum. Birincisi OBJECT_EXTENSION ile sadece okunabilir dosya tiplerini hedefliyoruz; binary log dosyalarına Macie'yi salmanın anlamı yok. İkincisi managed-data-identifier-ids listesini sade tutuyoruz. Tüm tanımlayıcıları açtığınızda hem maliyet artıyor hem de gerçekten önemsediğiniz bulgular gürültüde kayboluyor.

Kuruma özel kalıplar: custom data identifier

Yönetilen tanımlayıcılar dışında kendi formatlarınız varsa - mesela MUS-2024-00012345 gibi bir müşteri numarası - bunları da Macie'ye öğretebilirsiniz:

aws macie2 create-custom-data-identifier \
  --name 'MusteriNo' \
  --regex 'MUS-[0-9]{4}-[0-9]{8}' \
  --keywords '["musteri", "uye", "abone"]' \
  --description 'Dahili musteri numarasi formati'

keywords alanını boş geçmemenizi tavsiye ederim. Regex tek başına çalıştığında yanlış pozitif (false positive) oranı yükseliyor; anahtar kelimeler bir nesnede geçmediğinde Macie eşleşmeyi düşük güvenle işaretliyor.

EventBridge ile bulguları otomatize etmek

Bulguları konsoldan tek tek incelemek bir noktadan sonra mümkün değil. Bence en sağlıklı yaklaşım, Macie'nin bulgularını EventBridge'e akıtıp Lambda ile bir politika uygulamak. Yüksek şiddetli (high severity) bir bulgu geldiğinde nesneyi karantina bucket'ına taşıyıp ekibe SNS ile haber veren bir akış genelde yeterli oluyor.

import boto3, json

s3 = boto3.client('s3')
sns = boto3.client('sns')
QUARANTINE = 'pii-quarantine'
TOPIC = 'arn:aws:sns:eu-central-1:123456789012:pii-alerts'

def lambda_handler(event, context):
    detail = event['detail']
    severity = detail['severity']['description']
    bucket = detail['resourcesAffected']['s3Bucket']['name']
    key = detail['resourcesAffected']['s3Object']['key']

    if severity == 'High':
        s3.copy_object(
            Bucket=QUARANTINE,
            Key=f'{bucket}/{key}',
            CopySource={'Bucket': bucket, 'Key': key},
        )
        s3.delete_object(Bucket=bucket, Key=key)
        sns.publish(TopicArn=TOPIC, Subject='PII karantinaya alindi', Message=json.dumps(detail))
    return {'statusCode': 200}

Production'da bu fonksiyona idempotency kontrolü ve KMS yetkileri ekleyeceksiniz, ama iskelet bu kadar.

Sık karşılaşılan tuzaklar

  • Tüm hesabı tek seferde taramak: Macie GB başına ücretlendiriyor. Petabaytlık bir data lake'i --job-type SCHEDULED ile haftalık baştan aşağı taratırsanız aybaşında sürpriz bir fatura görürsünüz. Ben job'u önce kritik bucket'lara, sonra OBJECT_SIZE ile büyük dosyaları dışlayarak çalıştırıyorum.
  • Sample bulgulara güvenmek: Macie ücretsiz değerlendirme modunda sadece örnek tarama yapar; gerçek bulgu sayısını burada göremezsiniz. Üretim kararını sample üzerinden vermeyin.
  • Regex'i çok geniş yazmak: [0-9]{10,} gibi bir custom identifier aklınıza gelen her sayı dizisini PII sanır. Mutlaka anchor ve keyword birlikte kullanın.
  • Bucket policy'yi unutmak: Bulgu geldikten sonra dosyayı sildiniz diyelim; aynı uygulama yarın aynı dosyayı tekrar yazıyorsa sıfırdan başlıyorsunuz. Kaynağı düzeltmeden alarmı susturmayın.

Kapanış

Bu yazıda Macie ile S3'te PII keşfini, hedefli job tanımını, custom identifier'ları ve EventBridge tabanlı basit bir otomasyon hattını ele aldık. Şahsi kanaatim, Macie'yi 'her şeyi tara' modunda değil, dar kapsamlı ama düzenli çalışan job'lar olarak konumlandırmak hem cebinize hem de uyarı yorgunluğunuza iyi geliyor. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.