aws-v4-signing-custom-headers-gcs

Par divinevideo · divine-mobile

Ajoutez des en-têtes de métadonnées personnalisés (x-amz-meta-*) aux requêtes signées AWS v4 pour l'API compatible S3 de GCS. À utiliser quand : (1) vous ajoutez des métadonnées personnalisées aux uploads GCS via l'API S3, (2) vous obtenez des erreurs de non-concordance de signature après l'ajout de nouveaux en-têtes, (3) les en-têtes x-amz-meta-* sont ignorés ou provoquent des erreurs 403. Les en-têtes personnalisés DOIVENT être inclus dans la liste des en-têtes canoniques et des en-têtes signés.

npx skills add https://github.com/divinevideo/divine-mobile --skill aws-v4-signing-custom-headers-gcs

Signature AWS v4 avec en-têtes de métadonnées personnalisées pour GCS

Problème

Lors de l'ajout d'en-têtes de métadonnées personnalisées (x-amz-meta-*) aux requêtes de l'API compatible S3 de GCS, les requêtes échouent avec des erreurs de non-correspondance de signature. Les en-têtes doivent être correctement inclus dans le calcul de la signature AWS v4.

Contexte / Conditions de déclenchement

  • Utilisation de l'API XML compatible S3 de GCS (pas l'API JSON native)
  • Ajout d'en-têtes x-amz-meta-* pour les métadonnées d'objet
  • Erreur : « SignatureDoesNotMatch » ou 403 Forbidden après ajout d'en-têtes
  • Les en-têtes fonctionnent avec les requêtes non signées mais échouent avec la signature AWS v4
  • Identifiants HMAC configurés pour l'interopérabilité GCS

Solution

Les en-têtes personnalisés doivent être inclus à la fois dans les en-têtes canoniques et dans la liste des en-têtes signés, triés alphabétiquement :

1. En-têtes canoniques (triés alphabétiquement)

let canonical_headers = format!(
    "host:{}\nx-amz-content-sha256:{}\nx-amz-date:{}\nx-amz-meta-owner:{}\n",
    host, payload_hash, amz_date, owner  // Note: ordre alphabétique !
);

2. Liste des en-têtes signés

let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner";

3. Exemple complet (Rust)

fn sign_request_with_owner(
    req: &mut Request,
    config: &GCSConfig,
    payload_hash: Option<String>,
    owner: &str
) -> Result<()> {
    // Définir les en-têtes d'abord
    req.set_header("x-amz-date", &amz_date);
    req.set_header("x-amz-content-sha256", &payload_hash);
    req.set_header("x-amz-meta-owner", owner);  // Métadonnée personnalisée

    // En-têtes canoniques - DOIVENT être triés alphabétiquement
    let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner";
    let canonical_headers = format!(
        "host:{}\nx-amz-content-sha256:{}\nx-amz-date:{}\nx-amz-meta-owner:{}\n",
        host, payload_hash, amz_date, owner
    );

    // Suite de la signature AWS v4...
    let canonical_request = format!(
        "{}\n{}\n{}\n{}\n{}\n{}",
        method, uri, query, canonical_headers, signed_headers, payload_hash
    );

    // Signer et ajouter l'en-tête Authorization...
}

Vérification

Après le chargement, vérifiez que les métadonnées sont présentes :

gsutil stat gs://bucket/object-name
# Doit afficher :
#     Metadata:
#         owner: <value>

Ou via l'API S3 :

aws s3api head-object --bucket bucket --key object-name --endpoint-url https://storage.googleapis.com

Exemple

Avant (cassé) - en-tête non inclus dans la signature :

let signed_headers = "host;x-amz-content-sha256;x-amz-date";  // Manque x-amz-meta-owner
req.set_header("x-amz-meta-owner", owner);  // En-tête ajouté mais non signé
// Résultat : 403 SignatureDoesNotMatch

Après (fonctionnant) - en-tête correctement signé :

let signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-meta-owner";  // Inclus !
req.set_header("x-amz-meta-owner", owner);
// Inclure dans canonical_headers aussi
// Résultat : 200 OK, métadonnées visibles dans GCS

Notes

  • Les noms d'en-têtes ne sont pas sensibles à la casse mais sont conventionnellement en minuscules dans la forme canonique
  • La liste des en-têtes signés séparés par des points-virgules doit correspondre aux en-têtes canoniques séparés par des retours à la ligne
  • Pour GCS, les métadonnées apparaissent comme Metadata: key: value dans la sortie de gsutil stat
  • Lors de l'utilisation de l'API JSON native de GCS, utilisez le champ d'objet metadata à la place
  • Plusieurs en-têtes personnalisés peuvent être ajoutés - assurez-vous simplement qu'ils sont tous dans les listes canoniques/signées

Références

Skills similaires