AWS/S3 API kompatibler Object-Storage mit MinIO

Produktionsreifer, verteilter Object-Storage in Kubernetes
Table of contents

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 werde ich für die Installation von MinIO verwenden.

Starte ich mit der..

Generierung von Zugangsdaten

Nachfolgend erzeuge ich eine access key ID und einen secret access key, welche alsbald die administrativen Zugangsdaten zu meinem 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:

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

Vorbereitung von HELM

Danach füge ich der lokalen HELM Installation das MinIO chart repository hinzu und aktualisiere die Metadaten:

1helm repo add minio https://helm.min.io/
2helm 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

Ich erstelle einen neuen Namespace und starte die Installation:

1kubectl create ns minio
2
3helm install --namespace minio \
4  --set "accessKey=${AKEY},secretKey=${SKEY}" \
5  --set "persistence.size=100Gi" \
6  --set "service.type=LoadBalancer" \
7  --set "mode=distributed,replicas=3" \
8  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:

1kubectl create secret -n minio tls minio-tls-secret \
2  --cert=/Pfad/zur/Zertifikatsdatei \
3  --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:

1helm upgrade --namespace minio \
2  --set "accessKey=${AKEY},secretKey=${SKEY}" \
3  --set "persistence.size=100Gi" \
4  --set "service.type=LoadBalancer" \
5  --set "mode=distributed,replicas=3" \
6  --set "tls.enabled=true" \
7  --set "tls.certSecret=minio-tls-secret" \
8  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:

1kubectl 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 ich 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 anlege.

 1export MINIO_ACCESS_KEY="$AKEY" # Eingabe der zuvor
 2export MINIO_SECRET_KEY="$SKEY" # erzeugten Zugangsdaten
 3
 4NEW_ACCESS_KEY="$(openssl rand -hex 6)"  # Generierung zusätzlicher Schlüssel
 5NEW_SECRET_KEY="$(openssl rand -hex 32)" # für den neuen Benutzer
 6
 7# Das Stammverzeichnis für neue Benutzer kann frei gewählt werden
 8BUCKET_BASE_NAME="users"
 9
10# Der Name des "buckets" des neuen Benutzers entspricht seiner "ACCESS KEY ID"
11USER_BUCKET_NAME="${NEW_ACCESS_KEY}"

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

 1kubectl apply -f - <<EOF
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: minio-client
 6spec:
 7  containers:
 8  - image: bitnami/minio-client
 9    imagePullPolicy: Always
10    name: minio-client
11    env:
12    - name: MC_HOST_minio
13      value: "http://${MINIO_ACCESS_KEY}:${MINIO_SECRET_KEY}@minio-svc.minio.svc.cluster.local:9000"
14    - name: MC_HOST_test
15      value: "http://${NEW_ACCESS_KEY}:${NEW_SECRET_KEY}@minio-svc.minio.svc.cluster.local:9000"
16    - name: MC_USER_ID
17      value: "${NEW_ACCESS_KEY}"
18    command: ["sh", "-c", "sleep 5000"]
19EOF

Ich warte, bis sich der Pod im Zustand “Running” befindet:

1kubectl get po minio-client -w

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

 1kubectl exec -i minio-client -- /bin/bash - <<-EOF
 2  # Der primäre bucket des neuen Nutzers wird auf dem MinIO Server erzeugt.
 3  # 'minio' referenziert hier die Host-Konfiguration aus der
 4  # Umgebungsvariable 'MC_HOST_minio'
 5  mc mb "minio/${BUCKET_BASE_NAME}/${USER_BUCKET_NAME}"
 6
 7  # Wir listen in einer Baumansicht alle Verzeichnisse auf
 8  mc tree minio
 9
10  # legen den neuen Benutzer an
11  mc admin user add minio "${NEW_ACCESS_KEY}" "${NEW_SECRET_KEY}"
12
13  # und listen anschließend alle existierenden Benutzer auf
14  mc admin user list minio
15
16  # Dann schreiben wir das Regelwerk für den neuen Benutzer
17  # welches den ausschließlichen Zugriff auf einen primären bucket
18  # gestattet in eine Datei auf dem Container
19  cat > /tmp/bucket_policy.json << END
20{
21  "Version": "2012-10-17",
22  "Statement": [
23    {
24      "Sid": "AllowAllActions",
25      "Action": [
26        "s3:*"
27      ],
28      "Effect": "Allow",
29      "Resource": [
30        "arn:aws:s3:::${BUCKET_BASE_NAME}/\\\${aws:username}/*"
31      ]
32    },
33    {
34      "Sid": "AllowAllBucketActionsRead",
35      "Action": [
36        "s3:GetBucketLocation",
37        "s3:ListBucket"
38      ],
39      "Effect": "Allow",
40      "Resource": [
41        "arn:aws:s3:::${BUCKET_BASE_NAME}/*"
42      ]
43    }
44  ]
45}
46END
47  # Und laden die Richtlinie auf in den MinIO Cluster
48  mc admin policy add minio \
49    "${NEW_ACCESS_KEY}-bucket-policy" /tmp/bucket_policy.json
50
51  # Anschließend weisen wir sie dem neuen Benutzer zu
52  mc admin policy set minio \
53    "${NEW_ACCESS_KEY}-bucket-policy" user="${NEW_ACCESS_KEY}"
54
55  # Dann lassen wir uns die Berechtigungen des Nutzers anzeigen
56  mc admin user info minio "${NEW_ACCESS_KEY}"
57EOF

Abschließend teste ich die Berechtigungen des Nutzers mit folgendem Befehl:

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

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

1users
2└─ 55a2dd82fa98

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

1echo "ADMIN ACCESS_KEY: $MINIO_ACCESS_KEY"
2echo "ADMIN SECRET_KEY: $MINIO_SECRET_KEY"
3echo "USER ACCESS_KEY:  $NEW_ACCESS_KEY"
4echo "USER SECRET_KEY:  $NEW_SECRET_KEY"

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

1kubectl delete po minio-client

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

1https://${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:

1helm --namespace minio uninstall minio