MinIO давно перестал быть просто «аналогом S3 для своих». Сегодня это полноценное объектное хранилище, которое крутится в Kubernetes, обслуживает резервные копии, хранит артефакты CI/CD, модели машинного обучения, логи, медиаконтент и вообще всё, что DevOps-инженер однажды решил «временно положить в бакет». А потом это стало продом. Как обычно...
И вот тут начинается самое интересное:
не просто «залить файлы», а нормально разграничить доступ:
-
кто может читать,
-
кто может писать,
-
кто может удалять,
-
кто видит только свой бакет,
-
кто вообще не должен знать о существовании других бакетов,
-
и почему разработчик внезапно получил AccessDenied в пятницу вечером.
Разберём всё подробно:
-
установка клиента,
-
подключение,
-
создание пользователей,
-
политики (policy),
-
права на бакеты и объекты,
-
ограничения,
-
примеры для DevOps, CI/CD, backup и multi-tenant окружений.
Что такое MinIO и почему все его любят
MinIO - это высокопроизводительное S3-совместимое объектное хранилище.
По сути:
-
API совместим с Amazon S3,
-
можно запускать где угодно,
-
отлично работает в Kubernetes,
-
легко автоматизируется,
-
поддерживает replication, lifecycle, versioning, encryption,
-
и не требует продавать почку ради лицензии.
MinIO особенно любят:
-
DevOps,
-
SRE,
-
Data Engineers,
-
ML-команды,
-
CI/CD инженеры,
-
и все, кто однажды пытался хранить бэкапы на NFS.
Где используется MinIO
Типовые сценарии:
| Сценарий | Что хранится |
|---|---|
| CI/CD | артефакты сборки |
| Kubernetes | backup Velero |
| GitLab | registry и uploads |
| PostgreSQL | WAL и backup |
| ML/AI | модели и datasets |
| Видео/фото | медиафайлы |
| Логи | архивы и telemetry |
| Dev environments | временные данные |
Установка клиента mc
Для управления MinIO используется официальный клиент mc (MinIO Client).
macOS
brew install minio/stable/mc
Linux
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/
Windows
Скачать:
MinIO Client для Windows
Проверка установки
mc --version
Пример:
mc version RELEASE.2026-01-01T12-00-00Z
Подключение к MinIO
Создание alias
mc alias set storage https://s3.company.local ACCESS_KEY SECRET_KEY
Где:
| Параметр | Описание |
|---|---|
| storage | имя подключения |
| https://s3.company.local | URL MinIO |
| ACCESS_KEY | логин |
| SECRET_KEY | пароль |
Проверка подключения
mc admin info storage
Или:
mc ls storage
Создание бакета
mc mb storage/backups
Проверка:
mc ls storage
Создание пользователя
Новый пользователь
mc admin user add storage backup-user SUPER_SECRET_PASSWORD
Проверка:
mc admin user list storage
Как работает система прав в MinIO
В MinIO права строятся через:
-
Пользователей
-
Policies
-
Groups
-
STS/JWT/OIDC
-
Bucket Policy
На практике чаще всего используют:
User -> Policy -> Bucket/Object
Важный момент: bucket policy ≠ admin policy
Очень частая ошибка.
Bucket Policy
Работает на уровне самого бакета.
Например:
-
публичное чтение,
-
анонимный доступ,
-
download-only.
Admin Policy
Привязывается к пользователю или группе.
Например:
-
read/write,
-
readonly,
-
backup-only,
-
upload-only.
Создание policy
Создадим файл:
vim bucket-rw-policy.json
Полный доступ к объектам внутри бакета
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::backups",
"arn:aws:s3:::backups/*"
]
}
]
}
Почему нужно указывать два Resource
Очень важный момент.
Это:
"arn:aws:s3:::backups"
- сам бакет.
А это:
"arn:aws:s3:::backups/*"
- объекты внутри бакета.
Если забыть второе:
-
бакет будет виден,
-
но файлы читать нельзя.
Если забыть первое:
-
объекты могут работать криво,
-
list bucket может ломаться.
И потом начинается любимое:
"Но у меня же вроде policy есть..."
Загрузка policy
mc admin policy create storage backups-rw ./bucket-rw-policy.json
В старых версиях встречается:
mc admin policy add
Но сейчас рекомендуется именно:
mc admin policy create
Назначение policy пользователю
mc admin policy attach storage backups-rw --user backup-user
Проверка прав пользователя
mc admin policy entities storage backups-rw
Пример: пользователь только читает файлы
readonly-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::reports",
"arn:aws:s3:::reports/*"
]
}
]
}
Пример: upload-only
Очень популярный кейс.
Например:
-
камеры видеонаблюдения,
-
backup agents,
-
IoT,
-
CI/CD upload jobs.
Пользователь может:
-
загружать,
-
но не читать,
-
не удалять,
-
не скачивать.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::uploads/*"
]
}
]
}
Пример: backup-пользователь
Нормальный production backup policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::postgres-backups",
"arn:aws:s3:::postgres-backups/*"
]
}
]
}
Пример: запрет удаления
Очень полезно для backup-хранилищ.
{
"Effect": "Deny",
"Action": [
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::postgres-backups/*"
]
}
Комбинирование Allow и Deny
Важно понимать:
Deny всегда сильнее Allow
Даже если:
"Action": ["s3:*"]
но отдельно есть:
"Deny": ["s3:DeleteObject"]
удаление всё равно будет запрещено.
Это база IAM/S3-модели.
Multi-tenant схема
Очень частая архитектура:
company-storage
├── team-a
├── team-b
├── team-c
Но лучше:
team-a-bucket
team-b-bucket
team-c-bucket
Почему:
-
проще права,
-
проще аудит,
-
проще lifecycle,
-
проще replication,
-
меньше риска случайного доступа.
Изоляция пользователей по бакетам
user1-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::team1"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::team1/*"
]
}
]
}
Скрытие остальных бакетов
Если дать:
"s3:ListAllMyBuckets"
пользователь увидит все бакеты.
Поэтому в multi-tenant окружениях обычно:
-
либо не дают ListAllMyBuckets,
-
либо делают отдельные инстансы,
-
либо используют gateway/API.
Проверка доступа от имени пользователя
Очень полезный приём.
Создаём alias:
mc alias set test-user https://s3.company.local USER PASSWORD
Проверяем:
mc ls test-user
mc cp file.txt test-user/backups
mc rm test-user/backups/file.txt
Аудит и безопасность
MinIO умеет:
-
audit logging,
-
webhook audit,
-
Kafka audit,
-
Elasticsearch audit,
-
Prometheus metrics.
И это прям must-have.
Включение audit webhook
mc admin config set storage audit_webhook:primary endpoint="https://audit.company.local/minio"
Почему нельзя использовать root-пользователя
Потому что:
root user + production = будущий инцидент
Root должен:
-
храниться в Vault,
-
использоваться редко,
-
не применяться приложениями.
Интеграция с Vault
Очень хороший production-подход:
-
Vault генерирует временные креды,
-
MinIO принимает STS,
-
приложения получают short-lived credentials,
-
ротация автоматическая.
И вот тут безопасность начинает выглядеть как безопасность, а не как:
"access_key = admin"
в .env файле
Пример для Kubernetes
Secret
apiVersion: v1
kind: Secret
metadata:
name: minio-creds
type: Opaque
stringData:
access_key: backup-user
secret_key: VERY_SECRET_PASSWORD
Использование в CronJob backup
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: minio-creds
key: access_key
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: minio-creds
key: secret_key
Полезные команды mc
Список бакетов
mc ls storage
Размер бакета
mc du storage/backups
Копирование файла
mc cp backup.tar.gz storage/backups
Синхронизация
mc mirror ./data storage/backups
Удаление
mc rm storage/backups/file.tar.gz
Версионирование
mc version enable storage/backups
Versioning - включайте почти всегда
Потому что:
-
accidental delete,
-
ransomware,
-
кривой deploy,
-
"ой я случайно очистил бакет".
Это происходит чаще, чем хотелось бы.
Lifecycle policy
Автоудаление старых файлов:
mc ilm rule add storage/logs --expire-days 30
Частые ошибки
1. Нет доступа к объектам
Забыли:
"arn:aws:s3:::bucket/*"
2. Видны чужие бакеты
Выдали:
"s3:ListAllMyBuckets"
3. Upload работает, download нет
Нет:
"s3:GetObject"
4. List bucket не работает
Нет:
"s3:ListBucket"
Практические рекомендации
Для production
Делайте:
-
отдельного пользователя под сервис,
-
отдельный бакет под приложение,
-
lifecycle,
-
versioning,
-
audit logging,
-
deny delete где нужно,
-
ротацию ключей,
-
Vault/OIDC/STС.
Хорошая архитектура
MinIO
├── backups-postgres
├── backups-kubernetes
├── gitlab-artifacts
├── logs
├── ml-models
└── uploads
И отдельный пользователь под каждый сервис.
Плохая архитектура
bucket: prod
users:
- app1
- app2
- backup
- ci
- intern
- temp-script
А потом:
-
никто не понимает права,
-
audit невозможен,
-
удалили не то,
-
и начинается археология policy-файлов.
Итог
MinIO - это не просто «файлопомойка с S3 API».
Это полноценное объектное хранилище уровня production-инфраструктуры.
И если сразу:
-
нормально строить политики,
-
изолировать сервисы,
-
включать аудит,
-
использовать временные креды,
-
не раздавать s3:*,
-
и не запускать всё от root -
то MinIO становится очень мощным и безопасным компонентом инфраструктуры.
А если нет - через полгода кто-нибудь обязательно спросит:
«А почему пользователь из тестового стенда может удалить backup продакшена?»