WebDisk
Object Storage

STS на практиці: доступ до S3 корпоративним обліковим записом (SSO), без постійних ключів

Data publikacji:

Блог WebDisk · категорія: Безпека · час читання: ~11 хвилин

Коротко:- Постійні ключі S3 – це секрети без терміну придатності: вони витікають, ніхто їх не ротує, а звільнення працівника їх не скасовує.- STS (Security Token Service) видає тимчасові облікові дані: вони діють годину або кілька, а потім стають безвартісними.- Поєднання STS із корпоративним входом (SSO) робить так, що до сховища S3 ви заходите своїм корпоративним обліковим записом – а правами й доступом керують в одному місці. >Не працюєте з терміналом? Пропустіть приклади коду – опис принципу дії та розділ про WebDisk дають повну картину.

Уявіть, що кожен працівник на старті отримує універсальний ключ до офісу – зроблений у майстерні за рогом, без обліку, дійсний безстроково. Коли хтось звільняється, ключ залишається в його шухляді. Коли хтось його загубить, ви міняєте замки… теоретично, бо на практиці ніхто не пам'ятає, скільки ключів ходить по світу.

Звучить абсурдно? А саме так працює більшість впроваджень S3: постійна пара ключів (access key + secret key), згенерована один раз, вставлена у скрипти, конфігурації та нотатки – і жива роками. У цій статті показуємо альтернативу, яку світ хмари застосовує вже давно, а яка досі напрочуд маловідома: STS, тобто службу, що видає тимчасові облікові дані, та її найцікавіше застосування – вхід до S3 корпоративним обліковим записом із SSO. Наприкінці описуємо, як ми побудували на цьому цілий продукт у WebDisk.

Проблема: секрет, який ніколи не втрачає чинності

Класичний доступ до S3 – це пара: ідентифікатор ключа (access key) і секрет (secret key). Технічно це просте й зручне рішення – тому воно так прижилося. Але воно має чотири вади, які з часом лише зростають:

  • Витік – це питання часу. Ключ потрапляє у скрипт, скрипт – у репозиторій, репозиторій – на GitHub. Автомати, що сканують публічні репозиторії, знаходять такі секрети за кілька хвилин після публікації.
  • Ротація болить, тому її не роблять. Заміна ключа означає оновлення всіх місць, куди його вставили – а ніхто не знає, скільки їх. Наслідок: ключі живуть роками.
  • Звільнення працівника нічого не змінює. Обліковий запис у корпоративному каталозі блокують, але ключ S3 – це окрема сутність: він працює далі, доки хтось про нього не згадає під час аудиту.
  • Один ключ, багато користувачів. На практиці команди спільно користуються ключами, тож журнал подій каже лише «хтось із ключем X» – без інформації, хто.

Кожна з цих вад має спільне джерело: облікові дані вічні й відірвані від ідентичності людини. Виправити це можна лише одним способом – облікові дані мають бути короткочасними й видаватися на підставі справжньої, корпоративної ідентичності.

Що таке STS: перепустка замість ключа

STS (Security Token Service) – це служба з родини API AWS, реалізована також у Ceph RGW, рушії нашої платформи, яка робить одну річ: видає тимчасові облікові дані доступу. Замість вічної пари ключів ви отримуєте трійку:

  • тимчасовий access key і secret key – виглядають і працюють як звичайні ключі S3,
  • session token – додатковий елемент, який додається до кожного запиту,
  • та дату завершення чинності – після її спливу вся трійка стає безвартісною.

Найкраща аналогія – це гостьова перепустка в бізнес-центрі: рецепція перевіряє, хто ви, друкує ідентифікатор, дійсний до 17:00, і на цьому все. Не треба здавати його на виході, не треба міняти замки, якщо ви його загубите – просто завтра він уже не працює.

Ключове питання звучить так: на якій підставі STS видає перепустку? Способів кілька (родина викликів AssumeRole*), але нас цікавить найелегантніший: на підставі доказу з корпоративного входу.

SSO + S3, тобто AssumeRoleWithWebIdentity

Якщо ваша компанія має SSO (single sign-on – один вхід до всіх застосунків), то кожен працівник уже має цифрову ідентичність: обліковий запис у корпоративному каталозі, з паролем, MFA та належністю до груп. Стандарт OpenID Connect (OIDC), на якому працює більшість сучасних SSO, після входу видає так званий id_token – цифрово підписане «посвідчення особи»: хто увійшов, де й для якого застосунку.

Виклик STS під назвою AssumeRoleWithWebIdentity дозволяє обміняти це посвідчення на тимчасові облікові дані S3. Крок за кроком:

  1. Ви входите корпоративним обліковим записом (SSO: пароль, MFA – як до будь-якого іншого застосунку). Отримуєте id_token.
  2. Пред'являєте id_token службі STS, вказуючи роль IAM (IAM – Identity and Access Management, система ролей і прав у світі AWS/S3), яку хочете прийняти. Роль – це зразок перепустки, який рецепція тримає в теці: набір політик, що описують, що дозволено її власникові (напр. «читай і записуй бакети, назви яких починаються з firma-»).
  3. STS перевіряє посвідчення: перевіряє підпис токена у видавця (вашого SSO), його чинність і те, чи політика довіри ролі (trust policy) дозволяє власникам таких токенів приймати цю роль.
  4. Ви отримуєте трійку облікових даних, дійсну, наприклад, годину – і працюєте з S3 точно так само, як досі: aws CLI, rclone, boto3, будь-який сумісний із S3 інструмент.
  5. Після завершення чинності входите знову (або інструмент оновлює облікові дані сам – про це нижче).

Зверніть увагу на розподіл ролей: SSO відповідає на питання «хто ти», роль IAM – «що тобі дозволено», а STS є рецепцією, яка перевіряє одне й друкує перепустку за зразком. Ця розділеність – суть усієї конструкції:

  • ідентичностями керує ІТ-відділ в одному місці (корпоративний каталог) – блокування облікового запису відрізає доступ до всього одразу,
  • правами до даних керує власник даних – політикою ролі, а не роздаванням ключів,
  • а в журналі подій кожна сесія має назву, яку можна пов'язати з особою. Одне застереження: назву сесії декларує той, хто викликає, тож достовірна підзвітність вимагає її примусового встановлення на боці політики довіри або брокера, який виконує обмін (так робимо у WebDisk – про це нижче).

Технічна цікавинка: AssumeRoleWithWebIdentity – це один із небагатьох викликів у світі AWS API, який не вимагає жодних попередніх облікових даних – ви не підписуєте його ключем, бо вашою автентифікацією є сам id_token. Саме тому весь ланцюг може працювати для користувача, який не має і ніколи не мав статичних ключів S3.

Як виглядає роль IAM

Роль складається з двох частин, які варто розрізняти, бо вони відповідають на два різні питання. У прикладах з'являється ARN (Amazon Resource Name) – унікальний ідентифікатор ресурсу у світі AWS/S3: ролі, бакета чи видавця ідентичності.

Політика довіри (trust policy) – хто може прийняти роль. Вказує зареєстрованого видавця OIDC (ваше SSO) та умови, напр. що токен має бути виданий для конкретного застосунку:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "arn:aws:iam::<konto>:oidc-provider/sso.firma.example/realms/firma" },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": { "StringEquals": { "sso.firma.example/realms/firma:aud": "s3-firma" } }
  }]
}

Політики прав (permission policies) – що власник ролі може зробити. Звичайний документ IAM, напр.:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:ListBucket", "s3:GetObject", "s3:PutObject"],
    "Resource": ["arn:aws:s3:::firma-*"]
  }]
}

Точний синтаксис ключів умов різниться між постачальниками (AWS, Ceph RGW) – але конструкція завжди та сама: довіра до видавця ідентичності + межі прав.

Зроби сам: STS у терміналі та в коді

Перш ніж почати. Вам потрібні три речі від адміністратора платформи: адреса ендпоїнта S3/STS, ARN ролі, яку ви можете прийняти, та чинний id_token із вашого SSO. Останнє на практиці найважче: токен видає ваше SSO після входу, а здобувають його власною інтеграцією OIDC (потік Authorization Code + PKCE) або інструментами на кшталт oidc-agent. У послузі WebDisk вам не потрібно робити нічого з цього – панель самообслуговування виконує вхід через SSO і робить увесь обмін за вас (про це в наступному розділі); наведені нижче приклади показують, що відбувається під капотом, і є відправною точкою для інтеграторів.

Обмін токена на облікові дані в aws CLI:

aws sts assume-role-with-web-identity \
  --role-arn "arn:aws:iam::<konto>:role/firma-s3" \
  --role-session-name "jkowalski" \
  --web-identity-token file://id_token.jwt \
  --duration-seconds 3600 \
  --endpoint-url https://s3.twoj-dostawca.example

У відповідь ви отримуєте блок Credentials із трійкою облікових даних і датою завершення чинності. Вставте їх у змінні середовища – і відтепер кожен сумісний із S3 інструмент працює як завжди:

export AWS_ACCESS_KEY_ID="ASIA...tymczasowy"
export AWS_SECRET_ACCESS_KEY="...tymczasowy-sekret..."
export AWS_SESSION_TOKEN="...dlugi-token-sesji..."

aws s3 ls s3://firma-dokumenty/ --endpoint-url https://s3.twoj-dostawca.example

Ще зручніше: CLI та SDK AWS знають змінні AWS_ROLE_ARN і AWS_WEB_IDENTITY_TOKEN_FILE. Коли ви їх встановите, обмін токена й оновлення облікових даних відбуваються автоматично – інструмент сам викликає STS, коли попередня перепустка втрачає чинність:

export AWS_ROLE_ARN="arn:aws:iam::<konto>:role/firma-s3"
export AWS_WEB_IDENTITY_TOKEN_FILE="$HOME/.config/firma/id_token.jwt"
export AWS_ENDPOINT_URL_STS="https://s3.twoj-dostawca.example" # без цього CLI викличе STS від Amazon!

aws s3 ls s3://firma-dokumenty/ --endpoint-url https://s3.twoj-dostawca.example

Дві пастки, які треба знати:

  • --endpoint-url стосується лише самого виклику S3. Автоматичний обмін токена – це окремий, прихований виклик STS: без зазначення ендпоїнта інструмент спрямує його до типового STS від Amazon (sts.<region>.amazonaws.com) – приклад завершиться помилкою, а ваш корпоративний id_token потрапить до чужої служби. Тому при зовнішньому постачальнику завжди встановлюйте також AWS_ENDPOINT_URL_STS (у постачальників на Ceph RGW, у тому числі в нас, S3 і STS живуть за однією адресою). Це вимагає актуальних інструментів із підтримкою ендпоїнтів для окремих служб: aws CLI v2 ≥ 2.13 (v1 ≥ 1.29), boto3 ≥ 1.28; старіші SDK такої конфігурації не знають. Явні виклики – як перший приклад вище – коректні незалежно від версії.
  • Автоматика настільки свіжа, наскільки свіжий токен у файлі. При кожному оновленні інструмент читає файл із токеном заново – а id_token'и OIDC живуть недовго (типово від кількох до кількох десятків хвилин), зазвичай коротше, ніж видана на їхній підставі перепустка. Тож із вручну збереженим токеном оновлення вдасться раз чи двічі, а потім STS відповість помилкою ExpiredToken. Для роботи, довшої за життя токена, вам потрібне щось, що оновлює сам токен: інтеграція OIDC з refresh token, повторний вхід – або середовище, яке ротує файл за вас (так працює, напр., Kubernetes, де kubelet регулярно підмінює сервісний токен пода).

Те саме програмно на Python (boto3):

import boto3

sts = boto3.client("sts", endpoint_url="https://s3.twoj-dostawca.example")

resp = sts.assume_role_with_web_identity(
    RoleArn="arn:aws:iam::<konto>:role/firma-s3",
    RoleSessionName="jkowalski",
    WebIdentityToken=open("id_token.jwt").read(),
    DurationSeconds=3600,
)
c = resp["Credentials"]

s3 = boto3.client(
    "s3", endpoint_url="https://s3.twoj-dostawca.example",
    aws_access_key_id=c["AccessKeyId"],
    aws_secret_access_key=c["SecretAccessKey"],
    aws_session_token=c["SessionToken"],
)
listing = s3.list_objects_v2(Bucket="firma-dokumenty")
print([o["Key"] for o in listing.get("Contents", [])])

А якщо ви віддаєте перевагу rclone: тимчасові облікові дані вказуєте як звичайні, додаючи токен сесії (session_token у конфігурації віддаленого S3 або env_auth = true, щоб rclone читав три змінні середовища, показані вище).

Що це дає – і чого не дає

Чесний баланс виглядає так:

Ви отримуєте:

  • Відсутність вічних секретів. Немає чого вставити в репозиторій на роки; витік облікових даних небезпечний годину, а не десятиліття.
  • Централізований офбординг. Блокування облікового запису в SSO відрізає можливість отримати нові облікові дані – до всіх систем одразу, в одному місці.
  • Підзвітність. Кожна сесія має назву, пов'язану з особою (якщо її примусово встановлює брокер або політика); журнал подій перестає бути анонімним.
  • Межі, встановлені політикою, а не ключем. Зміна прав – це редагування політики ролі, миттєве для всіх наступних сесій, без заміни секретів.

Треба знати:

  • Видана перепустка живе до кінця своєї чинності. Блокування облікового запису в SSO не скасовує облікових даних, виданих хвилину раніше – вони згаснуть самі, але до того часу працюють. Саме тому встановлюють короткий час життя: годину, а не добу.
  • Інструменти мають уміти оновлюватися. Скрипт, що працює довше за чинність облікових даних, мусить їх оновити – автоматика з AWS_WEB_IDENTITY_TOKEN_FILE зробить це за вас за умови, що у файлі є свіжий id_token (див. пастки вище).
  • Автомати – це інша історія. STS із SSO вирішує проблему людей. Сервісні процеси (резервне копіювання, інтеграції) не входять паролем і MFA – для них застосовують окремі механізми: сервісні облікові записи з мінімальними правами, ідентичності машин, а постійні ключі, якщо вони мусять існувати, тримають у менеджері секретів і ротують автоматично.

Як ми робимо це у WebDisk: Tenant Manager

Усе, що ми описали вище, ми складаємо докупи в нашій послузі S3 для організацій, керованій через WebDisk Tenant Manager. Проєктуючи її, ми ухвалили рішення, яке впорядковує всю модель безпеки: кінцеві користувачі взагалі не мають постійних ключів S3 – доступ здійснюється виключно через STS.

Кожна організація (tenant) отримує комплект:

  • власний каталог ідентичностей – виділена область у нашому SSO, в якій адміністратор організації сам створює облікові записи для своїх людей; саме тут відбувається вхід і тут блокують облікові записи працівників, що звільняються,
  • жорстко ізольований обліковий запис на платформі Ceph – бакети, ролі та політики однієї організації невидимі й недоступні для інших; ізоляцію завершує виділений префікс назв бакетів,
  • ролі IAM із довірою виключно до каталогу цієї організації – політика довіри вказує конкретного видавця OIDC, тож токен із каталогу іншої компанії безвартісний,
  • графічний редактор політик IAM – адміністратор організації керує правами з панелі, без написання JSON вручну,
  • та власний ключ шифрування SSE-KMS – дані у стані спокою шифруються ключем організації, який можна зротувати або вимкнути з панелі (про варіанти шифрування в S3 ми писали в попередній статті цього циклу).

Для працівника організації це виглядає так: він заходить на сторінку самообслуговування, входить своїм корпоративним обліковим записом (SSO організації), а панель – що діє як брокер – виконує за нього описаний вище AssumeRoleWithWebIdentity і показує готові облікові дані, дійсні годину, разом із готовими фрагментами конфігурації для вставлення: змінні середовища, конфігурація aws CLI, конфігурація rclone. Брокер також надає назву сесії на підставі ідентичності, з якою здійснено вхід – тож підзвітність не залежить від доброї волі того, хто викликає. Один клік оновлює перепустку. Жодного ключа для запам'ятовування, жодного секрету для ротації, повна сумісність із будь-яким інструментом S3.

Послуга S3 для організацій наразі перебуває у фазі раннього доступу – якщо хочете протестувати цю модель у себе, напишіть нам, і ми підготуємо середовище для вашої організації.

Варто підкреслити різницю щодо наших кінцевих застосунків. У вебзастосунках WebDisk Files чи WebDisk Send ви не торкаєтеся облікових даних S3 – доступом до сховища за вас керує застосунок. Пропозиція STS – для протилежної ситуації: коли ваші люди та ваші власні інструменти мають спілкуватися з S3 напряму – аналітичні скрипти, rclone, інтеграції – а ви хочете, щоб вони робили це вашою корпоративною ідентичністю, а не примарним ключем із нотатника.

Часті запитання

Чи мушу я змінювати свої інструменти, щоб користуватися STS? Ні. Тимчасові облікові дані – це звичайні облікові дані S3 плюс токен сесії; їх підтримують aws CLI, усі SDK, rclone і практично будь-який сумісний із S3 інструмент. Змінюється лише спосіб їх отримання.

Що відбувається, коли працівник звільняється? Адміністратор блокує його обліковий запис у каталозі (SSO) – і на цьому процедура закінчується. Нових облікових даних він уже не отримає. Остання видана перепустка згасне сама щонайпізніше через годину.

Чи працює STS лише в AWS? Ні – це API, визначене AWS, яке стало де-факто стандартом і яке реалізують також інші платформи, зокрема Ceph RGW, на якому працює наша об'єктна платформа. З перспективи інструментів різниці немає: ті самі виклики, той самий формат облікових даних.

Чим відрізняється AssumeRole від AssumeRoleWithWebIdentity? AssumeRole вимагає, щоб той, хто викликає, уже мав якісь облікові дані (ключ або іншу роль) – він служить для переходу між ролями. AssumeRoleWithWebIdentity автентифікує самим токеном OIDC із SSO – і тому є правильним вибором, коли відправною точкою є корпоративний обліковий запис, а не наявний ключ.

Година чинності – це не занадто мало? На практиці ні: нові облікові дані отримують одним кліком у панелі (або автоматично, якщо ваша інтеграція OIDC дбає про свіжий id_token у файлі), а коротка чинність – це саме те, що робить витік малонебезпечним. Це свідомий компроміс – що довша перепустка, то довше вона діє в чужих руках.

У мене є автомати й сервісні процеси. Чи можуть вони теж використовувати STS? Самі виклики – так, але автомат не увійде паролем із MFA, тож йому потрібне інше джерело ідентичності. Це окрема тема (ідентичності машин, сервісні облікові записи); у типовому впровадженні люди користуються SSO + STS, а нечисленні сервісні облікові записи мають мінімальні права і ключі під опікою менеджера секретів.

Підсумок

Постійні ключі S3 – це борг безпеки, який зростає з кожним місяцем: секрети множаться, знання про них губиться, а звільнення працівників нічого не змінюють. STS перевертає цю модель – облікові дані стають короткочасними, іменними й виданими на підставі корпоративного входу:

  • SSO каже, хто ти (і дозволяє централізовано заблокувати цей обліковий запис),
  • роль IAM каже, що тобі дозволено (і дозволяє змінити це однією політикою),
  • STS обмінює одне на друге – на годину, а не назавжди.

У WebDisk ми зробили з цього фундамент послуги S3 для організацій: власний каталог ідентичностей, жорстка ізоляція, редактор політик і самообслуговувані тимчасові облікові дані – без жодного постійного ключа в руках користувачів. Послуга перебуває у фазі раннього доступу – якщо хочете побачити цю модель у себе, напишіть нам. А якщо вас цікавить, як ми шифруємо дані у стані спокою, зазирніть до попередньої статті циклу про SSE-S3, SSE-KMS і SSE-C.


Стаття є частиною циклу про безпеку даних у послугах WebDisk. Приклади ви виконаєте на будь-якій платформі S3 з підтримкою STS та OIDC. Параметр --endpoint-url у aws CLI вказує ендпоїнт S3 вашого постачальника, а при автоматичному обміні токена додатково AWS_ENDPOINT_URL_STS вказує його ендпоїнт STS – у Ceph RGW обидва API живуть за однією адресою, в AWS це дві різні служби.

STS на практиці: доступ до S3 корпоративним обліковим записо | WebDisk