S3 – eine Freigabe ist ein Bucket
serve "s3" { addr = "0.0.0.0:9000" }Oder über HTTPS, seit v0.9.0, mit tls = true und einem
tls-Block:
serve "s3" {
addr = "0.0.0.0:9000"
tls = true
}Das fünfte Protokoll, und dasjenige, das ein Image von allem aus erreichbar macht,
was Objektspeicher spricht – ein Backup-Werkzeug, eine Datenpipeline, rclone, das
fetch() eines Browsers. Nichts wird eingehängt.
GET / the shares this person may use, as buckets
GET /photos?list-type=2 the files in that share, as keys
GET /photos/holiday.jpg the file itself, Range and allEine Freigabe ist ein Bucket
Bereitgestellt über denselben Baum pro Benutzer, den SFTP verwendet: ein Dateisystem, dessen oberste Ebene aus den Freigaben besteht, die diese Person nutzen darf. Eine Freigabe, die alice nicht nutzen darf, ist also kein Bucket, den alice sehen kann, und die Zugriffsregeln werden an einer Stelle angewendet, statt in ein zweites Protokoll kopiert zu werden.
Ein Verzeichnis innerhalb einer Freigabe ist ein Präfix, kein Objekt
Genau das nehmen S3-Clients ohnehin an – sie zeigen Präfixe, die auf
das Trennzeichen enden, als Ordner an. Ein GET auf ein Verzeichnis antwortet mit NoSuchKey, weil
eine Antwort 200 einen Client glauben ließe, er könne die Bytes eines Ordners abrufen.
Ein Access Key ist ein Benutzer; der Secret Key ist sein Passwort
export AWS_ACCESS_KEY_ID=alice
export AWS_SECRET_ACCESS_KEY=$(cat alice.pw)
aws --endpoint-url http://attic.example.org:9000 s3 lsSigV4 weist den Besitz des Geheimnisses nach, indem daraus ein HMAC berechnet wird – das Passwort geht nie über die Leitung, genau wie bei NTLMv2.
Daher muss das Verzeichnis das Passwort HALTEN, nicht nur prüfen
Eine Quelle, die ein Passwort nur verifizieren kann – ein LDAP-Bind, eine bcrypt-Spalte –, kann WebDAV beantworten und kann S3 nicht beantworten.
Und auch kein NT-Hash: Das ist der MD4-Wert, mit dem SMB arbeiten kann, und ein HMAC
lässt sich daraus nicht berechnen. Eine Identität, die nur einen NT-Hash hält, bedient
SMB und nicht S3 – nahe Nachbarn statt derselben Antwort.
check gibt die Spalte aus.
⛔ Es gibt nirgends im Programm einen Password()-Accessor: Das Passwort wird
nur über Identity.Derive erreicht, das eine Ableitung entgegennimmt und
deren Ergebnis zurückgibt. Für S3 ist die Ableitung die Identität, weil der Schlüsselplan von SigV4
in go-filesystems/s3 liegt; das Geheimnis geht an diese Signaturprüfung
für diesen einen Benutzer und nirgendwo sonst hin.
Was bereitgestellt wird
ListBuckets, HeadBucket, ListObjectsV2 mit Präfix, Trennzeichen, max-keys
und Fortsetzung, HeadObject und GetObject mit Range. SigV4 in beiden
Formen, im Header und vorsigniert.
Die Objekt-API selbst ist
go-filesystems/s3.
Was abgelehnt wird, und warum
Schreibvorgänge antworten mit 403
PUT, POST und DELETE werden mit AccessDenied („this export is
read-only“) abgelehnt. fileshare hält den S3-Server schreibgeschützt, weil eine Freigabe, die eine Person
nur lesen darf, an derselben Stelle ablehnen muss wie bei SFTP, und das ist noch nicht
verdrahtet; go-filesystems/s3 v0.3.0, auf dem dieses Release aufbaut, lehnt
ohnehin jeden Schreibvorgang ab. Ablehnen ist besser als ein halb geschriebenes Objekt.
Ein Bearer-Token wird hier nicht akzeptiert
OIDC funktioniert über WebDAV und nirgendwo sonst. S3 authentifiziert mit einer SigV4-Signatur – einem HMAC über die Anfrage, ohne ein Feld, in das ein Bearer-Token passt.
Der übliche Weg ist STS AssumeRoleWithWebIdentity, das ein OIDC-Token
gegen temporäre Zugangsdaten tauscht, mit denen der Client dann signiert. Das ist ein
anderer Mechanismus, und er ist nicht implementiert.
Multipart-Upload, Versionierung, ACLs, Richtlinien, Lifecycle-Regeln, Replikation und
Tagging sind nicht implementiert. Eines davon zu setzen oder einen Multipart-Upload
zu beginnen, ist ein Schreibvorgang und antwortet wie jeder andere mit AccessDenied. Ein GET, das
nach einem davon fragt (?versioning, ?acl, ?tagging…), wird nicht unterschieden:
Die Query wird ignoriert, und das Listing des Buckets bzw. das Objekt wird zurückgegeben.
NotImplemented beantwortet ein anderes Listing als list-type=2, jede Methode außer
GET auf / und eine Methode, die keine Operation hier verwendet.
Zwei Grenzen, die man kennen sollte, bevor man es auf etwas Großes richtet
GetObject liest das ganze Objekt in den Arbeitsspeicher. Die Treiberschnittstelle bietet
ReadFile und sonst nichts – keinen Opener, keinen Reader –, daher gibt es kein streamendes
Lesen, das man nutzen könnte. Eine Obergrenze von 256 MiB antwortet mit EntityTooLarge, statt
den Prozess zum Absturz zu bringen.
LastModified ist die Epoche. filesystem.Stat trägt Mode, Size und
Inode und überhaupt keine Änderungszeit. Das Feld ist im S3-Schema nicht optional,
also muss etwas gesendet werden; die Epoche ist offensichtlich keine echte Zeit,
während time.Now() wie eine gerade geänderte Datei aussähe und jedes Sync-Werkzeug
bei jedem Lauf alles kopieren ließe.
Erstellt am von tannevaled
Geändert am von tannevaled