S3 — un partage est un bucket
serve "s3" { addr = "0.0.0.0:9000" }Ou en HTTPS, depuis la v0.9.0, avec tls = true et un
bloc tls :
serve "s3" {
addr = "0.0.0.0:9000"
tls = true
}Le cinquième protocole, celui qui rend une image accessible depuis tout ce qui
parle le stockage objet — un outil de sauvegarde, une chaîne de traitement de données, rclone, le
fetch() d’un navigateur. Rien n’est monté.
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 allUn partage est un bucket
Servi sur la même arborescence par utilisateur que celle de SFTP : un système de fichiers dont le niveau supérieur est l’ensemble des partages que cette personne peut utiliser. Un partage qu’alice ne peut pas utiliser n’est donc pas un bucket qu’alice peut voir, et les règles d’accès sont appliquées en un seul endroit plutôt que recopiées dans un second protocole.
Un répertoire dans un partage est un préfixe, pas un objet
C’est ce que croient déjà les clients S3 — ils affichent comme des dossiers les préfixes qui se terminent par
le délimiteur. Un GET sur un répertoire répond NoSuchKey, car
répondre 200 ferait croire à un client qu’il peut récupérer les octets d’un dossier.
Une clé d’accès est un utilisateur ; la clé secrète est son mot de passe
export AWS_ACCESS_KEY_ID=alice
export AWS_SECRET_ACCESS_KEY=$(cat alice.pw)
aws --endpoint-url http://attic.example.org:9000 s3 lsSigV4 prouve la possession du secret en calculant un HMAC à partir de celui-ci — le mot de passe ne traverse jamais le réseau, exactement comme avec NTLMv2.
L’annuaire doit donc DÉTENIR le mot de passe, et pas seulement le vérifier
Une source qui ne sait que vérifier un mot de passe — une liaison LDAP, une colonne bcrypt — peut répondre à WebDAV et ne peut pas répondre à S3.
Pas non plus une empreinte NT : c’est le MD4 dont SMB peut se servir, et un HMAC
ne peut pas être calculé à partir de lui. Une identité qui ne détient qu’une empreinte NT sert
SMB et pas S3 — des voisins proches plutôt que la même réponse.
check affiche la colonne.
⛔ Il n’existe aucun accesseur Password() dans le programme : le mot de passe n’est
atteint que par Identity.Derive, qui prend une dérivation et renvoie
son résultat. Pour S3, la dérivation est l’identité, car le calendrier de clés de SigV4
se trouve dans go-filesystems/s3 ; le secret va à cette vérification de signature,
pour ce seul utilisateur, et nulle part ailleurs.
Ce qui est servi
ListBuckets, HeadBucket, ListObjectsV2 avec préfixe, délimiteur, max-keys
et continuation, HeadObject, et GetObject avec Range. SigV4 sous ses deux
formes, en en-tête et présignée.
L’API objet elle-même est
go-filesystems/s3.
Ce qui est refusé, et pourquoi
Les écritures répondent 403
PUT, POST et DELETE sont refusés avec AccessDenied (« this export is
read-only »). fileshare garde le serveur S3 en lecture seule parce qu’un partage qu’une personne
ne peut que lire doit refuser au même endroit que SFTP, et ce n’est pas encore
câblé ; go-filesystems/s3 v0.3.0, sur lequel repose cette version, refuse de toute façon
toutes les écritures. Refuser vaut mieux qu’un objet à moitié écrit.
Un jeton porteur n’est pas accepté ici
OIDC fonctionne sur WebDAV et nulle part ailleurs. S3 s’authentifie avec une signature SigV4 — un HMAC sur la requête, sans aucun champ où un jeton porteur pourrait se loger.
La voie habituelle est STS AssumeRoleWithWebIdentity, qui échange un jeton OIDC
contre des identifiants temporaires avec lesquels le client signe ensuite. C’est un
mécanisme différent, et il n’est pas implémenté.
Le téléversement en plusieurs parties (multipart), le versionnage, les ACL, les politiques, les règles de cycle de vie, la réplication et
les étiquettes ne sont pas implémentés. Définir l’un d’eux, ou commencer un téléversement
multipart, est une écriture, et répond AccessDenied comme toute autre. Un GET qui
en demande un (?versioning, ?acl, ?tagging…) n’est pas distingué :
la requête est ignorée et c’est le listage du bucket ou l’objet qui est renvoyé.
NotImplemented répond à un listage autre que list-type=2, à toute méthode autre que
GET sur /, et à une méthode qu’aucune opération ici n’utilise.
Deux limites à connaître avant de le pointer vers quelque chose de volumineux
GetObject lit l’objet entier en mémoire. L’interface des pilotes n’offre que
ReadFile — ni ouvreur, ni lecteur — il n’y a donc aucune lecture en flux
à utiliser. Une borne, 256 Mio, répond EntityTooLarge plutôt que de faire
tomber le processus.
LastModified vaut l’epoch. filesystem.Stat porte Mode, Size et
Inode, et aucune date de modification. Le champ n’est pas facultatif dans le schéma
S3, il faut donc envoyer quelque chose ; l’epoch n’est manifestement pas une vraie date,
alors que time.Now() ressemblerait à un fichier qui vient de changer et ferait tout recopier
à chaque outil de synchronisation, à chaque passage.
Créée le par tannevaled
Modifiée le par tannevaled