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 права строятся через:

  1. Пользователей

  2. Policies

  3. Groups

  4. STS/JWT/OIDC

  5. 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 продакшена?»