Copyright © KC Green

AWS/S3 API kompatibler Object-Storage mit MinIO

 infrastructure   howto 

Produktionsreifer, verteilter Object-Storage in Kubernetes
TOC

MinIO ist ein offenes, AWS/S3 API kompatibles Object-Storage System, welches hervorragend dazu geeignet ist, in Kubernetes betrieben zu werden. Die Installation einer produktionsreifen Konfiguration gestaltet sich äußerst einfach.

Die einzigen beiden Voraussetzungen sind der Zugriff auf einen Kubernetes Cluster und HELM (in Version 3). Sollte der Cluster noch nicht bereit stehen, kannst du natürlich Minikube verwenden oder dir einmal k3s ansehen, damit kann man in wenigen Sekunden einen schlüsselfertigen Single-Node Kubernetes Cluster aufsetzen. Den Kubernetes Paketmanager HELM werden wir für die Installation von MinIO verwenden.

Starten wir mit der..

Generierung von Zugangsdaten

Nachfolgend erzeugen wir eine access key ID und einen secret access key, welche alsbald die administrativen Zugangsdaten zu unserem MinIO Konto (aws:PrincipalType == “account”) darstellen werden. Sie entsprechen im Prinzip Benutzernamen und Passwort.

Im Beispiel verwende ich openssl, aber es kann natürlich jede andere Methode für die Generierung verwendet werden:

AKEY="$(openssl rand -hex 32)"
SKEY="$(openssl rand -hex 32)"

Vorbereitung von HELM

Danach fügen wir der lokalen HELM Installation das MinIO chart repository hinzu und aktualisieren die Metadaten:

helm repo add minio https://helm.min.io/
helm repo update

Nun ist alles bereit, um MinIO im Kubernetes Cluster zu installieren.

Update: Mittlerweile wurde das HELM Chart für die Installation von MinIO als veraltet markiert. Das offizielle Chart wird nunmehr nur noch sporadisch gepflegt und die Installation des MinIO Operators empfohlen!

Stand 24.02.2021 funktioniert jedoch alles noch ohne Einschränkungen und das verwendete Container Image entspricht nahezu dem aktuellen Release.

MinIO Cluster Installation

Wir erstellen einen neuen Namespace und starten die Installation:

kubectl create ns minio

helm install --namespace minio \
  --set "accessKey=${AKEY},secretKey=${SKEY}" \
  --set "persistence.size=100Gi" \
  --set "service.type=LoadBalancer" \
  --set "mode=distributed,replicas=3" \
  minio minio/minio

Info: Mit helm show values minio/minio kann man sich alle verfügbaren HELM Parameter und deren Standardwerte anzeigen lassen.

Einrichtung von TLS

Für ein produktives Setup sollte man in jedem Fall TLS aktivieren, andernfalls werden die Logindaten im Klartext übertragen! Hierzu muss man lediglich die HELM Parameter “tls.enabled=true” und “tls.certSecret=minio-tls-secret” setzen. Letzteres muss auf ein Kubernetes TLS Secret verweisen, welches public.crt und private.key beinhaltet.

Das Kubernetes Secret kann auf folgende Weise erstellt werden:

kubectl create secret -n minio tls minio-tls-secret \
  --cert=/Pfad/zur/Zertifikatsdatei \
  --key=/Pfad/zur/Schlüsseldatei

Um nachträglich MinIO auf TLS hören zu lassen, kann man einfach via helm ein Upgrade durchführen und die zusätzlichen Parameter anhängen:

helm upgrade --namespace minio \
  --set "accessKey=${AKEY},secretKey=${SKEY}" \
  --set "persistence.size=100Gi" \
  --set "service.type=LoadBalancer" \
  --set "mode=distributed,replicas=3" \
  --set "tls.enabled=true" \
  --set "tls.certSecret=minio-tls-secret" \
  minio minio/minio

Administrative Aufgaben

Lokaler Zugriff auf Weboberfläche

Um mit dem Browser auf die MinIO Weboberfläche zugreifen zu können muss man nichts weiter tun, als via kubectl eine Portweiterleitung auf den MinIO Kubernetes Service einzurichten. Hierzu genügt:

kubectl port-forward -n minio svc/minio 9000:9000

Danach kann man sich über http://localhost:9000 mit den zuvor erstellten Admin-Zugangsdaten (ACCESS KEY ID/SECRET ACCESS KEY) anmelden, um administrative Aufgaben durchzuführen, wie z.B. eingeschränkte Nutzer und Buckets verwalten, Dateien hochladen oder löschen, etc..

Verwaltung mit MinIO Client aus Cluster

Alternativ und vermutlich auch komfortabler kann man die MinIO Installation mit dem Minio Client, direkt aus dem Kubernetes Cluster heraus, verwalten.

Benutzer mit eingeschränkten Rechten anlegen

Nachfolgend beschreibe ich, wie man mit Hilfe eines “MinIO-CLI-Pods” einen neuen Benutzer (aws:PrincipalType == “user”) mit eingeschränkten Rechten und einem primären bucket aus dem Kubernetes Cluster heraus anlegt.

export MINIO_ACCESS_KEY="$AKEY" # Eingabe der zuvor
export MINIO_SECRET_KEY="$SKEY" # erzeugten Zugangsdaten

NEW_ACCESS_KEY="$(openssl rand -hex 6)"  # Generierung zusätzlicher Schlüssel
NEW_SECRET_KEY="$(openssl rand -hex 32)" # für den neuen Benutzer

# Das Stammverzeichnis für neue Benutzer kann frei gewählt werden
BUCKET_BASE_NAME="users"

# Der Name des "buckets" des neuen Benutzers entspricht seiner "ACCESS KEY ID"
USER_BUCKET_NAME="${NEW_ACCESS_KEY}"

Anschließend erstellen wir einen neuen Kubernetes Pod, auf Basis des Bitnami MinIO Client Container-Images. Die Umgebungsvariablen mit den Zugangsdaten werden an den Pod weitergegeben.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: minio-client
spec:
  containers:
  - image: bitnami/minio-client
    imagePullPolicy: Always
    name: minio-client
    env:
    - name: MC_HOST_minio
      value: "http://${MINIO_ACCESS_KEY}:${MINIO_SECRET_KEY}@minio-svc.minio.svc.cluster.local:9000"
    - name: MC_HOST_test
      value: "http://${NEW_ACCESS_KEY}:${NEW_SECRET_KEY}@minio-svc.minio.svc.cluster.local:9000"
    - name: MC_USER_ID
      value: "${NEW_ACCESS_KEY}"
    command: ["sh", "-c", "sleep 5000"]
EOF

Wir warten, bis sich der Pod im Zustand “Running” befindet:

kubectl get po minio-client -w

Und können dann mit kubectl exec Befehle an den MinIO Client senden, die im Container ausgeführt werden:

kubectl exec -i minio-client -- /bin/bash - <<-EOF
  # Der primäre bucket des neuen Nutzers wird auf dem MinIO Server erzeugt.
  # 'minio' referenziert hier die Host-Konfiguration aus der
  # Umgebungsvariable 'MC_HOST_minio'
  mc mb "minio/${BUCKET_BASE_NAME}/${USER_BUCKET_NAME}"

  # Wir listen in einer Baumansicht alle Verzeichnisse auf
  mc tree minio

  # legen den neuen Benutzer an
  mc admin user add minio "${NEW_ACCESS_KEY}" "${NEW_SECRET_KEY}"

  # und listen anschließend alle existierenden Benutzer auf
  mc admin user list minio

  # Dann schreiben wir das Regelwerk für den neuen Benutzer
  # welches den ausschließlichen Zugriff auf einen primären bucket
  # gestattet in eine Datei auf dem Container
  cat > /tmp/bucket_policy.json << END
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAllActions",
      "Action": [
        "s3:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::${BUCKET_BASE_NAME}/\\\${aws:username}/*"
      ]
    },
    {
      "Sid": "AllowAllBucketActionsRead",
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::${BUCKET_BASE_NAME}/*"
      ]
    }
  ]
}
END
  # Und laden die Richtlinie auf in den MinIO Cluster
  mc admin policy add minio \
    "${NEW_ACCESS_KEY}-bucket-policy" /tmp/bucket_policy.json

  # Anschließend weisen wir sie dem neuen Benutzer zu
  mc admin policy set minio \
    "${NEW_ACCESS_KEY}-bucket-policy" user="${NEW_ACCESS_KEY}"

  # Dann lassen wir uns die Berechtigungen des Nutzers anzeigen
  mc admin user info minio "${NEW_ACCESS_KEY}"
EOF

Abschließend testen wir die Berechtigungen des Nutzers mit folgendem Befehl:

kubectl exec -i minio-client -- /bin/bash - <<-EOF
  # Bitte beachtet die Referenz der Host-Konfiguration
  mc tree test
EOF

Wenn alles funktioniert hat, wird ausschließlich der Pfad zum Benutzer-Bucket in der Baumansicht dargestellt. Ähnlich wie hier:

users
└─ 55a2dd82fa98

Um die Zugangsdaten zu speichern, kann man sie sich noch einmal gesammelt ausgeben lassen:

echo "ADMIN ACCESS_KEY: $MINIO_ACCESS_KEY"
echo "ADMIN SECRET_KEY: $MINIO_SECRET_KEY"
echo "USER ACCESS_KEY:  $NEW_ACCESS_KEY"
echo "USER SECRET_KEY:  $NEW_SECRET_KEY"

Dann wird der MinIO-Client Pod nicht mehr benötigt und kann gelöscht werden:

kubectl delete po minio-client

Die S3 URI zum Benutzer-Bucket setzt sich wie folgt zusammen:

https://${A_KEY}:${S_KEY}@minio-svc.minio.svc.cluster.local:9000/Pfad/zum/Bucket

Deinstallation des MinIO Clusters

Die Deinstallation gestaltet sich Dank HELM auch sehr einfach:

helm --namespace minio uninstall minio