Implémentez rapidement le stockage compatible S3 avec python-flask

Qu'est-ce que c'est ça

Ceci est un article sur la création d'un stockage compatible S3 avec python. Le sens d'étudier est fort.

Explorez le mouvement du client

Après un rapide coup d'œil à la documentation officielle de l'API AWS, j'ai décidé de découvrir ce que faisait réellement le client S3.

Conditions préalables

--Utilisez python et flask pour l'application de serveur factice --Utilisez cyberduck pour le client (car il était à portée de main et semblait facile à utiliser) --Utilisez HTTPS (car le port standard lors de l'utilisation de s3 avec cyberduck était 443)

opération

Object Listing --Le préfixe est spécifié dans la requête GET et les paramètres liés à demilita sont définis. --La racine du seau est atteinte

127.0.0.1 - - [29/Jan/2017 01:02:24] "GET /test-bucket/?max-keys=1000&prefix&delimiter=%2F HTTP/1.1"

[En-tête de la demande]
Authorization: AWS hogehoge_user1:ysH68SkszwcudzrtZAlxlV9z8WA=
Content-Length:
User-Agent: Cyberduck/4.7.2.18004 (Mac OS X/10.10.5) (x86_64)
Connection: upgrade
Host: b.tgr.tokyo
X-Amz-Request-Payer: requester
Date: Sun, 29 Jan 2017 01:02:23 GMT
Content-Type:

Upload --Utilisez la méthode PUT (pas POST)

127.0.0.1 - - [29/Jan/2017 01:04:19] "PUT /test-bucket/gopher.png HTTP/1.1"

[En-tête de la demande]
Authorization: AWS hogehoge_user1:suTrxv+XQuecbq7vUMYoQ3rWBcM=
Content-Length: 114063
User-Agent: Cyberduck/4.7.2.18004 (Mac OS X/10.10.5) (x86_64)
Connection: upgrade
Host: b.tgr.tokyo
Date: Sun, 29 Jan 2017 01:04:18 GMT
Content-Type: image/png

Download --Utilisez la méthode GET

127.0.0.1 - - [29/Jan/2017 01:05:09] "GET /test-bucket/gopher.png HTTP/1.1"

[En-tête de la demande]
Authorization: AWS hogehoge_user1:rhqMjHlbcYg/APr7bv9PH7tbyy4=
Content-Length:
User-Agent: Cyberduck/4.7.2.18004 (Mac OS X/10.10.5) (x86_64)
Connection: upgrade
Host: b.tgr.tokyo
X-Amz-Request-Payer: requester
Date: Sun, 29 Jan 2017 01:05:09 GMT
Content-Type:

Delete --Utiliser la méthode DELETE

127.0.0.1 - - [29/Jan/2017 01:05:59] "DELETE /test-bucket/gopher.png HTTP/1.1"

[En-tête de la demande]
Authorization: AWS hogehoge_user1:U2NEDsKLvJ08mLYdPIB43R+IAu0=
Content-Length:
User-Agent: Cyberduck/4.7.2.18004 (Mac OS X/10.10.5) (x86_64)
Connection: upgrade
Date: Sun, 29 Jan 2017 01:05:59 GMT
Host: b.tgr.tokyo
Content-Type:

Impressions

C'est assez rafraîchissant, donc si vous écrivez un serveur APP avec les fonctions suivantes Il semble que vous puissiez créer S3 accessible depuis Cyberduck.

--Vérifiez l'en-tête d'autorisation et autorisez (commun à toutes les demandes)

Mettre en place

Bien que ce soit une version terminée, je l'ai poussé vers simple-s3-clone. Veuillez voir ici pour le code détaillé. Il n'y a pas de concept de seau et la gestion des erreurs est toujours douce, je l'ajouterai donc plus tard.

Le code qui apparaît dans l'explication ci-dessous a été supprimé à des fins d'explication. J'espère transmettre le concept seul.

Partie authentification

C'est là que j'ai eu le plus de problèmes. En gros, je m'authentifie avec la procédure suivante, mais j'ai oublié l'existence de l'en-tête X-Amz, et j'étais frustré car il ne correspondait pas à la signature générée par le client pour toujours.

--Créez une chaîne de génération de signature (cette chaîne peut être générée à partir de la méthode de demande, du chemin et des informations d'en-tête)


def get_x_amz_headers():
    return filter(lambda x: x[0].startswith('X-Amz-'), request.headers.items())

def generate_x_amz_string():
    ret = ''
    #X pour générer une chaîne d'authentification-Trier et concaténer les en-têtes Amz
    for key in sorted(get_x_amz_headers()):
        k = key[0].lower()
        v = request.headers.get(key[0])
        ret += '{}:{}\n'.format(k, v)
    return ret


def generate_auth_string():
    s = '{}\n{}\n{}\n{}\n{}{}'.format(
        request.method,
        request.headers.get('Content-Md5', ''),
        request.headers.get('Content-Type', ''),
        request.headers.get('Date', ''),
        generate_x_amz_string(),
        request.path
    )
    return s

def auth_check(auth_raw_string):
    auth_info = request.headers.get('Authorization')
    access_key_id = 'hogehoge_key_id'
    secret_access_key = 'hogehoge_secret'
    # HMAC-SHA-Utilisez 1 pour hacher la chaîne générée avec une clé secrète(Génération de signature)
    hashed = hmac.new(secret_access_key, auth_raw_string,
                      hashlib.sha1).digest()
    #La forme de l'en-tête d'authentification envoyé par l'utilisateur(AWS AccessKeyID:Signature)faire
    generated_signature = 'AWS {}:{}'.format(
        access_key_id, base64.encodestring(hashed).rstrip())
    #Comparer avec la signature générée par l'utilisateur
    if auth_info != generated_signature:
        raise exception.SignatureDoesNotMatch()


@app.before_request
def before_request():
    #Authentifiez-vous avant chaque demande
    s = generate_auth_string()
    auth_check(s)

Liste d'objets et téléchargement

@app.route("/<path:path>")
def get_request_with_path(path):
    if g.resource_path == '':
        return process_object_list()
    else:
        return download_object()

Téléchargement d'objets, création de dossiers

@app.route("/<path:path>", methods=['PUT'])
def put_request_with_path(path):
    if int(request.headers.get('Content-Length')) != len(request.data):
        raise exception.MissingContentLength()
    if g.resource_path[-1] == '/':
        return create_prefix()
    else:
        return create_object()

Supprimer des objets, supprimer des dossiers


@app.route("/<path:path>", methods=['DELETE'])
def delete_request_with_path(path):
    if g.resource_path[-1] == '/':
        return delete_prefix()
    else:
        return delete_object()

Il semble bouger

simple-s3-clone.gif

s3cmd ne fonctionnait pas car la manière dont la demande était envoyée était différente de cyberduck. Cependant, si vous modifiez la partie authentification, il semble que vous puissiez répondre immédiatement.

finalement

Jusqu'à présent, je faisais des calculs scientifiques et technologiques tels que la simulation, mais après avoir rejoint l'entreprise, j'ai découvert des services comme S3 Cette motivation est que je voulais implémenter le côté serveur.

Site de référence

Recommended Posts

Implémentez rapidement le stockage compatible S3 avec python-flask
Visualisez rapidement avec les pandas
Implémenter FReLU avec tf.keras
Téléchargeur S3 avec boto