AWSRevokeOlderSessions — jak natychmiast zablokować przejęte credentials IAM

Tymczasowych poświadczeń STS nie możesz unieważnić — ale możesz je zablokować jedną inline policy. Wyjaśniam jak działa aws:TokenIssueTime i jak z niego skorzystać podczas incydentu.

AWSRevokeOlderSessions — jak natychmiast zablokować przejęte credentials IAM
📋 Spis treści

Scenariusz: credentials wyciekły. Co teraz?

Dostajesz alert z GuardDuty albo widzisz dziwne wpisy w CloudTrail. Ktoś używa Twoich tymczasowych poświadczeń IAM (ASIA...) spoza oczekiwanego adresu IP. Wiesz, że nastąpił wyciek.

Odruchowo szukasz przycisku “Revoke” dla tego konkretnego klucza. I tu zaczyna się problem — takiego przycisku nie ma.


Dlaczego tymczasowych credentials nie można po prostu usunąć?

Tymczasowe poświadczenia STS (ASIA*) działają inaczej niż długoterminowe klucze IAM (AKIA*):

  • Są generowane “w locie” przez usługę STS (Secure Token Service)
  • AWS nie przechowuje ich po wygenerowaniu — nie ma listy aktywnych tokenów
  • Wygasają same — ale dopiero po upływie czasu życia sesji (domyślnie 1h, maks. 12h dla AssumeRole)
  • Można je unieważnić… ale nie bezpośrednio

Kiedy aplikacja lub osoba wywołuje sts:AssumeRole, AWS generuje trójkę:

  • AccessKeyId (ASIA...)
  • SecretAccessKey
  • SessionToken

Tego zestawu po wygenerowaniu nie ma jak “cofnąć”. Działa aż do momentu wygaśnięcia, chyba że…


Trik: aws:TokenIssueTime

AWS IAM udostępnia specjalny klucz kontekstu żądaniaaws:TokenIssueTime. Jego wartość to dokładna data i czas wystawienia tokenu STS dla bieżącej sesji.

Dzięki temu można napisać politykę, która mówi:

“Zablokuj wszystkie akcje, jeśli token pochodzi sprzed daty X.”

I to właśnie robi AWSRevokeOlderSessions — inline policy dodawana do roli, której credentials wyciekły:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": ["*"],
      "Resource": ["*"],
      "Condition": {
        "DateLessThan": {
          "aws:TokenIssueTime": "2026-02-26T14:30:00.000Z"
        }
      }
    }
  ]
}

Podajesz datę i godzinę dodania tej polityki. Każdy token wystawiony przed tą chwilą dostaje twardy Deny na wszystkie akcje — niezależnie od innych uprawnień roli.

Nowe sesje (AssumeRole po tej dacie) działają normalnie.


Jak to działa mechanicznie?

IAM ewaluuje polisy w określonej kolejności. Explicit Deny zawsze wygrywa — nawet jeśli inna polisa daje Allow. Schemat ewaluacji wygląda tak:

1. Czy istnieje Deny pasujący do żądania?  → TAK → ODMOWA
2. Czy istnieje Allow pasujący do żądania? → NIE → ODMOWA (implicit deny)
3.                                           → TAK → DOSTĘP

Nasza inline policy dodaje warunek do każdego żądania: “czy token jest starszy niż data X?”. Dla atakującego, który ma stary token — wynik to zawsze Deny. Koniec historii.

Co ważne — aws:TokenIssueTime jest zawsze dostępny w kontekście żądania przy użyciu tymczasowych credentials. AWS gwarantuje tę wartość dla każdego tokenu STS.


Implementacja: Konsola AWS

  1. Przejdź do IAM → Roles i wybierz zaatakowaną rolę
  2. Zakładka Add permissions → Create inline policy
  3. Przełącz na widok JSON i wklej:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": ["*"],
      "Resource": ["*"],
      "Condition": {
        "DateLessThan": {
          "aws:TokenIssueTime": "TUTAJ-DATA-ISO8601"
        }
      }
    }
  ]
}
  1. Datę ustaw na aktualny czas UTC (np. 2026-02-26T14:35:00.000Z)
  2. Nazwij politykę AWSRevokeOlderSessions
  3. Kliknij Create policy

Alternatywnie: w zakładce Revoke sessions kliknij przycisk Revoke active sessions — AWS robi dokładnie to samo automatycznie.


Implementacja: AWS CLI

# 1. Pobierz aktualny czas UTC w formacie ISO 8601
REVOKE_TIME=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")

# 2. Utwórz plik z polisą
cat > revoke-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": ["*"],
      "Resource": ["*"],
      "Condition": {
        "DateLessThan": {
          "aws:TokenIssueTime": "${REVOKE_TIME}"
        }
      }
    }
  ]
}
EOF

# 3. Dodaj inline policy do roli
aws iam put-role-policy \
  --role-name NazwaZaatakowanejRoli \
  --policy-name AWSRevokeOlderSessions \
  --policy-document file://revoke-policy.json

Efekt jest natychmiastowy — nie ma opóźnienia propagacji.


Ważne zastrzeżenia

Co ta polityka robi:

  • Blokuje wszystkich posiadaczy tokenów starszych niż podana data
  • Dotyczy KAŻDEGO, kto zrobił AssumeRole — nie tylko atakującego
  • Użytkownicy/serwisy mogą odnowić sesję (AssumeRole ponownie) i działać bez przeszkód

Czego ta polityka nie robi:

  • Nie działa dla service-linked roles — te role mają własny mechanizm i inline policy dla nich nie można dodać w ten sposób
  • Nie odwołuje długoterminowych kluczy (AKIA*) — te wymagają dezaktywacji lub usunięcia w IAM
  • Nie blokuje dostępu do konsoli przez federację z zewnętrznym dostawcą tożsamości, jeśli token jest niezależny

Pułapka z “Revoke sessions” w konsoli: Przycisk ustawia datę i godzinę kliknięcia. Jeśli atakujący nadal ma dostęp i zrobi AssumeRole po Twoim kliknięciu — jego nowy token nie będzie zablokowany. Dlatego równolegle napraw Trust Policy roli, żeby uniemożliwić nowe AssumeRole ze strony nieuprawnionego podmiotu.


Pełna reakcja na incydent — sekwencja działań

1. IZOLACJA
   └─ Dodaj AWSRevokeOlderSessions do zaatakowanej roli

2. ZABLOKOWANIE ŹRÓDŁA
   └─ Napraw Trust Policy — usuń/ogranicz kto może AssumeRole
   └─ Jeśli EC2/Lambda: rotate credentials, zabroń IMDS lub ogranicz do IMDSv2

3. ANALIZA
   └─ CloudTrail: sprawdź co zrobił atakujący przez ostatnie godziny
   └─ GuardDuty findings: oceń zakres naruszenia

4. NAPRAWA
   └─ Wyeliminuj przyczynę (SSRF, debug mode, hardcoded credentials w kodzie)
   └─ Sprawdź czy atakujący nie stworzył backdoora (nowe role, użytkownicy IAM)

5. PRZYWRÓCENIE
   └─ Usuń AWSRevokeOlderSessions gdy zagrożenie minęło
   └─ Zrotuj credentials używane przez legitymowanych aktorów

Dlaczego ta polityka zasługuje na uwagę?

To eleganckie rozwiązanie problemu, który wydaje się nierozwiązywalny — jak cofnąć coś, czego nie można cofnąć.

AWS nie przechowuje listy aktywnych tokenów. Ale każdy token nosi w sobie datę urodzin w postaci aws:TokenIssueTime. I właśnie ta cecha — niezmienność czasu wystawienia — staje się dźwignią, którą można wymusić blokadę.

Jedna inline policy, jedna data, natychmiastowy efekt. Żadnych rebootów, żadnego downtime dla nowych sesji.


Odnośniki:

  1. Revoking IAM role temporary security credentials
  2. aws:TokenIssueTime condition key
  3. IAM JSON policy evaluation logic
← Wróć do Bezpieczeństwo